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; } }
没有人不辛苦,只有人不喊疼