蓝书(算法竞赛进阶指南)刷题记录——POJ1390 Blocks(区间DP+记忆化搜索)

题目:POJ1390.
题目大意:给定一个长度为 n n n的序列,每次可以删除权值相同连续一段且得分为长度的平方,求最大得分.
数据组数 ≤ 15 \leq 15 15, 1 ≤ n ≤ 200 1\leq n\leq 200 1n200.

按照区间DP的套路,设 f [ l ] [ r ] f[l][r] f[l][r]表示区间 [ l , r ] [l,r] [l,r]的答案,发现根本没办法转移.

考虑无法转移的原因是什么,我们发现在转移的时候,若把中间消掉了,还有一段可以并起来,但是这一段并起来的比原来增加的增量并不能直接算出来,现在我们要解决的是如何提前预知增量.

我们先把连续的同色段并称一个二元组 ( a i , c i ) (a_i,c_i) (ai,ci),表示为 a i a_i ai的颜色连续出现了 c i c_i ci个.然后我们设 f [ l ] [ r ] [ k ] f[l][r][k] f[l][r][k]表示区间 [ l , r ] [l,r] [l,r]中第 r r r个二元组变成 ( a r , c r + k ) (a_r,c_r+k) (ar,cr+k)后的答案,这个问题就变得容易了许多.

考虑如何转移,一种情况是 f [ l ] [ r ] [ k ] f[l][r][k] f[l][r][k]中第 r r r个二元组可以不与前面任意一个合并,即 f [ l ] [ r − 1 ] [ 0 ] + ( c r + k ) 2 f[l][r-1][0]+(c_r+k)^2 f[l][r1][0]+(cr+k)2;另一种是当满足 i ∈ [ l , r − 1 ) i\in[l,r-1) i[l,r1) a [ i ] = a [ r ] a[i]=a[r] a[i]=a[r]时,第 r r r个二元组与第 k k k个合并,即 f [ l ] [ i ] [ c r + k ] + f [ m i d + 1 ] [ r − 1 ] [ 0 ] f[l][i][c_r+k]+f[mid+1][r-1][0] f[l][i][cr+k]+f[mid+1][r1][0].即:
f [ l ] [ r ] [ k ] = { ( c l + k ) 2 l = r max ⁡ { f [ l ] [ r − 1 ] [ 0 ] + ( c r + k ) 2 , max ⁡ i = l , a [ i ] = a [ r ] r − 2 { f [ l ] [ i ] [ c r + k ] + f [ i + 1 ] [ r − 1 ] [ 0 ] } } l = ̸ r f[l][r][k]=\left\{\begin{matrix} (c_l+k)^2&l=r\\ \max \left\{ f[l][r-1][0]+(c_r+k)^2,\max_{i=l,a[i]=a[r]}^{r-2} \left\{ f[l][i][c_r+k]+f[i+1][r-1][0] \right\} \right\}&l=\not{}r \end{matrix}\right. f[l][r][k]={(cl+k)2max{f[l][r1][0]+(cr+k)2,maxi=l,a[i]=a[r]r2{f[l][i][cr+k]+f[i+1][r1][0]}}l=rl≠r

这个算法的时间复杂度为 O ( n 4 ) O(n^4) O(n4),但其实有大量无用状态不用计算,所以用记忆化搜索实现后常数会变得非常小,实测可以通过本题.

代码如下:

#include
#include
#include
  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;
}

你可能感兴趣的:(蓝书(算法竞赛进阶指南)刷题记录——POJ1390 Blocks(区间DP+记忆化搜索))