CF1324E Sleeping Schedule 题解

博客园同步

原题链接

简要题意:

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

E题是个水dp,也不怎样

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

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

如果不选,那么 f i , j = f i 1 , j a i f_{i,j} = f_{i-1,j-a_i} .

如果选,那么 f i , j = f i 1 , j a i + 1 f_{i,j} = f_{i-1,j-a_i+1} .

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

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

所以:

f i , j = { 0 , i = 0   and   j = 0 max f i 1 , j a i , f i 1 , j a i + 1 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 ,这样处理:

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

如果 x x 是正数,那 + h +h 不影响答案;如果 x x 是负数,那 + h +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;
}

发布了61 篇原创文章 · 获赞 86 · 访问量 8901

猜你喜欢

转载自blog.csdn.net/bifanwen/article/details/105368362