思路:标程奇奇怪怪,有点绕,搞了半天才勉强看懂,还有数据水了
先背包求出
,表示花
天学第
门课最多能得多少分。
设表示前
门课花
天学习挂科
门能最多能得到的分数,那么有:
如果第门课学
天,并且不及格,那么有
如果第门课学
天,并且及格,那么有
其实第一维是可以滚掉的,得到,那么有:
如果第门课学
天,并且不及格,那么有
如果放弃第门课(一天也不学,即
),那么有
。把第一维滚掉后,这里特别需要注意,虽然
时符合上一个条件,如果使用上面的转移方程,得到的是
,等同于
,这就出问题了。
如果第门课学
天,并且及格,那么有
初始,之后
,即
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;
}

京公网安备 11010502036488号