1. 程式人生 > 實用技巧 >2020杭電多校(一) Minimum Index(lyndon分解)

2020杭電多校(一) Minimum Index(lyndon分解)

學習完lyndon分解後,我們發現這個分解可以分割字串並且分割成a[i]>=a[i+1]且每個字串都是自己的最小字尾

因此在分解的過程中

當遇到s[j]==s[k],這說明前面都是迴圈的字串,那麼答案就是上一個同樣位置的答案後移一個迴圈節長度

如果s[j]<s[k],這說明馬上整串都變成一個lyndon字串了,因此答案就是開頭位置是最小的。

如果s[j]>s[k]那就說明當前迴圈節的答案是錯誤的,不過因為本身在求lyndon字串的時候,指標就會跳轉到當前迴圈節首位,所以只需要重算一遍就行了

注意初始化,因為剛開始只有一個字元,因此答案是自身

#include<bits/stdc++.h>
using
namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int N=1e6+10; const int mod=1e9+7; const int BAS=1112; string s; int p[N]; int f[N]; int main(){ ios::sync_with_stdio(false); int t; cin>>t; f[0]=1; for(int i=1;i<N;++i) f[i]=1LL*f[i-1]*BAS%mod; while
(t--){ string s; cin>>s; int n=(int)s.size(); s=" "+s; for(int i=1;i<=n;){ int j=i,k=i+1; p[i]=i; while(k<=n&&s[j]<=s[k]){ if(s[j]<s[k]){ p[k]=i; j
=i; } else{ p[k]=p[j]+(k-j); j++; } k++; } while(i<=j){ i+=k-j; } } ll ans=0; for(int i=1;i<=n;++i) ans=(ans+1ll*f[i-1]*(p[i]))%mod; cout<<ans<<endl; } }
View Code