图片加载可能有点慢,请跳过题面先看题解,谢谢
先上一波区间 \(dp\) 的套路,设 \(f[l][r]\) 为消掉区间 \((l,r)\) 的最大分数,然后枚举一个断点 \(k\) ,发现这样的套路根本做不了
那怎么办
我们可以发现一件事情,每消掉一段后,会使得被消掉的这一段的左右两端合到一起,那么就有可能导致两端不在一起的同色的块拼到一起去。这就可以看成是左边那一段的最右边那个块在右边接上了若干个同色的块
所以可以设状态:\(f[l][r][k]\) 为,消掉区间 \((l,r)\) 右边接上 k 个与 r 同色的块的最大分数
这里我们有两种操作:
- 消掉 \(r\) 以及 \(r\) 右边的 \(k\) 个块,\(f[l][r][k]=f[l][r-1][0]+(k+1)^2\);
- 在 \((l,r)\) 中找到一个块 \(i\) 使得 \(color[i]=color[r]\) ,并消除 \((i+1,r-1)\) ,\(f[l][r][k]=max(f[l][i][k+1]+f[i+1][r-1][0])\);
\(f[l][r][k]\) 就是上面两种操作的 \(max\)
$
$
可以记忆搜实现
//made by Hero_of_Someone
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define il inline
#define RG register
using namespace std;
il int gi(){ RG int x=0,q=1; RG char ch=getchar(); while( ( ch<'0' || ch>'9' ) && ch!='-' ) ch=getchar();
if( ch=='-' ) q=-1,ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x; }
int T,t,n,A[210],f[210][210][210];
il void init(){ n=gi(); for(int i=1;i<=n;i++) A[i]=gi(); }
il int dfs(int l,int r,int k){
if(l>r) return 0;
if(f[l][r][k]) return f[l][r][k];
int ret=dfs(l,r-1,0)+(k+1)*(k+1);
for(int i=l;i<r;i++)
if(A[i]==A[r])
ret=max(ret,dfs(l,i,k+1)+dfs(i+1,r-1,0));
return f[l][r][k]=ret;
}
il void work(){
memset(f,0,sizeof(f));
printf("Case %d: %d\n",t,dfs(1,n,0));
}
int main(){ T=gi(); for(t=1;t<=T;t++){ init(); work(); } return 0; }