【BZOJ4922】[Lydsy六月月賽]Karp-de-Chant Number 貪心+動態規劃
阿新 • • 發佈:2017-11-19
ostream 競賽 namespace hint 秘密 動態規劃 += n+1 ems
第一行包含一個正整數n(1<=n<=300),表示括號序列的個數。
接下來n行,每行一個長度在[1,300]之間的括號序列,僅由小括號構成。
())
((()
)()
【BZOJ4922】[Lydsy六月月賽]Karp-de-Chant Number
Description
卡常數被稱為計算機算法競賽之中最神奇的一類數字,主要特點集中於令人捉摸不透,有時候會讓水平很高的選手迷之超時。 普遍認為卡常數是埃及人Qa‘a及後人發現的常數。也可認為是卡普雷卡爾(Kaprekar)常數的別稱。主要用於求解括號序列問題。 據考證,卡(Qa‘a)是古埃及第一王朝的最後一位法老。他發現並研究了一種常數,後世以他的名字叫做卡常數。卡特蘭數的起源也是因為卡的後人與特蘭克斯結婚,生下來的孩子就叫卡特蘭,而他只是發表了祖傳的家書而已。Sereja也是卡的後人,提出括號序列問題,也是從家書裏得到的資料。然而Sereja為了不讓這個秘密公開,於是隱瞞了這道題的真正做法。可是由於卡的後人不是各個都像卡特蘭一樣愛慕虛榮,這一算法也無法找到。“欲見賢人而不以其道,猶欲其入而閉之門也”。卡之常數的奧秘,需要以一顆誠心去追尋。 現給定n個括號序列,你需要選擇若幹序列,將它們按一定的順序從左往右拼接起來,得到一個合法的括號序列。 顯然,這個問題可以用卡常數解決,為了檢驗你是否會卡常數,請寫一個程序,計算可以得到的合法的括號序列的長度的最大值。Input
Output
輸出一行一個整數,即最大長度,註意你可以一個序列也不選,此時長度為0。Sample Input
3())
((()
)()
Sample Output
10HINT
按{2,1,3}的順序拼接得到((()()))(),總長度為10。題解:先用棧求出每個串左邊有多少多余的右括號l,右邊有多少多余的左括號r。那麽我們最終的序列一定是先來一些l<r的,再來一些r<l的。用f[i]表示右面還剩i個多余的左括號時,總長度的最大值,轉移時顯然是背包,但是轉移順序呢?這就是一個經典的貪心模型了。
對於l<r的,顯然我們要先選擇l更小的,因為這樣可以獲得更多的左括號來填掉多余的右括號;對於l>r的就反過來想,先選r更大的。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int n,m; int f[90010]; struct node { int l,r,v; }p[310]; char str[310]; bool cmp(const node &a,const node &b) { if((a.r>a.l)!=(b.r>b.l)) return (a.r>a.l)>(b.r>b.l); if(a.r>a.l) return a.l<b.l; else return a.r>b.r; } int main() { scanf("%d",&n); int i,j; for(i=1;i<=n;i++) { scanf("%s",str),p[i].v=strlen(str),m+=p[i].v; int top=0; for(j=0;j<p[i].v;j++) { if(str[j]==‘)‘) { if(top) top--; else p[i].l++; } else top++; } for(top=0,j=p[i].v-1;j>=0;j--) { if(str[j]==‘(‘) { if(top) top--; else p[i].r++; } else top++; } } sort(p+1,p+n+1,cmp); memset(f,0xc0,sizeof(f)); f[0]=0; for(i=1;i<=n;i++) { if(p[i].r>p[i].l) { for(j=m;j>=p[i].r;j--) f[j]=max(f[j],f[j+p[i].l-p[i].r]+p[i].v); } else for(j=p[i].r;j-p[i].r+p[i].l<=m;j++) f[j]=max(f[j],f[j-p[i].r+p[i].l]+p[i].v); } printf("%d",f[0]); return 0; }
【BZOJ4922】[Lydsy六月月賽]Karp-de-Chant Number 貪心+動態規劃