题目描述
题解
这道dp想了很久都没有思路。这种消来消去的题目感觉用dp没法搞吖。
果然我还是太弱。
记忆化搜索的方法是看了网上的题解的。不过还是盯着那个状态看了很久才勉强理解。f(l,r,k)表示将l到r这一段区间并且连同r后面的k个和r相同颜色的方块都消完的最大得分。那么
f(l,r,k)=max{f(l,r−1,0)+(k+1)2,f(l,i,k+1)+f(i+1,r−1,0)}
。
实际上我认为这个转移很难理解。不过不想那么多的话也许更好想一点,其实就是分类讨论,
f(l,r−1,0)+(k+1)2
表示将k+1个连着一起消掉,
f(l,i,k+1)+f(i+1,r−1,0)
则表示分成两部分消掉。
但是TA的方法更稳一点,而且更好理解。
f(l,r,k)
要求l,r颜色相同,表示将l~r这一段消到只剩k个和lr颜色相同的点的最大得分,
g(l,r)
表示将lr这一段全部消去的最大得分。
那么
f(l,r,k)=max{f(l,r,k),f(l,i,k−1)+g(i+1,r−1)}
,
g(l,r)=max{f(l,r,k)+k∗k,g(l,i)+g(i+1,r)}
。
时间复杂度
O(n4)
,不过是可以过的。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 205
int T,n,Case;
int color[N],f[N][N][N];
int dp(int l,int r,int k)
{
if (l>r) return 0;
if (f[l][r][k]) return f[l][r][k];
f[l][r][k]=dp(l,r-1,0)+(k+1)*(k+1);
for (int i=r-1;i>=l;--i)
if (color[i]==color[r])
f[l][r][k]=max(f[l][r][k],dp(l,i,k+1)+dp(i+1,r-1,0));
return f[l][r][k];
}
int main()
{
scanf("%d",&T);
while (T--)
{
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",&color[i]);
memset(f,0,sizeof(f));
printf("Case %d: %d\n",++Case,dp(1,n,0));
}
}
Orz TA
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 205
int T,n,Case;
int color[N],tot[N][N],f[N][N][N],g[N][N];
void clear()
{
n=0;
memset(f,128,sizeof(f)); memset(g,0,sizeof(g));
memset(tot,0,sizeof(tot));memset(color,0,sizeof(color));
}
int main()
{
scanf("%d",&T);
while (T--)
{
clear();
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",&color[i]);
for (int i=1;i<=n;++i)
for (int j=i+1;j<=n;++j)
if (color[i]==color[j])
for (int k=i;k<=j;++k)
if (color[k]==color[i]) tot[i][j]++;
memset(f,128,sizeof(f)); memset(g,0,sizeof(g));
for (int i=1;i<=n;++i) f[i][i][0]=1,f[i][i][1]=0,g[i][i]=1;
for (int len=2;len<=n;++len)
for (int l=1;l<=n-len+1;++l)
{
int r=l+len-1;
if (color[l]==color[r])
for (int k=1;k<=tot[l][r];++k)
{
for (int i=l;i<r;++i)
f[l][r][k]=max(f[l][r][k],f[l][i][k-1]+g[i+1][r-1]);
g[l][r]=max(g[l][r],f[l][r][k]+k*k);
}
for (int i=l;i<r;++i)
g[l][r]=max(g[l][r],g[l][i]+g[i+1][r]);
f[l][r][0]=g[l][r];
}
printf("Case %d: %d\n",++Case,g[1][n]);
}
}