【BZOJ3325】[Scoi2013]密碼 Manacher
阿新 • • 發佈:2017-09-20
一行 family main tput 小寫字母 中心 sin 字符串 space
3
1 1 1
0 0
Sample #2
3
1 3 1
0 0
Sample #3
3
1 3 1
2 2
abc
Sample #2
aba
Sample #3
aaa
【BZOJ3325】[Scoi2013]密碼
Description
Fish是一條生活在海裏的魚。有一天他很無聊,就到處去尋寶。他找到了位於海底深處的宮殿,但是一扇帶有密碼鎖的大門卻阻止了他的前進。通過翻閱古籍,Fish 得知了這個密碼的相關信息: 1. 該密碼的長度為N。 2. 密碼僅含小寫字母。 3. 以每一個字符為中心的最長回文串長度。 4. 以每兩個相鄰字符的間隙為中心的最長回文串長度。 很快Fish 發現可能有無數種滿足條件的密碼。經過分析,他覺得這些密碼中字典序最小的一個最有可能是答案,你能幫他找到這個密碼麽? 註意:對於兩個串A和B,如果它們的前i個字符都相同,而A的第i+1個字符比B的第i+1個字符小,那麽認為是則稱密碼A 的字典序小於密碼B 的字典序,例如字符串abc 字典序小於字符串acb。如果密碼A的字典序比其他所有滿足條件的密碼的字典序都小,則密碼A是這些密碼中字典序最小的一個。Input
輸入由三行組成。
第一行僅含一個整數N,表示密碼的長度。
第二行包含N 個整數,表示以每個字符為中心的最長回文串長度。
第三行包含N - 1 個整數,表示每兩個相鄰字符的間隙為中心的最長回文串長度。
對於20% 的數據,1 <= n <= 100。
另有30% 的數據,1 <= n <= 1000。
最後50% 的數據,1 <= n <= 10^5。
Output
輸出僅一行。輸出滿足條件的最小字典序密碼。古籍中的信息是一定正確的,故一定存在滿足條件的密碼。
Sample Input
Sample #13
1 1 1
0 0
Sample #2
1 3 1
0 0
Sample #3
3
1 3 1
2 2
Sample Output
Sample #1abc
Sample #2
aba
Sample #3
aaa
題解:我們模擬Manacher的過程,Manacher的時候是當str[..]=str[..]時,rl[i]++,那麽我們已知了rl,如果rl比當前值大了,則說明str[..]=str[..],否則str[..]!=str[..]。
相等的條件比較好判斷,那不等的條件呢?用f[i][j]表示i字符能不能取j,那麽如果i字符沒有與...相等的條件,就讓它等於i可以取的最小字符即可。
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int maxn=200010; char str[maxn]; int n,mx,pos; int rl[maxn],f[maxn][26]; inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘)f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+gc-‘0‘,gc=getchar(); return ret*f; } int main() { n=rd(); int i,j; for(i=1;i<=n;i++) rl[i*2-1]=rd()+1; for(i=1;i<=n-1;i++) rl[i*2]=rd()+1; n<<=1,str[1]=‘a‘,str[0]=‘*‘,rl[0]=1; for(i=0,mx=-1;i<=n;i++) { if(!(i&1)) str[i]=‘*‘; else { if(str[i]<‘a‘) { for(j=0;j<26;j++) if(!f[i][j]) break; str[i]=‘a‘+j; } } if(mx>i) j=min(mx-i+1,rl[2*pos-i]); else j=1; for(j--;j<rl[i];j++) str[i+j]=str[i-j]; if(rl[i]<=i) f[i+rl[i]][str[i-rl[i]]-‘a‘]=1; if(mx<i+rl[i]-1) mx=i+rl[i]-1,pos=i; } for(i=1;i<n;i+=2) printf("%c",str[i]); return 0; }
【BZOJ3325】[Scoi2013]密碼 Manacher