2 条题解
-
1
202502cj14 (张子瑞) LV 8 @ 2025-03-23 16:47:58
#include<cstdio>
#define max(a,b) a>b?a:b
#define r(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int f[41][41][41],a[351],n,m,g[4],t;
int main()
{
scanf("%d%d",&n,&m);
r(i,1,n) scanf("%d",&a[i]);
while(m--) {scanf("%d",&t);g[t-1]++;}
f[0][0][0]=0;
r(i,0,g[0])
r(j,0,g[1])
r(k,0,g[2])
r(l,0,g[3])
{
t=a[1+i+(j<<1)+k*3+(l<<2)];
if(j) f[j][k][l]=max(f[j][k][l],f[j-1][k][l]);
if(k) f[j][k][l]=max(f[j][k][l],f[j][k-1][l]);
if(l) f[j][k][l]=max(f[j][k][l],f[j][k][l-1]);
f[j][k][l]+=t;
}
printf("%d",f[g[1]][g[2]][g[3]]);
} -
-12025-03-23 16:48:20@
由于题目告诉我们确保用完牌恰好能走完,题目被大大简化
我们用数组dp[a][b][c][d]表示用了a张一步牌,b张2步牌,c张3步牌,d张4布牌所能得到的最高分
num[i-1]表示i步牌的张数;path[]数组记录路径信息;card[]数组记录卡牌信息。
则有dp[0][0][0][0]=path[0]//什么牌都不用就可以获得起点的分数
并且有**path[a+2b+3c+4d]为当前点的分数**
之后四重循环,分别枚举a,b,c,d;
对于枚举的每种情况:
dp[a][b][c][d]=max(dp[a][b][c][d],**之前的一步操作**+**[a+2b+3c+4d]**)
这句话的意思是:**是不进行前一步操作比较赚还是进行比较赚**
为什么要判断a,b,c,d是否大于0呢?**都没牌了哪里还存在前一步操作呢?**
ok!最后答案被保存在dp[num[0]][[num[1]][num[2]][num[3]]里,输出即可。
talk is cheap shou me the code:
#include<iostream>
using namespace std;
int N,M,pv,num[4],path[500],card[500],dp[42][42][42][42];
int main()
{
cin>>N>>M;
for(int i=0;i<N;i++)cin>>path[i];
for(int i=0;i<M;i++){cin>>card[i];num[card[i]-1]+=1;}
dp[0][0][0][0]=path[0];
for(int a=0;a<=num[0];a++)
for(int b=0;b<=num[1];b++)
for(int c=0;c<=num[2];c++)
for(int d=0;d<=num[3];d++)
{pv=a+b*2+c*3+d*4;
if(a>0) dp[a][b][c][d]=max(dp[a][b][c][d],dp[a-1][b][c][d]+path[pv]);
if(b>0) dp[a][b][c][d]=max(dp[a][b][c][d],dp[a][b-1][c][d]+path[pv]);
if(c>0) dp[a][b][c][d]=max(dp[a][b][c][d],dp[a][b][c-1][d]+path[pv]);
if(d>0) dp[a][b][c][d]=max(dp[a][b][c][d],dp[a][b][c][d-1]+path[pv]);}
cout<<dp[num[0]][num[1]][num[2]][num[3]];
return 0;
}
- 1