代码部落 20250713 CSP-J复赛 模拟赛
网址:代码部落
密码 666888
T1-T3 自行处理
一:T4 游乐场
思路:首先进行可行性判断: 当c[q]>m时,直接输出-1即可
原本我想用01背包做,但因为有免费玩的条件在,所以应直接用线性dp
状态转移方程:
设f[i][j][0/1]表示前i个设施,花费j元,第i个设施是“免费”(0)
或花钱玩(1)时的最大快乐值
转移: f[i][j][0] : 从之前“花钱玩”的设施转移(免费获得当前设施),快乐值+hi
f[i][j][1]: 从之前“免费玩”的设施转移(花钱玩当前设施),快乐值+hi 花费+ci
同时设施按 从大到小排序(保证 “送” 的设施 ),并强制在 DP 中包含 q 设施。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=505;
int f[N][N][2];
int n,m,q;
struct node{int h,c,id;
}a[N];
bool cmp(node xx,node yy){return xx.c>yy.c;
}
signed main(){cin>>n>>m>>q;for(int i=1;i<=n;i++){cin>>a[i].h>>a[i].c;a[i].id=i; }if(a[q].c>m){cout<<-1<<endl;return 0;}sort(a+1,a+1+n,cmp);for(int i=1;i<=n;i++){if(a[i].id==q){q=i;break;}}memset(f,-1,sizeof(f));f[0][0][0]=0;for(int i=1;i<q;i++){for(int j=0;j<=m;j++){for(int k=0;k<i;k++){if(f[k][j][1]!=-1){f[i][j][0]=max(f[i][j][0],f[k][j][1]+a[i].h);}if(j-a[i].c>=0&&f[k][j-a[i].c][0]!=-1){f[i][j][1]=max(f[i][j][1],f[k][j-a[i].c][0]+a[i].h);}}}}for(int j=0;j<=m;j++){for(int k=0;k<q;k++){if(f[k][j][1]!=-1)f[q][j][0]=max(f[q][j][0],f[k][j][1]+a[q].h);if(j-a[q].c>=0&&f[k][j-a[q].c][0]!=-1)f[q][j][1]=max(f[q][j][1],f[k][j-a[q].c][0]+a[q].h);}}for(int i=q+1;i<=n;i++){for(int j=0;j<=m;j++){for(int k=q;k<i;k++){if(f[k][j][1]!=-1)f[i][j][0]=max(f[i][j][0],f[k][j][1]+a[i].h);if(j-a[i].c>=0&&f[k][j-a[i].c][0]!=-1)f[i][j][1]=max(f[i][j][1],f[k][j-a[i].c][0]+a[i].h);}}}int ans=0;for(int i=q;i<=n;i++){for(int j=0;j<=m;j++){ans=max(ans,max(f[i][j][0],f[i][j][1]));}}cout<<ans<<endl;return 0;}