题目:https://www.luogu.org/problemnew/show/UVA10559
应该想到区间dp。但怎么设计状态?
因为连续的东西有分值,所以应该记录一下连续的有多少个。
只要记录与边界连续的有多少个就能涵盖所有的连续了。只记一边的边界即可。
两个转移:用掉记录的那些连续的 或 在自己区间中再找一个一样颜色的使连续数量+1。
用掉了以后剩余部分的连续长度就是0。也许 j-1 和 j 同色,但这个可以在另一个转移里体现,所以没问题。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=205; int T,n,a[N],dp[N][N][N]; int rdn() { int ret=0,fx=1; char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=-1; ch=getchar();} while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return ret*fx; } void init() { memset(dp,0,sizeof dp); } int main() { T=rdn(); for(int t=1;t<=T;t++) { init(); n=rdn(); for(int i=1;i<=n;i++) a[i]=rdn(); for(int i=1;i<=n;i++) for(int k=0;k<=(n-i);k++) dp[i][i][k]=(k+1)*(k+1); for(int d=2,lm=n-d+1;d<=n;d++) for(int i=1,j,LM;i<=lm;i++) { j=i+d-1; LM=n-j; for(int k=0;k<=LM;k++) { dp[i][j][k]=dp[i][j-1][0]+(k+1)*(k+1); for(int l=i;l<j;l++) if(a[l]==a[j]) dp[i][j][k]=max(dp[i][j][k], dp[i][l][k+1]+dp[l+1][j-1][0]); //printf("dp[%d][%d][%d]=%d ",i,j,k,dp[i][j][k]); } } printf("Case %d: %d ",t,dp[1][n][0]); } return 0; }