题目描述见原题。
分析
假如以s[i]为中心,求出的最长回文子串为len,那么可以分别得到一个长度为len-2,len-4,...,1的回文子串。若知道每种长度的回文串数量即可求出答案。
我们不妨这么做:先对每个点求出以它为中心,向左右拓展的最长回文串长度len,并把len的计数加一,然后把一点的回文串计数也加一。如果我们先计算出了每个点左右拓展的最长回文串,那么只需逆推,就可得到所有长度回文串的计数。然后只需对于每种可以选的长度做快速幂即可。注意此题只需要奇数长度的回文串。
求最长回文子串?当然是Manacher!模板都几乎不用改的。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
typedef unsigned long long LL;
const int MAXN=1000005;
const LL mod=19930726;
char s[MAXN*2],a[MAXN];
int N=0,M,p[MAXN*2];
LL K,cnt[MAXN*2];
LL Pow(LL x,LL k,LL mo)
{
LL s=1;
while(k)
{
if(k&1) s=(s*x)%mo;
x=x*x%mo;
k=k>>1;
}
return s;
}
void solve()
{
scanf("%d%lld%s",&M,&K,a);
int i=0,maxright=0,mid=0;
s[N]='$';s[++N]='#';
while(i<M)
{
s[++N]=a[i];
s[++N]='#';
i++;
}s[N+1]='\0'; //插入其他字符
for(i=1;i<N;i++)
{
p[i]=maxright>i?min(p[mid*2-i],maxright-i):1;
while(s[i+p[i]]==s[i-p[i]]) p[i]++;
if(i+p[i]-1>maxright)
{
maxright=i+p[i]-1;
mid=i;
}
cnt[p[i]-1]++; //第一遍统计
}
for(i=M-(1-M%2);i>=1;i-=2) cnt[i]+=cnt[i+2]; //逆推统计
LL ans=1;
for(LL i=M-(1-M%2);i>=1;i-=2) //统计答案
{
if(K<=cnt[i])
{
ans=(ans*Pow(i,K,mod))%mod;
break;
}
ans=(ans*Pow(i,cnt[i],mod))%mod;
K-=cnt[i];
}
cout<<ans;
}
int main()
{
solve();
return 0;
}