zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    c++中的length,strlen;静态数据成员,静态局部变量
    c++中*的含义
    (1)引用的解释; (2)类的成员函数在类外实现的情况
    DbFunctions 作为 LINQ to Entities 查询的一部分使用时,此方法调用规范 CreateDateTime EDM 函数以创建新的 DateTime 对象。
    年视图,选择月份 ---bootstrap datepicker
    时间控件,页面刷新初始化时间控件只显示年月
    load加载层
    response 下载文件火狐浏览器文件名乱码问题
    Web Uploader
    layer是一款近年来备受青睐的web弹层组件
  • 原文地址:https://www.cnblogs.com/zsyzlzy/p/12373873.html
Copyright © 2011-2022 走看看