版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/90766227
题目:POJ1390.
题目大意:给定一个长度为
的序列,每次可以删除权值相同连续一段且得分为长度的平方,求最大得分.
数据组数
,
.
按照区间DP的套路,设 表示区间 的答案,发现根本没办法转移.
考虑无法转移的原因是什么,我们发现在转移的时候,若把中间消掉了,还有一段可以并起来,但是这一段并起来的比原来增加的增量并不能直接算出来,现在我们要解决的是如何提前预知增量.
我们先把连续的同色段并称一个二元组 ,表示为 的颜色连续出现了 个.然后我们设 表示区间 中第 个二元组变成 后的答案,这个问题就变得容易了许多.
考虑如何转移,一种情况是
中第
个二元组可以不与前面任意一个合并,即
;另一种是当满足
且
时,第
个二元组与第
个合并,即
.即:
这个算法的时间复杂度为 ,但其实有大量无用状态不用计算,所以用记忆化搜索实现后常数会变得非常小,实测可以通过本题.
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=200;
int n,a[N+9],cnt[N+9],dp[N+9][N+9][N+9],vis[N+9][N+9][N+9];
int sqr(int x){return x*x;}
int Dfs_dp(int L,int R,int i){
int &res=dp[L][R][i];
if (vis[L][R][i]) return res;
vis[L][R][i]=1;
if (L==R) return res=sqr(cnt[L]+i);
res=Dfs_dp(L,R-1,0)+sqr(cnt[R]+i);
for (int mid=L;mid<R-1;++mid)
if (a[mid]==a[R]) res=max(res,Dfs_dp(L,mid,cnt[R]+i)+Dfs_dp(mid+1,R-1,0));
return res;
}
Abigail into(){
scanf("%d",&n);
int ca=0,x;
for (int i=1;i<=n;++i){
scanf("%d",&x);
if (a[ca]==x) ++cnt[ca];
else a[++ca]=x,cnt[ca]=1;
}
n=ca;
}
Abigail work(){
for (int i=1;i<=n;++i)
for (int j=i;j<=n;++j)
for (int k=0;k<=n;++k)
vis[i][j][k]=0;
}
Abigail outo(int cas){
printf("Case %d: %d\n",cas,Dfs_dp(1,n,0));
}
int main(){
int T;
scanf("%d",&T);
for (int i=1;i<=T;++i){
into();
work();
outo(i);
}
return 0;
}