好久没写博客了,写一发。
之前学的Manacher算法拿到模板题找到那最后一个点的错误了,TMD没开long long。
Manachar算法主要是处理字符串中关于回文串的问题的,它可以在 O(n)的时间处理出以字符串中每一个字符为中心的回文串半径,由于将原字符串处理成两倍长度的新串,在每两个字符之间加入一个特定的特殊字符,因此原本长度为偶数的回文串就成了以中间特殊字符为中心的奇数长度的回文串了。Manacher算法提供了一种巧妙的办法,将长度为奇数的回文串和长度为偶数的回文串一起考虑,具体做法是,在原字符串的每个相邻两个字符中间插入一个分隔符,同时在首尾也要添加一个分隔符,分隔符的要求是不在原串中出现,一般情况下可以用#号。
设f[i]表示以i为中心的最长回文串的半径,如:
string:aba,那么f[2]=2。
那么我们再设一个mx,表示当前推到的最右边界(id+f[id]),初值为0。
再设id表示上一个点。
再看下面这张图:
因为mx=f[id]+id,所以设j为i的对称点,i点的f值为min(f[id*2-i(j)],mx-i),可以理解为i~mx和f[j]的最小值,因为在-mx~mx之间以id对称。
在看例题,先求出f数组,用前缀和求出啦啦队的长度的数量,用快速幂统计。
code:
#include <cstdio> #include <string> #include <cstring> #include <iostream> using namespace std; long long N,K; string S; const long long MOD=19930726; long long pow(long long x,long long k) { long long res=1; while(k){ if(k&1)res=res*x%MOD; x=x*x%MOD; k>>=1; } return res; } string Ne; int f[2000015]; int sum[1000005]; void Manacher() { Ne+="?!"; for(int i=0;i<S.size();i++) Ne+=S[i],Ne+='!'; Ne+='~'; int mx=0,id=0; for(int i=1;i<Ne.size()-1;i++){ f[i]=i<=mx?min(f[id*2-i],mx-i):1; while(Ne[i-f[i]]==Ne[i+f[i]]) f[i]++; if(mx<i+f[i]){ id=i; mx=i+f[i]; } } for(int i=1;i<Ne.size()-1;i++) if(Ne[i]!='!')sum[f[i]-1]++; for(int i=N;i>0;i--) sum[i]+=sum[i+2]; return ; } int main() { cin>>N>>K>>S; Manacher(); long long ans=1; for(int i=N;i>0;i--){ if(K<=0)break; if(sum[i]){ if(K>sum[i])ans=(ans*pow(i,sum[i]))%MOD; else ans=(ans*pow(i,K))%MOD; K-=sum[i]; } } printf("%lld",ans); return 0; }