题意:有一排数量为(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
",t,f[1][n][0]);
}
return 0;
}