题意:有一排数量为\(N(N<=200)\)的方块,每次可以把连续的相同颜色的区间消除,得到的分数为区间长度的平方,然后左右两边连在一起,问最大分数为多少?
分析:设\(f[i][j][k]\)表示处理区间\([i,j]\),且在\(j\)右边有且仅有\(k\)个和\(j\)同色的方块,消除所有这些方块的最大分数.考虑如何转移?
1.将\(j\)与\(j\)右边\(k\)个和\(j\)同色的方块一起消掉,\(f[i][j][k]=max(f[i][j][k],f[i][j-1][0]+(k+1)^2\)
2.在\([i,j]\)中找到一个和\(j\)同色的点\(p\),消掉\([p+1,j-1]\)使得\(p\)和\(j\)相邻,\(f[i][j][k]=max(f[i][j][k],f[i][p][k+1]+f[p+1][j-1][0])\) \(if(color[p]=color[j])\)
第一个转移中\(j\)右边与\(j\)同色的方块的数量可以直接\(n^2\)预处理,第二个转移中颜色相等的\(p\)与\(j\)两个方块直接循环暴力找.总的时间复杂度为\(T*n^3.T<=15,n<=200\).
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=205;
int a[N],sum[N],f[N][N][N];
int main(){
int T=read();
for(int t=1;t<=T;++t){
memset(f,0,sizeof(f));
memset(sum,0,sizeof(sum));//多组数据一定要记得初始化
int n=read();
for(int i=1;i<=n;++i)a[i]=read();
for(int i=1;i<=n;++i)
for(int j=i+1;j<=n;++j)
if(a[j]==a[i])++sum[i];//预处理i右边有多少个与i颜色相同的方块
for(int i=n;i>=1;--i){//从右边往左边消
for(int j=i;j<=n;++j){
for(int k=0;k<=sum[j];++k)
f[i][j][k]=max(f[i][j][k],f[i][j-1][0]+(k+1)*(k+1));//转移一
for(int p=i;p<j;++p)//暴力找颜色一样的
if(a[p]==a[j]){
for(int k=0;k<=sum[j];++k)
f[i][j][k]=max(f[i][j][k],f[i][p][k+1]+f[p+1][j-1][0]);//转移二
}
}
}
printf("Case %d: %d\n",t,f[1][n][0]);
}
return 0;
}