P2135 方块消除
区间dp
2135
a[i]第i个数
b[i]第i个数有几个
s[i]从1到i一共有多少个格子(前缀和
首先我们们读题可以发现,这是一个区间的题,而且这很不像贪心,于是我们考虑dp,首先也是最明显的就是一个区间嘛,所以一定要有l,r。
然而我们可以发现这不够,因为我们想让后面连在一起消除,所以我们还要维护一个后面有几个和a[r],一样的数,这样更好转移,dp[l][r][k]表示在l到r这段区间,后面有k个和a[r]一样的数,全部删掉后的最大得分,这样我们就想办法把他们一起消除使得分最高。
先是我们为他们赋值。
枚举k(0~s[n]-s[r])//剩下一共s[n]-s[r]个数
dp[l][r][k]=dp[l][r-1][0]+(b[r]+k)(b[r]+k);
然后枚举k(分割点a[k]==a[r])
j(0~s[n]-s[r])
dp[l][r][k]=max(dp[l][r][k],dp[l][k][b[r]+j]+dp[k+1][r-1][0]. //区间加区间。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n;
int a[50001],b[50001],s[50001];
int dp[200][200][200];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
s[i]=s[i-1]+b[i];
}
for(int i=0;i<=n;i++)
{
for(int l=1;l<=n;l++)
{
int r=i+l;
if(i+l>n)
break;
for(int k=0;k<=s[n]-s[r];k++)
dp[l][r][k]=dp[l][r-1][0]+(b[r]+k)*(b[r]+k);
for(int k=l;k<r;k++)
for(int j=0;j<=s[n]-s[r];j++)
{
if(a[k]==a[r])
dp[l][r][j]=max(dp[l][r][j],dp[l][k][b[r]+j]+dp[k+1][r-1][0]);
}
}
}
printf("%d",dp[1][n][0]);
return 0;
}