https://www.luogu.org/problemnew/show/P1659
题目描述艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了。拉拉队是篮球比赛的一个看点,好的拉拉队往往能帮助球队增加士气,赢得最终的比赛。所以作为拉拉队队长的楚雨荨同学知道,帮助篮球队训练好拉拉队有多么的重要。
拉拉队的选拔工作已经结束,在雨荨和校长的挑选下,n位集优秀的身材、舞技于一体的美女从众多报名的女生中脱颖而出。这些女生将随着篮球队的小伙子们一起,和对手抗衡,为艾利斯顿篮球队加油助威。
一个阳光明媚的早晨,雨荨带领拉拉队的队员们开始了排练。n个女生从左到右排成一行,每个人手中都举了一个写有26个小写字母中的某一个的牌子,在比赛的时候挥舞,为小伙子们呐喊、加油。
雨荨发现,如果连续的一段女生,有奇数个,并且他们手中的牌子所写的字母,从左到右和从右到左读起来一样,那么这一段女生就被称作和谐小群体。
现在雨荨想找出所有和谐小群体,并且按照女生的个数降序排序之后,前K个和谐小群体的女生个数的乘积是多少。由于答案可能很大,雨荨只要你告诉她,答案除以19930726的余数是多少就行了。
输入输出格式输入格式:
输入为标准输入。
第一行为两个正整数n和K,代表的东西在题目描述中已经叙述。
接下来一行为n个字符,代表从左到右女生拿的牌子上写的字母。
输出格式:
输出为标准输出。
输出一个整数,代表题目描述中所写的乘积除以19930726的余数,如果总的和谐小群体个数小于K,输出一个整数-1。
思路这是一道manacher经典例题。
由于我们只用求奇数回文串,所以中间可以不插字符。
这里给一个例子:abcba
这里是一个以c为中心长度为5的回文串。
不难发现,此串包含abcba,bcb,c的回文串,且都已c为中心。
所以我们一起使用前缀和来统计有多少个回文串。
由于数据很大,要用快速幂。
代码#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int mod=19930726,maxn=1000077;
long long len[maxn*2],n,k,a[maxn*2];
char s[maxn],st[maxn*2];
int init()
{
scanf("%d%d%s",&n,&k,s);
int l=strlen(s);
int t=0;
st[t]='$';
for(int i=0; i<l; i++)
{
st[++t]=s[i];
}
st[t+1]='*';
return t;
}
void manacher(int l)
{
long long mx=0,rd=0;
for(int i=1; i<=l; i++)
{
if(i<mx) len[i]=min(mx-i,len[2*rd-i]);
else len[i]=1;
while(st[len[i]+i]==st[i-len[i]])
len[i]++;
if(len[i]+i-1>mx)
{
mx=len[i]+i-1;
rd=i;
}
}
}
long long power(int x,int y)
{
long long t=x,b=y,ass=1;
while(t)
{
if(t%2==1) ass=ass*b%mod;
b=b*b%mod;
t>>=1;
}
return ass;
}
long long sum(int l)
{
long long mx=0,ass=1;
for(int i=1; i<=l; i++) a[len[i]*2-1]++,mx=max(mx,len[i]*2-1);
for(int i=mx-2; i>=1; i--) a[i]+=a[i+2];
while(mx>0&&k>0)
{
int x=0;
if(a[mx]<=k) x=a[mx];else x=k;
ass=ass*power(x,mx)%mod;
mx--; k-=x;
}
if(k) return -1;else return ass;
}
int main()
{
int l=init();
manacher(l);
printf("%d",sum(l));
}