思路:
标程奇奇怪怪,有点绕,搞了半天才勉强看懂,还有数据水了
背包求出,表示花天学第门课最多能得多少分。
表示前门课花天学习挂科门能最多能得到的分数,那么有:

如果第门课学天,并且不及格,那么有

如果第门课学天,并且及格,那么有

其实第一维是可以滚掉的,得到,那么有:
如果第门课学天,并且不及格,那么有

如果放弃第门课(一天也不学,即),那么有。把第一维滚掉后,这里特别需要注意,虽然时符合上一个条件,如果使用上面的转移方程,得到的是,等同于,这就出问题了。

如果第门课学天,并且及格,那么有

初始,之后,即

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;
}