随便水一篇。(其实是多校单人A的机会太少了)
朱同学非常地不喜欢学习要考试了都没预习完。此时有若干个复习资料,对于一套资料而言,只需花费(x)天就能使该门课提升(y)分。(我也想要这种好东西)问能否在(t)天之内完成逆袭使得挂科数小于(p),如果能够创造奇迹,输出能获得的最大分数。
首先需要处理(m)份的复习资料,用DP来实现,用(f[i][j])表示第(i)门课得到(j)分数所需要的最短天数,这一部分状态转移方程较为常见,复杂度为(O(m*100))。
随后处理最大分数以及挂科数是否能够小于目标值。仍然用DP来实现,代码中用(dp[i][j][k])表示(i-1)门课时花费(j)天且挂科数为(k)时能达到的最高分数。状态转移方程为(dp[i+1][j+f[i][l]][k+1]=max(dp[i+1][j+f[i][l]][k+1],dp[i][j][k]+l))。(l)表示第(i)门课获得(l)分。这一部分做一个四重循环进行DP,但由于系数较小(50*500*4*100),时间复杂度是没有问题的。
#include<bits/stdc++.h> #define fast ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) #define ll long long #define pb push_back using namespace std; const int maxn = 60; const int maxm = 15010; string c[maxn]; int f[maxn][110]; map<string,int> mp; int dp[maxn][510][4]; int main() { fast; int T; cin>>T; while(T--) { mp.clear(); int n,m; string s; int x,y; cin>>n; for(int i=1;i<=n;i++) { cin>>c[i]; mp[c[i]]=i; for(int j=0;j<=100;j++) { if(j==0) f[i][j]=0; else f[i][j]=-1; } } cin>>m; for(int i=1;i<=m;i++) { cin>>s>>x>>y; int tmp=mp[s]; for(int j=100;j>=0;j--) { if(f[tmp][j]!=-1) { if(f[tmp][min(j+x,100)]==-1) f[tmp][min(j+x,100)] = f[tmp][j]+y; else f[tmp][min(j+x,100)] = min(f[tmp][min(j+x,100)],f[tmp][j]+y); } } } int day,limit; cin>>day>>limit; int minn=1e9; int maxx=-1; int sum=0; int flag=0; for(int i=0;i<=n+1;i++) { for(int j=0;j<=day;j++) { for(int k=0;k<=limit;k++) { dp[i][j][k]=-1; } } } dp[1][0][0]=0; for(int i=1;i<=n;i++) { for(int j=0;j<=day;j++) { for(int k=0;k<=3;k++) { // if(k!=3) dp[i+1][j][k+1]=max(dp[i+1][j][k+1],dp[i][j][k]); for(int l=0;l<=100;l++) { if(j+f[i][l]<=day && f[i][l]!=-1 && dp[i][j][k]!=-1) { if(l>=60) dp[i+1][j+f[i][l]][k]=max(dp[i+1][j+f[i][l]][k],dp[i][j][k]+l); else { if(k!=3) dp[i+1][j+f[i][l]][k+1]=max(dp[i+1][j+f[i][l]][k+1],dp[i][j][k]+l); } } } } } } /*for(int i=2;i<=n+1;i++) { for(int j=0;j<=day;j++) { for(int k=0;k<=limit;k++) { cout<<i<<' '<<j<<' '<<k<<' '<<dp[i][j][k]<<' '; } } }*/ for(int i=0;i<=day;i++) { for(int j=0;j<=limit;j++) { maxx=max(dp[n+1][i][j],maxx); } } if(maxx!=-1) cout<<maxx<<' '; else cout<<"-1 "; } }