https://www.luogu.org/problemnew/show/P1541
2年前做过这道题,不过早就忘了怎么做的了。
看到题,先想到用f(p,i,j,k,l)表示当前在位置p,手中有i,j,k,l张四种面值的卡片,已经得到的分数,
则f(p,i,j,k,l)=max{f(p-1,i+1,j,k,l),f(p-2,i,j+1,k,l),f(p-3,i,j,k+1,l),f(p-4,i,j,k,l+1)}+score(p).
没分析复杂度,结果开始炸了空间,想到空间要350*40^4,就把第一维数组改成循环滚动5个就够了,结果交上去TLE,啊时间也是350*40^4的。
实际上,五维的状态有冗余,当前的位置可以由(i,j,k,l)唯一表示,故改成四维。
设f(i,j,k,l):已经分别使用四张卡片的张数
f[i,j,k,l]:=max{f[i-1,j,k,l]f[i,j-1,k,l],f[i,j,k-1,l],f[i,j,k,l-1]}+a[x],x=1+i+j*2+k*3+l*4
边界是f(0,0,0,0)=a(1)
#include<bits/stdc++.h>
using namespace std;
#define INF (1<<30)
int n,m,a[355],x,tot[5];
int f[45][45][45][45];
int Max(int a,int b,int c,int d)
{
int x=max(a,b),y=max(c,d);
return max(x,y);
}
int main()
{
freopen("input.in","r",stdin);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=m;i++)cin>>x,tot[x]++;
for(int i=0;i<=tot[1];i++)
for(int j=0;j<=tot[2];j++)
for(int k=0;k<=tot[3];k++)
for(int l=0;l<=tot[4];l++)
{
f[i][j][k][l]=a[1+i+2*j+3*k+4*l]+Max(f[max(i-1,0)][j][k][l],
f[i][max(j-1,0)][k][l],f[i][j][max(k-1,0)][l],f[i][j][k][max(l-1,0)]);
}
//这里顺便把存在ijkl=0时-1小于0数组越界的情况也处理了,因为每个状态初始值为0,
//越界的那一个子状态处理为它本身即0即可。比较的四个
//子状态实际上是max(_,_,_,0),使得不受边界之外的影响。
//写4个if也可以
cout<<f[tot[1]][tot[2]][tot[3]][tot[4]]<<endl;
return 0;
}