http://acm.hdu.edu.cn/showproblem.php?pid=3905
dp + 记忆化搜索
把 M 和 L 弄反了 wa 了N久 我彻底无语了
关键思路:
在学了 L 之后如果想继续学 在学的时间无需大于等于 L
代码及其注释:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<vector> #include<queue> #include<map> #include<stack> #include<algorithm> #include<cmath> using namespace std; //#pragma comment(linker,"/STACK:1000000000,1000000000") #define LL long long const int INF=0x3f3f3f3f; const int N=1005; int ansL[N][N];// 前 i 的时间内 至少需要睡 j 分钟 如果学习要至少L 时间 的最优结果 int ans1[N][N];// 前 i 的时间内 至少需要睡 j 分钟 如果学习 可以时间任意 的最优结果 int sum[N];// 前 i 项和 int a[N];// 某个时间点的值 int n,L,M; int dp1(int ,int); int dpL(int i,int j) { if(ansL[i][j]!=-1) return ansL[i][j]; ansL[i][j]=0;//最少获得 0 值 if(j==0) { if(i>=L)// 这时候 剩余量时间在大于等于L的情况下 才可以全部获得 ansL[i][j]=sum[i]; return ansL[i][j]; } if(j-1<=i-1) ansL[i][j]=dpL(i-1,j-1);//此时间点睡觉 if(j<=i-L) ansL[i][j]=max(ansL[i][j],sum[i]-sum[i-L]+dp1(i-L,j));//学习L时间(然后再学的话 时间不受限制) return ansL[i][j]; } int dp1(int i,int j) { if(ans1[i][j]!=-1) return ans1[i][j]; ans1[i][j]=0; if(j==0) return (ans1[i][j]=sum[i]); if(j-1<=i-1) ans1[i][j]=dpL(i-1,j-1);//此时间点睡觉 if(j<=i-1) ans1[i][j]=max(ans1[i][j],a[i]+dp1(i-1,j));//此时间点学习 return ans1[i][j]; } int main() { //freopen("data.txt","r",stdin); while(scanf("%d %d %d",&n,&M,&L)!=EOF) { memset(ansL,-1,sizeof(ansL)); memset(ans1,-1,sizeof(ans1)); for(int i=1;i<=n;++i) scanf("%d",&a[i]); sum[0]=0; for(int i=1;i<=n;++i) { sum[i]=a[i]+sum[i-1]; } printf("%d\n",dpL(n,M)); } return 0; }