[Luogu P1659] 拉拉队排练
badge:
因为只求奇数长度的回文串,所以不需要中间加字符。
先求出Manacher数组。
然后,对于一个回文中心i,以它为中心的回文串半径长度一定存在p[i],p[i]-2,p[i]-4,...,1各自都有一个。
所以对p[i]这个值,在值域上打一下标记,从大到小做一下后缀和就可以了。
记得用快速幂。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const long long mo=19930726ll;
long long maxf(long long x,long long y){return x>y?x:y;}
long long minf(long long x,long long y){return x<y?x:y;}
long long p[2000010];
char s[2000010];
long long quickpow(long long a,long long x)
{
long long ans=1ll;
while(x)
{
if(x&1)ans=(ans*a)%mo;
a%=mo;
a=(a*a)%mo;
x>>=1;
}
return ans;
}
long long tot[1000010];
int main()
{
long long n,m,i,j,k,x,y,z;
long long mx,id,lm,maxn,sum;
long long ans=1ll;
scanf("%lld%lld",&n,&m);
scanf("%s",s+1);
s[0]='$';
p[0]=1;
mx=id=lm=0;
maxn=1;
for(i=1;i<=n;i++)
{
j=2*id-i;
if(i<=mx)p[i]=minf(p[j],mx-i+1);
else p[i]=1;
while(s[i+p[i]]==s[i-p[i]])p[i]++;
if(mx<i+p[i]-1)
{
mx=i+p[i]-1;
id=i;
lm=2*id-mx;
}
maxn=maxf(maxn,2*p[i]-1);
tot[2*p[i]-1]++;
}
for(i=maxn;i>=0;i-=2)
tot[i]+=tot[i+2];
sum=0ll;
for(i=1;i<=maxn;i+=2)
sum+=tot[i];
if(sum<m)
{
printf("-1\n");
return 0;
}
i=maxn;
while(m)
{
if(m>tot[i])
{
ans=(1ll*ans*(quickpow(i,tot[i])))%mo;
m-=tot[i];
i-=2;
}
else
{
ans=(1ll*ans*(quickpow(i,m)))%mo;
break;
}
}
printf("%lld\n",ans);
return 0;
}
/*
5 3
ababa
ans:45
*/