题目大意:给定一序列,可点击某一位置消除与其相邻且相同的方块,得分为$len*len$,求最大得分。
解题关键:关键是状态的构造,首先离散化一下,令$dp[i][j][k]$表示序列$i-j$且后面有$k$个与该序列最后位置相同的元素,
则$dp[i][j][k]$可以由两种情况转化而来,
1、最后一部分自己消除 $dp[i][j][k]=dp[i][j-1][0]+(k+len[j])*(k+len[j])$
2、最后一部分和该序列中前面的某一部分消除,假设坐标pos与r颜色相同 $dp[i][j][k]=dp[i][pos][k+len[j]]+dp[pos+1][j-1][0]$
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> #include<cmath> using namespace std; typedef long long ll; int t,n,dp[202][202][202],a[202],len[202],clr[202],num; int dfs(int l,int r,int k){ if(l>r) return 0; if(dp[l][r][k]) return dp[l][r][k]; dp[l][r][k]=dfs(l,r-1,0)+(k+len[r])*(k+len[r]); for(int i=l;i<r;i++){ if(clr[i]==clr[r]) dp[l][r][k]=max(dp[l][r][k],dfs(l,i,k+len[r])+dfs(i+1,r-1,0)); } return dp[l][r][k]; } int main(){ scanf("%d",&t); for(int ca=1;ca<=t;ca++){ memset(dp,0,sizeof dp); memset(len, 0, sizeof len); num=0; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",a+i); for(int i=0;i<=n;i++){ if(a[i]!=a[i-1]) clr[++num]=a[i],len[num]=1; else len[num]++; } int ans=dfs(1,num,0); printf("Case %d: %d ",ca,ans); } return 0; }