一、题目
二、解法
巧妙的定义,我可能这辈子都想不到。
设 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]为区间 [ i , j ] [i,j] [i,j]右边有 k k k个和 j j j颜色相同的格子,转移:
- 删去 j j j和后面 k k k个格子: d p [ i ] [ j ] [ k ] = d p [ i ] [ j − 1 ] [ 0 ] + v [ k + 1 ] dp[i][j][k]=dp[i][j-1][0]+v[k+1] dp[i][j][k]=dp[i][j−1][0]+v[k+1]
- 枚举一个和 j j j颜色相同的格子 p p p: d p [ i ] [ j ] [ k ] = d p [ i ] [ p ] [ k + 1 ] + d p [ p + 1 ] [ j − 1 ] dp[i][j][k]=dp[i][p][k+1]+dp[p+1][j-1] dp[i][j][k]=dp[i][p][k+1]+dp[p+1][j−1]
一开始一直不理解为什么第一个转移可以直接删除,因为第二个转移实际上是一个一个增加删去的量,所以所有情况都被考虑到了,第一个转移就可以直接删去。时间复杂度 O ( n 4 ) O(n^4) O(n4)
#include <cstdio>
#include <iostream>
using namespace std;
#define int long long
const int M = 105;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,a[M],v[M],dp[M][M][M];
signed main()
{
n=read();
for(int i=1;i<=n;i++)
scanf("%1d",&a[i]);
for(int i=1;i<=n;i++)
v[i]=read();
for(int i=n;i>=1;i--)
for(int j=i;j<=n;j++)
for(int k=0;k<=n-j;k++)
{
dp[i][j][k]=max(dp[i][j][k],dp[i][j-1][0]+v[k+1]);
for(int p=i;p<=j;p++)
if(a[p]==a[j])
dp[i][j][k]=max(dp[i][j][k],dp[p+1][j-1][0]+dp[i][p][k+1]);
}
printf("%lld\n",dp[1][n][0]);
}