题解 P1659 【[国家集训队]拉拉队排练】
XUCHENGHUI · · 题解
这道题是Manacher马拉车算法的一道题目。我们可以用马拉车算法求出最长的回文子串。马拉车算法是一种优秀的算法,它可以线性复杂度求出回文子串。我们利用p[i]表示以i为回文子串中心的最大子串长度。我们可以以 p[i]=mx>i?min(mx-i,p[id*2-i]):1;求出p数组。 其中mx表示能匹配到的最右边的坐标,id表示当前匹配中心。 由于本题的数据范围,我们需要用到前缀和和快速幂优化,我会在程序里讲解
#include<bits/stdc++.h>
#define ll long long
#define md 19930726
using namespace std;
ll n,m,k,p[5000005],mx,id,tot[1000005],ans=1;
string s,t;
ll read(){
char c;ll x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
void manacher(){
t="@#"; //这题也可以不插入'#'
for(ll i=0;i<n;i++){
t.push_back(s[i]);
t.push_back('#');
}
for(ll i=1;i<t.size();i++){
p[i]=mx>i?min(p[id*2-i],mx-i):1;
while(t[i+p[i]]==t[i-p[i]]) p[i]++;
if(mx<i+p[i]){
mx=i+p[i];id=i;
}
}
}
ll pows(ll a,ll b){
ll base=1;
while(b){
if(b&1) base=base*a%md;
a=a*a%md;
b/=2;
}
return base;
}
int main()
{
n=read();k=read();
cin>>s;
manacher();
for(ll i=1;i<t.size();i++){
if(t[i]=='#') continue;
/*for(ll j=1;j<=p[i];j++) if(j%2==1) tot[j]++;*/ //如果用for会超时
tot[p[i]-1]++;
}
for(int i=n;i>=1;i--)
if(i%2==1) tot[i]+=tot[i+2]; //前缀和优化,因为若其长度为l,那么长度为l-2,l-4……都行
for(ll i=n;i>=1;i--){
if(!tot[i]) continue;
if(k-tot[i]>=0){
k-=tot[i];ans=(ans*pows(i,tot[i]))%md; //快速幂求解答案,不用一个一个乘
}
else{
ans=(ans*pows(i,k))%md;break;
}
}
printf("%lld",ans%md);
return 0;
}