题意:
(from洛谷)
思路:
很容易想到DP。
dp[i][j]表示选完前i个元素前缀和对h取余的值为j的优秀睡眠的个数。
划分依据就是选择第i个元素时是否将其减一,如果不减一的话,上一个状态就是dp[i-1][j-a[i]],即选完前i-1个元素后前缀和对h取余的值为j-a[i]的优秀睡眠的个数;减一的话也类似。
有两个需要注意的点:
一是初始化,因为有些状态不合法,要初始化为极小值。
二是关于取余的问题,应该要保证dp数组的第二维为正数。
代码:
#pragma GCC optimize("Ofast",3,"inline") #include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ll,ll>PLL; typedef pair<int,int>PII; typedef pair<double,double>PDD; #define I_int ll inline ll read() { ll x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-')f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*f; } char F[200]; inline void out(I_int x) { if (x == 0) return (void) (putchar('0')); I_int tmp = x > 0 ? x : -x; if (x < 0) putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0) putchar(F[--cnt]); //cout<<" "; } ll ksm(ll a,ll b,ll p) { ll res=1; while(b) { if(b&1)res=res*a%p; a=a*a%p; b>>=1; } return res; } const ll inf = 0x3f3f3f3f3f3f3f3f; const int maxn=1e5+100,mod=1e8; const double PI = atan(1.0)*4; const double eps=1e-6; int n,h,l,r; int a[maxn],dp[2100][2100]; int main() { n=read(),h=read(),l=read(),r=read(); for(int i=1;i<=n;i++) a[i]=read(); memset(dp,-0x3f,sizeof dp); dp[0][0]=0; for(int i=1;i<=n;i++) for(int j=0;j<h;j++){ int tmp=0; if(j>=l&&j<=r) tmp++; dp[i][j]=max(dp[i-1][(j-a[i]+h)%h],dp[i-1][(j-a[i]+1+h)%h])+tmp; } int maxx=0; for(int i=0;i<h;i++) maxx=max(maxx,dp[n][i]); out(maxx); return 0; }