1. 程式人生 > >[bzoj4922]Karp-de-Chant Number

[bzoj4922]Karp-de-Chant Number

mes 公開 () 解決 sin ios 翻轉 chan top

來自FallDream的博客,未經允許,請勿轉載,謝謝。


卡常數被稱為計算機算法競賽之中最神奇的一類數字,主要特點集中於令人捉摸不透,有時候會讓水平很高的選手迷之超時。 普遍認為卡常數是埃及人Qa‘a及後人發現的常數。也可認為是卡普雷卡爾(Kaprekar)常數的別稱。主要用於求解括號序列問題。 據考證,卡(Qa‘a)是古埃及第一王朝的最後一位法老。他發現並研究了一種常數,後世以他的名字叫做卡常數。卡特蘭數的起源也是因為卡的後人與特蘭克斯結婚,生下來的孩子就叫卡特蘭,而他只是發表了祖傳的家書而已。Sereja也是卡的後人,提出括號序列問題,也是從家書裏得到的資料。然而Sereja為了不讓這個秘密公開,於是隱瞞了這道題的真正做法。可是由於卡的後人不是各個都像卡特蘭一樣愛慕虛榮,這一算法也無法找到。“欲見賢人而不以其道,猶欲其入而閉之門也”。卡之常數的奧秘,需要以一顆誠心去追尋。 現給定n個括號序列,你需要選擇若幹序列,將它們按一定的順序從左往右拼接起來,得到一個合法的括號序列。 顯然,這個問題可以用卡常數解決,為了檢驗你是否會卡常數,請寫一個程序,計算可以得到的合法的括號序列的長度的最大值。 n<=300 合法的括號序列只要滿足前綴和都大等於0並且總和是0就行了。 預處理每個序列的和還有前綴最小值 合法的括號序列可以看成兩段接起來,分別由和是正的 和 和是負的組成。 對於和是正的,按照前綴最小值排序之後背包dp 負的也同理,翻轉一下就是同樣的做法了。 復雜度n^3
#include<iostream>
#include
<cstdio> #include<algorithm> #include<cstring> #define MN 300 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < 0 || ch > 9){ if(ch == -) f = -1; ch = getchar();} while(ch >= 0 && ch <= 9){x = x * 10
+ ch - 0;ch = getchar();} return x * f; } char st[MN+5][MN+5]; int n,len[MN+5],mn[MN+5],f[MN*MN+5],g[MN*MN+5],mx[MN+5],top=0,top2=0,ans=0; struct data{int x,l,len;}q[MN+5],q2[MN+5]; bool cmp(data x,data y){return x.x>y.x;} int main() { n=read(); memset(f,128,sizeof(f)); memset(g,
128,sizeof(g)); for(int i=1;i<=n;++i) { scanf("%s",st[i]+1); for(int j=1;st[i][j];++j) len[i]+=st[i][j]==(?1:-1, mn[i]=min(mn[i],len[i]); for(int j=strlen(st[i]+1),k=0;j;--j) k+=st[i][j]==(?1:-1,mx[i]=max(mx[i],k); len[i]>=0?(q[++top]=(data){mn[i],len[i],strlen(st[i]+1)},0): (q2[++top2]=(data){-mx[i],-len[i],strlen(st[i]+1)},0); } sort(q+1,q+top+1,cmp); sort(q2+1,q2+top2+1,cmp); f[0]=g[0]=0; for(int i=1;i<=top;++i) for(int j=i*MN;j>=q[i].l-q[i].x;--j) f[j]=max(f[j],f[j-q[i].l]+q[i].len); for(int i=1;i<=top2;++i) for(int j=i*MN;j>=q2[i].l-q2[i].x;--j) g[j]=max(g[j],g[j-q2[i].l]+q2[i].len); for(int i=MN*MN;~i;--i) if(f[i]>=0&&g[i]>=0) ans=max(ans,f[i]+g[i]); cout<<ans; return 0; }

[bzoj4922]Karp-de-Chant Number