思路:标程奇奇怪怪,有点绕,搞了半天才勉强看懂,还有数据水了
先背包求出,表示花天学第门课最多能得多少分。
设表示前门课花天学习挂科门能最多能得到的分数,那么有:
如果第门课学天,并且不及格,那么有
如果第门课学天,并且及格,那么有
其实第一维是可以滚掉的,得到,那么有:
如果第门课学天,并且不及格,那么有
如果放弃第门课(一天也不学,即),那么有。把第一维滚掉后,这里特别需要注意,虽然时符合上一个条件,如果使用上面的转移方程,得到的是,等同于,这就出问题了。
如果第门课学天,并且及格,那么有
初始,之后,即
code;
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 3e5+7; int f[55][505],g[505][5]; map<string,int>mp; string s; struct node{ int x,y; }; vector<node>v[55]; int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); int _; int n,m,t,p; cin>>_; while(_--) { mp.clear(); cin>>n; for(int i=1; i<=n; ++i) { cin>>s; mp[s]=i; } cin>>m; for(int i=1,x,y,id; i<=m; ++i) { cin>>s>>x>>y; id=mp[s]; v[id].emplace_back(node{x,y}); } cin>>t>>p; memset(f,0,sizeof f); memset(g,-0x3f,sizeof g); g[0][0]=0; for(int id=1; id<=n; ++id) { for(int i=0; i<v[id].size(); ++i) for(int j=500; j>=v[id][i].y; --j) f[id][j]=max(f[id][j],f[id][j-v[id][i].y]+v[id][i].x); for(int i=500; i; --i) { if(f[id][i]<100) break; f[id][i]=100; } for(int i=t; i; --i) { for(int k=p; k>0; --k)g[i][k]=g[i][k-1];//不选第id个人 g[i][0]=-1e9;//那么不能是max(g[id-1][i][k],g[id-1][i][k-1]) for(int k=0;k<=p; ++k) { for(int j=1; j<=i; ++j) { if(f[id][j]>=60) g[i][k]=max(g[i][k],g[i-j][k]+f[id][j]); else if(k) g[i][k]=max(g[i][k],g[i-j][k-1]+f[id][j]); } } } g[0][0]=-1e9; } int ans=-1; for(int j=0; j<=p; ++j) if(g[t][j]>ans) ans=g[t][j]; cout<<ans<<'\n'; for(int i=1;i<=n;++i) v[i].clear(); } return 0; }