zoukankan      html  css  js  c++  java
  • @bzoj


    @description@

    卡常数被称为计算机算法竞赛之中最神奇的一类数字,主要特点集中于令人捉摸不透,有时候会让水平很高的选手迷之超时。
    普遍认为卡常数是埃及人Qa'a及后人发现的常数。也可认为是卡普雷卡尔(Kaprekar)常数的别称。主要用于求解括号序列问题。
    据考证,卡(Qa'a)是古埃及第一王朝的最后一位法老。他发现并研究了一种常数,后世以他的名字叫做卡常数。卡特兰数的起源也是因为卡的后人与特兰克斯结婚,生下来的孩子就叫卡特兰,而他只是发表了祖传的家书而已。Sereja也是卡的后人,提出括号序列问题,也是从家书里得到的资料。然而Sereja为了不让这个秘密公开,于是隐瞒了这道题的真正做法。可是由于卡的后人不是各个都像卡特兰一样爱慕虚荣,这一算法也无法找到。“欲见贤人而不以其道,犹欲其入而闭之门也”。卡之常数的奥秘,需要以一颗诚心去追寻。
    【以上全是瞎 BB,不过还蛮有意思的 www】

    现给定n个括号序列,你需要选择若干序列,将它们按一定的顺序从左往右拼接起来,得到一个合法的括号序列。
    显然,这个问题可以用卡常数解决,为了检验你是否会卡常数,请写一个程序,计算可以得到的合法的括号序列的长度的最大值。

    input
    第一行包含一个正整数n(1<=n<=300),表示括号序列的个数。
    接下来n行,每行一个长度在[1,300]之间的括号序列,仅由小括号构成。

    output
    输出一行一个整数,即最大长度,注意你可以一个序列也不选,此时长度为0。

    sample input
    3
    ())
    ((()
    )()
    sample output
    10
    **sample explain **:
    按{2,1,3}的顺序拼接得到((()()))(),总长度为10。

    @solution@

    首先有个小性质:假如在不拼接的情况,一个括号已经有了匹配,那么拼接后这个括号的匹配不会变化。可以根据我们做括号匹配的过程理解这个性质。
    所以基于此,我们可以把串中能匹配的括号先匹配完,剩下的部分一定是形如 “)))))....))(((....(((” 的样子。
    我们将这部分记为 (p, q),其中 p 是 ')' 的个数,q 是 '(' 的个数。

    考虑选了一些括号以后,怎么排列它们是最优的。可以用贪心来解决。
    我们采用交换论证的方法来寻找排列方法。

    假如 a,b 是相邻的且 a 在 b 前面,我们可以先将 a 的 '(' 和 b 的 ')' 匹配完,剩下新的一个 “)))(((” 型的串。
    感性理解一下,我们应该剩下的东西越少越好。又因为 a 与 b 的括号总数不变,我们应该让 a 与 b 匹配尽量多的括号。匹配的括号个数就应该 (=min{(个数,)个数})

    所以如果 (min{a的(个数,b)个数} > min{b的(个数, a的)个数}),则 a 就排在 b 前面。

    可以发现上面那个东西是一直存在的,不会因为我们选的括号不同而变化。
    所以我们可以先按照上面的法则排序,然后作一个简单的 dp 就可以了。

    dp 的定义,以及状态转移留作习题。

    @accepted code@

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int MAXN = 300;
    const int INF = 1<<30;
    struct node{
    	int p, q;
    	int num;
    }a[MAXN + 5];// p -> ')', q -> '('
    bool operator < (node a, node b) {
    	return min(a.q, b.p) > min(a.p, b.q);
    }
    char s[MAXN + 5];
    int dp[2][MAXN*MAXN + 5];
    int main() {
    	int n; scanf("%d", &n);
    	for(int i=1;i<=n;i++) {
    		scanf("%s", s);
    		int len = strlen(s);
    		for(int j=0;j<len;j++) {
    			if( s[j] == '(' ) a[i].q++;
    			else {
    				if( !a[i].q ) a[i].p++;
    				else a[i].q--, a[i].num += 2;
    			}
    		}
    	}
    	int tot = 0; sort(a+1, a+n+1);
    	for(int i=1;i<=n;i++) {
    		for(int j=0;j<=tot;j++)
    			dp[i&1][j] = dp[i&1^1][j];
    		for(int j=tot+1;j<=tot+a[i].q;j++)
    			dp[i&1][j] = -INF;
    		for(int j=a[i].p;j<=tot;j++)
    			dp[i&1][j-a[i].p+a[i].q] = max(dp[i&1][j-a[i].p+a[i].q], dp[i&1^1][j]+2*a[i].p+a[i].num);
    		tot += a[i].q;
    	}
    	printf("%d
    ", dp[n&1][0]);
    }
    

    @details@

    这道题让我想起了多校赛的某道题 HDU - 6299
    当初好像是随便乱蒙了一个贪心性质就过了 www。

  • 相关阅读:
    02-高阶函数 map filter sorted
    01-切片的赋值操作
    学习资料记录
    django_初级学习(1)
    git配置使用
    openpyxl操作表格(2)
    openpyxl模块操作excell表格(1)
    精简语法
    MySQL常见面试题
    02-图片转字符画
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/10184566.html
Copyright © 2011-2022 走看看