P1659 [国家集训队] 拉拉队排练 - 洛谷
这题需要求前k大的回文子串的长度的乘积。因为n的大小为1e6 ,所以我们只能使用manacher 线性的来找到所有的回文子串。 其中长度大的回文子串可以包含小的回文子串,所以其实我们只需要知道以每一个位置为回文中心的回文子串长度即可。最后只用快速幂来求解。
string s,s1;
int n,k;
const int N = 2e6+10;
int h[N];
void change(){
s1+='?';
for (int i=1;i<=n;i++){
s1+='#';
s1+=s[i];
}
s1+='#';
n=n*2+2;
}//mancacher 预处理
int mp[N];
void manachar(){
int mid=0,r=0;
for (int i=1;i<=n;i++){
if(i<r){
h[i]=min(h[2*mid-i],r-i);
}
else {
h[i]=1;
}
while(s1[i+h[i]]==s1[i-h[i]]){
h[i]++;
}
if(i+h[i]>r){
r=i+h[i];
mid=i;
}
if((h[i]-1)%2==1){
mp[(h[i]-1)]++;
}//如果长度是奇数,就使用桶存起来
}
}
signed main()
{
IOS
//........................./
cin>>n>>k;
cin>>s;
s=" "+s;
int len = n;
change();
manachar();
int ans=1;
int sum=0;
for (int i=len;i>=1;i--){
if((i&1)){
sum+=mp[i];//重点是这里,更大的奇数回文子串是可以包含小的回文子串的。
if(k>sum){
ans=(ans*qmi(i,sum))%mod;
k-=sum;
}
else {
ans=(ans*qmi(i,k))%mod;
k=0;
break;
}
}
}
if(k>0){
cout<<-1<<endl;
}
else {
cout<<ans%mod<<endl;
}
}