首页 > 其他 > 详细

CF1324E Sleeping Schedule 题解

时间:2020-03-23 11:45:16      阅读:82      评论:0      收藏:0      [点我收藏+]

原题链接

简要题意:

每次可以将 \(a_i\)\(1\) 或不变。求让 \(a_i\) 的前缀和 \(\% h\) 的值在 \([l,r]\) 区间中的最多的个数。

E题是个水dp,也不怎样

\(f_{i,j}\) 表示前 \(i\) 个数中,\(\bigg ( \sum_{k=1}^{i} a_k \bigg ) \% h = j\) 的最大答案。

显然,我们从第 \(i\) 个数入手。(下标出现负数的,在代码中均处理;转移方程中保留)

如果不选,那么 \(f_{i,j} = f_{i-1,j-a_i}\).

如果选,那么 \(f_{i,j} = f_{i-1,j-a_i+1}\).

最后,\(f_{i,j} \gets f_{i,j} + (l \leq j \space \texttt{and} \space j<=r)\)

这是因为,如果当前的这个前缀和在该范围,也算一个答案。

所以:

\[ f_{i,j} = \begin{cases} 0 , i=0 \space \texttt{and} \space j=0 \\max{f_{i-1 , j-a_i} , f_{i-1,j-a_i+1}} \\end{cases} \]

防止出现下标负数 \(x\) ,这样处理:

\[x \gets (x+h) \%h \]

如果 \(x\) 是正数,那 \(+h\) 不影响答案;如果 \(x\) 是负数,那 \(+h\) 变为正数,答案也正确。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;

const int N=2e3+1;

inline int read(){char ch=getchar();int f=1;while(ch<‘0‘ || ch>‘9‘) {if(ch==‘-‘) f=-f; ch=getchar();}
	int x=0;while(ch>=‘0‘ && ch<=‘9‘) x=(x<<3)+(x<<1)+ch-‘0‘,ch=getchar();return x*f;}

int n,h,l,r,ans=0;
int a[N],f[N][N];

int main(){
	n=read(),h=read(),l=read(),r=read();
	for(int i=1;i<=n;i++) a[i]=read();
	memset(f,-63,sizeof(f)); //预处理为极小值
	f[0][0]=0;
	for(int i=1;i<=n;i++)
	for(int j=0;j<h;j++)
		f[i][j]=max(f[i-1][(j-a[i]+h)%h],f[i-1][(j-a[i]+1+h)%h])+(l<=j && j<=r);
	for(int i=0;i<h;i++) ans=max(ans,f[n][i]); //将 1~n 的答案取最大值
	printf("%d\n",ans);
	return 0;
}

CF1324E Sleeping Schedule 题解

原文:https://www.cnblogs.com/bifanwen/p/12550615.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!