4922: Karp-de-Chant Number
卡常數被稱為電腦演算法競賽之中最神奇的一類數字,主要特點集中於令人捉摸不透,有時候會讓水平很高的選手迷之逾時。
普遍認為卡常數是埃及人Qa’a及後人發現的常數。也可認為是卡普雷卡爾(Kaprekar)常數的別稱。主要用於求解括弧序列問題。
據考證,卡(Qa’a)是古埃及第一王朝的最後一位法老。他發現並研究了一種常數,後世以他的名字叫做卡常數。卡特蘭數的起源也是因為卡的後人與特蘭克斯結婚,生下來的孩子就叫卡特蘭,而他只是發表了祖傳的家書而已。Sereja也是卡的後人,提出括弧序列問題,也是從家書裡得到的資料。然而Sereja為了不讓這個秘密公開,於是隱瞞了這道題的真正做法。可是由於卡的後人不是各個都像卡特蘭一樣愛慕虛榮,這一演算法也無法找到。“欲見賢人而不以其道,猶欲其入而閉之門也”。卡之常數的奧秘,需要以一顆誠心去追尋。
現給定n個括弧序列,你需要選擇若干序列,將它們按一定的順序從左往右拼接起來,得到一個合法的括弧序列。
顯然,這個問題可以用卡常數解決,為了檢驗你是否會卡常數,請寫一個程式,計算可以得到的合法的括弧序列的長度的最大值。
Input
第一行包含一個正整數n(1<=n<=300),表示括弧序列的個數。
接下來n行,每行一個長度在[1,300]之間的括弧序列,僅由小括弧構成。
Output
輸出一行一個整數,即最大長度,注意你可以一個序列也不選,此時間長度度為0。
Sample Input
3
())
((()
)()
Sample Output
10
HINT
按{2,1,3}的順序拼接得到((()()))(),總長度為10。
新加兩組資料by alone_wolf 2017.6.20
wohenshuai大佬帶飛我
思路就是排序後DP
然後資料範圍300,所以隨便搞
n3 n^3也可以過
那麼問題就是怎麼排序
首先,有用的只有兩個值x,y,分別代表,這個字串的最小值和總和
字串當然是看作括弧序列啦,(為1,)為-1
我們來分類討論一下:
x>0且y>0 那麼這個字串肯定是分在決策第一類,因為他可以給我們更多的左括弧以便後面匹配
x>0且y<0 不存在的,那不成你x>y?
x<0且y>0 這種字串肯定是分在決策第二類,但若有兩個字串都符合這個規則,則讓x大的先決策,正確性顯然
x<0且y<0 這種情況就有一點點複雜了
我們考慮現在有兩個字串a和b,現在有的左括弧為j
那麼我看考慮,若我們同時想擁有a和b(當然,這個單個放是肯定可以的)
先放a,要滿足的條件為:j+a.y+b.x>0
先放b,要滿足的條件為j+b.y+a.x>0
我們來思考哪一個條件更苛刻,肯定是簡單的一個優先
於是就是要比較
a.y+b.x和b.y+a.x
移項就好了
#include<cstdio>#include<algorithm>#include<iostream>#include<cstring>using namespace std;const int N=305;const int MAX=1<<30;int n;struct qq{ char a[N]; int len; int x,y;//最小值 總和 }s[N];bool cmp (qq a,qq b)//a是否比b優 換句話說是否不需要交換 { if (a.y>=0&&b.y<0) return true; if (b.y>=0&&a.x<0) return false; if (a.y>=0) return a.x>b.x; return a.y-a.x>b.y-b.x;}int f[2][100005];int main(){ scanf("%d",&n); for (int u=1;u<=n;u++) { scanf("%s",s[u].a+1); s[u].len=strlen(s[u].a+1); int ooo=0; s[u].x=0; for (int i=1;i<=s[u].len;i++) { if (s[u].a[i]=='(') ooo++; else ooo--; s[u].x=min(s[u].x,ooo); } s[u].y=ooo; } for (int u=1;u<=n;u++) for (int i=u+1;i<=n;i++) if (!cmp(s[u],s[i])) swap(s[u],s[i]); /*for (int u=1;u<=n;u++) printf("%d %d %d\n",s[u].x,s[u].y,s[u].len);*/ int now=0; for (int u=1;u<=90000;u++) f[0][u]=-MAX; f[0][0]=0; for (int u=1;u<=n;u++) { now^=1; for (int i=0;i<=90000;i++) f[now][i]=f[now^1][i]; for (int i=0;i<=90000;i++) if (i+s[u].x>=0&&i+s[u].y<=90000)//合法就好 f[now][i+s[u].y]=max(f[now][i+s[u].y],f[now^1][i]+s[u].len); /*for (int i=0;i<=10;i++) printf("%d ",f[now][i]); printf("\n");*/ } printf("%d\n",f[now][0]); return 0;}