题目:
从1点起,用拥有的1,2,3,4牌(消耗)移动,最后到达终点,求经过点的权值最大(包括起点)
题解:
应该算是一个基础入门题吧,但我还是想写下
首先想到的DP:
d
p
[
i
]
[
s
1
]
[
s
2
]
[
s
3
]
[
s
4
]
表
示
用
了
s
1
张
1
,
s
2
张
2
,
s
3
张
3
,
s
4
张
4
后
到
达
i
点
的
最
大
值
dp[i][s1][s2][s3][s4]表示用了s1张1,s2张2,s3张3,s4张4后到达i点的最大值
dp[i][s1][s2][s3][s4]表示用了s1张1,s2张2,s3张3,s4张4后到达i点的最大值
然鹅,算下来空间和时间都会炸掉
于是可以发现
i
,
s
4
,
s
3
,
s
2
固
定
后
,
s
1
是
可
以
算
出
来
的
i,s4,s3,s2固定后,s1是可以算出来的
i,s4,s3,s2固定后,s1是可以算出来的
于是变成了
d
p
[
i
]
[
s
2
]
[
s
3
]
[
s
4
]
dp[i][s2][s3][s4]
dp[i][s2][s3][s4]空间时间就刚好过了qwq
然后刷表法走一遭,快乐地输出
d
p
[
n
]
[
t
2
]
[
t
3
]
[
t
4
]
dp[n][t_2][t_3][t_4]
dp[n][t2][t3][t4],AC了qwq
#include<bits/stdc++.h>
using namespace std;
const int N=355,M=45;
int n,m;
int a[N],t[5];
int dp[N][M][M][M];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int x,i=1;i<=m;i++)
scanf("%d",&x),t[x]++;
dp[1][0][0][0]=a[1];
for(int i=1;i<=n;i++)
{
for(int s4=0;s4<=t[4];s4++)
{
for(int s3=0;s3<=t[3];s3++)
{
for(int s2=0;s2<=t[2];s2++)
{
int s1=i-4*s4-3*s3-2*s2-1;if(s1<0)break;if(s1>t[1])continue;
if(s1+1<=t[1])dp[i+1][s2][s3][s4]=max(dp[i][s2][s3][s4]+a[i+1],dp[i+1][s2][s3][s4]);
if(s2+1<=t[2])dp[i+2][s2+1][s3][s4]=max(dp[i][s2][s3][s4]+a[i+2],dp[i+2][s2+1][s3][s4]);
if(s3+1<=t[3])dp[i+3][s2][s3+1][s4]=max(dp[i][s2][s3][s4]+a[i+3],dp[i+3][s2][s3+1][s4]);
if(s4+1<=t[4])dp[i+4][s2][s3][s4+1]=max(dp[i][s2][s3][s4]+a[i+4],dp[i+4][s2][s3][s4+1]);
}
}
}
}
printf("%d",dp[n][t[2]][t[3]][t[4]]);
}