CF1324E Sleeping Schedule 题解
阅读原文时间:2023年07月10日阅读:2

CSDN同步

原题链接

简要题意:

每次可以将 \(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;
}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章