[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
*/

猜你喜欢

转载自www.cnblogs.com/Rain142857/p/11791391.html
今日推荐