【题目描述】:
艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了。拉拉队是篮球比赛的一个看点,好的拉拉队往往能帮助球队增加士气,赢得最终的比赛。所以作为拉拉队队长的楚雨荨同学知道,帮助篮球队训练好拉拉队有多么的重要。拉拉队的选拔工作已经结束,在雨荨和校长的挑选下,n位集优秀的身材、舞技于一体的美女从众多报名的女生中脱颖而出。这些女生将随着篮球队的小伙子们一起,和对手抗衡,为艾利斯顿篮球队加油助威。一个阳光明媚的早晨,雨荨带领拉拉队的队员们开始了排练。n个女生从左到右排成一行,每个人手中都举了一个写有26个小写字母中的某一个的牌子,在比赛的时候挥舞,为小伙子们呐喊、加油。雨荨发现,如果连续的一段女生,有奇数个,并且他们手中的牌子所写的字母,从左到右和从右到左读起来一样,那么这一段女生就被称作和谐小群体。现在雨荨想找出所有和谐小群体,并且按照女生的个数降序排序之后,前K个和谐小群体的女生个数的乘积是多少。由于答案可能很大,雨荨只要你告诉她,答案除以19930726的余数是多少就行了。
【题目解法】:
显然我们可以用Manacher求出以i为中间点的最长回文串的长度设为p[i]
那么显然[1,2*p[i]-1]这一段区间的中所有长度为奇数的串都可以回文
所以我们开一个数组记录右端点,然后倒序扫一遍即可
复杂度为O(N)
然后Manacher都写错了TAT
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=1000005;
const long long maxmod=19930726;
int n,a[N],b[N]; long long ans,m,cnt;
int p[N]; char s[N];
inline long long getint()
{
long long x=0; char c=getchar(); bool flag=false;
while ((c!='-')&&((c<'0')||(c>'9'))) c=getchar();
if (c=='-') flag=true,c=getchar();
while ((c>='0')&&(c<='9')) x=x*10+(long long)(c-'0'),c=getchar();
if (flag) return -x; else return x;
}
void init()
{
n=getint(); m=getint();
scanf("%s",s+1);
}
void Manacher()
{
int far=0,id=0;
for (int i=1; i<=n; i++)
{
if (i<=far) p[i]=min(p[2*id-i],far-i+1);
while ((i-p[i]>=1)&&(i+p[i]<=n)&&(s[i-p[i]]==s[i+p[i]])) p[i]++;
if (i+p[i]-1>far) far=i+p[i]-1,id=i;
}
for (int i=1; i<=n; i++) cnt+=(long long)p[i],b[p[i]]++;
}
long long calc(long long x,long long y)
{
long long nowans=1;
while (y)
{
if (y%2==1) nowans=(nowans*x)%maxmod;
x=(x*x)%maxmod; y=y/2;
}
return nowans;
}
void solve()
{
if (cnt<m) {printf("-1\n"); return;}
long long now=0; ans=1;
for (int i=n; i>=1; i--)
{
now+=(long long)b[i];
ans=(ans*calc(2*i-1,min(now,m)))%maxmod;
m-=now; if (m<=0) break;
}
printf("%lld\n",ans);
}
int main()
{
init();
Manacher();
solve();
return 0;
}