POJ 1390 Blocks

【题意】

你们中的一些人可能玩过一个叫做消木块的游戏。

n个木块排成一列,每个木块都有一个颜色。

例如下图中木块的颜色分别为:金,银,银,银,银,铜,铜,铜,金。

在这里插入图片描述

每次,你都可以点击一个木块,这样被点击的木块以及和它相邻并且同色的木块就会消除。

如果一次性消除了k个木块,那么就会得到k*k分。

例如下图所示,点击银色木块,四个木块被消去,得到16分。
在这里插入图片描述

给定你一个游戏初始状态,请你求出最高得分是多少。

【输入格式】

第一行包含整数t,表示共有t组测试数据。

每组数据第一行包含整数n,表示共有n个木块。

第二行包含n个整数,表示n个木块的颜色。

代表木块颜色的整数范围是1~n。

【输出格式】

每组数据输出一个结果,每个结果占一行。

输出格式为“Case x: y”,其中x为数据组别编号,从1开始,y为结果。

【数据范围】

1≤t≤100

1≤n≤200

【输入样例】

2

9

1 2 2 2 2 3 3 3 1

1

1

【输出样例】

Case 1: 29

Case 2: 1

非常规区间DP

首先,我们可以把相同连续的数压成一个数。
然后,我们可以想到定义f[i][j]ijf[i][j]表示isim j 的最大得分.
然而,对于两段颜色相同的,可以通过消去中间的数使得它们连续——这就使得问题有点棘手。
也就是说,一个区间的右端的数,既可以和右边的合并,也可以和左边的合并,但是合并的数的总个数又不一定。
由于我们迫切地期望知道多合并的数的个数,所以我们不妨加一个维度——定义f[i][j][k][l,r]krf[i][j][k]表示区间[l,r]加上右边k个与r颜色相同的数的最大得分(注意:这个得分是预支的,并不用考虑r右边的情况)。

当然,因为右端点可以和左边的合并,所以我们可以找到一个左边同色的位置来贡献答案:
状态转移方程:f[l][r]k]=f[l][pos][k+cnt[r]]+f[pos+1,r1][0](col[pos]=col[r],cnt[r])f[l][r]k]=f[l][pos][k+cnt[r]]+f[pos+1,r-1][0](col[pos]=col[r],cnt[r]表示右端点所代表的原数的个数)

上面的话有些难理解,需要耐心咀嚼

代码:

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define g getchar()
using namespace std;
const int N=205;
void qr(int&x) {
	char c=g;x=0;
	while(!isdigit(c))c=g;
	while(isdigit(c))x=x*10+c-'0',c=g;
}
int T,num,n,c[N],cnt[N],tot,pre[N],last[N],f[N][N][N];
 
inline int dfs(int l,int r,int k) {
    int &x=f[l][r][k];
    if(x>0) return x;
    if(l>r) return 0;
    x=dfs(l,r-1,0)+(cnt[r]+k)*(cnt[r]+k);
    for(int pos=pre[r];pos>=l;pos=pre[pos])
        x=max(x,dfs(l,pos,k+cnt[r])+dfs(pos+1,r-1,0));
    return x;
}
     
int main() {
    qr(T);
    while(T--) {
        memset(f,0,sizeof f);
        memset(last,0,sizeof last);
        tot=0; qr(n);
        for(int i=1,x;i<=n;i++) {
            qr(x);
            if(x!=c[tot]) { 
                c[++tot]=x; 
                cnt[tot]=1;
            }
            else cnt[tot]++;
        }
        for(int i=1;i<=tot;i++) {
            pre[i]=last[c[i]];
            last[c[i]]=i;
        }
        printf("Case %d: %d
",++num,dfs(1,tot,0));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zsyzlzy/p/12373873.html