hdu6761 | 杭電多校2020#1 T11 Minimum Index
阿新 • • 發佈:2020-07-21
這是我給我們隊本場比賽的唯一貢獻,而且還帶著 3 發罰時 /kk。
考慮一個字串的最長字尾怎麼求,顯然一個字尾排序就完事了,可是這並不能拓展到一個字串的所有字首,所以他 GG 了。
所以考慮 lyndon 分解,那麼最小字尾就是分解得到的最後一個 lyndon word 。證明略
所以要計算出字串的所有字首的 lyndon 分解,考慮 Duval 演算法的過程,設當前字首的末尾是 \(j\)
- 如果 \(i\) 是原串 lyndon 分解的一段終點,那麼他的答案就是這段的起點
- 否則,設當前維護的近似 lyndon 串的長度為 \(len\) ,最小週期為 \(d\)
-
- 若 \(len=d\)
- 否則 \(ans_j=ans_{j-d}+d\) ,即與上一個週期答案相對位置相同,證明:顯然不會有這個週期之前的答案優於他,否則他就應該被前一個 lyndon word 包含;所以只與最後一個週期有關,必然是這樣。
- 若 \(len=d\)
題外話:lyndon 分解那套理論真的是 easy 嗎
Code:
#define N 1000005 char s[N]; int ans[N],tans[N]; void work() { scanf("%s",s+1); int n=strlen(s+1); int cnt=0; for(int i=1;i<=n;) { int j=i+1,k=i; ans[i]=i; while(j<=n&&s[k]<=s[j]) { if(k==i) ans[j-1]=i; else ans[j-1]=ans[k-1]+(j-k); if(s[k]==s[j]) k++; else k=i; j++; } while(i<=k) { i+=j-k; tans[++cnt]=i-1; } } for(int i=1;i<=cnt;i++) ans[tans[i]]=tans[i-1]+1; int Ans=0,tmp=1; for(int i=1;i<=n;i++) { Ans=add(Ans,mul(tmp,ans[i])); tmp=mul(tmp,1112); } printf("%d\n",Ans); } signed main() { int T=read(); while(T--) work(); return 0; }