洛谷传送门
BZOJ传送门
题目描述
艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了。拉拉队是篮球比赛的一个看点,好的拉拉队往往能帮助球队增加士气,赢得最终的比赛。所以作为拉拉队队长的楚雨荨同学知道,帮助篮球队训练好拉拉队有多么的重要。
拉拉队的选拔工作已经结束,在雨荨和校长的挑选下, n n 位集优秀的身材、舞技于一体的美女从众多报名的女生中脱颖而出。这些女生将随着篮球队的小伙子们一起,和对手抗衡,为艾利斯顿篮球队加油助威。
一个阳光明媚的早晨,雨荨带领拉拉队的队员们开始了排练。个女生从左到右排成一行,每个人手中都举了一个写有 26 26 个小写字母中的某一个的牌子,在比赛的时候挥舞,为小伙子们呐喊、加油。
雨荨发现,如果连续的一段女生,有奇数个,并且他们手中的牌子所写的字母,从左到右和从右到左读起来一样,那么这一段女生就被称作和谐小群体。
现在雨荨想找出所有和谐小群体,并且按照女生的个数降序排序之后,前 K K 个和谐小群体的女生个数的乘积是多少。由于答案可能很大,雨荨只要你告诉她,答案除以的余数是多少就行了。
输入输出格式
输入格式:
输入为标准输入。
第一行为两个正整数 n n 和,代表的东西在题目描述中已经叙述。
接下来一行为 n n 个字符,代表从左到右女生拿的牌子上写的字母。
输出格式:
输出为标准输出。
输出一个整数,代表题目描述中所写的乘积除以的余数,如果总的和谐小群体个数小于K,输出一个整数 −1 − 1 。
输入输出样例
输入样例#1:
5 3
ababa
输出样例#1:
45
说明
样例说明
和谐小群体女生所拿牌子上写的字母从左到右按照女生个数降序排序后为ababa
,aba
, aba
,bab
,a
,a
, a
,b
, b
,前三个长度的乘积为
45
45
。
数据范围与约定
测试点 | n | K |
---|---|---|
1 | 10 | 10 |
2-3 | 100 | 100 |
4-7 | 1,000 | 1,000 |
8 | 100,000 | = 1 |
9-11 | 100,000 | 100,000 |
12-14 | 100,000 | 1,000,000,000,000 |
15-17 | 500,000 | 1,000,000,000,000 |
18 | 1,000,000 | = 1 |
19 | 1,000,000 | 1,000,000 |
20 | 1,000,000 | 1,000,000,000,000 |
解题分析
很显然我们用 manacher m a n a c h e r 算出每个位置的最大回文直径, 然后做一个类似前缀和的操作:因为较大回文半径的回文串一定包含了更小的回文串, 所以我们从大到小累加每个回文直径的个数, 再快速幂统计答案。
特殊的是, 这道题只需要统计奇数长度的回文串, 所以我们并不需要插入其他字符, 大力 manacher m a n a c h e r 即可。
注意 K K 可能爆…
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cctype>
#include <cmath>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 1000500
#define ll long long
#define MOD 19930726
int len;
ll tot, k, ans = 1;
char dat[MX];
int buc[MX], rad[MX], cent, pos;
IN ll qpow(ll base, ll tim)
{
ll ret = 1;
for (R unsigned i = 0; i <= 31; ++i, base = base * base % MOD)
if(tim & (1 << i)) ret = ret * base % MOD;
return ret;
}
void manacher()
{
dat[0] = '*';
for (R int i = 1; i <= len; ++i)
{
if(i < pos) rad[i] = std::min(pos - i, rad[2 * cent - i]);
else rad[i] = 1;
W (dat[i - rad[i]] == dat[i + rad[i]]) ++rad[i];
if(pos < rad[i] + i) pos = rad[i] + i, cent = i;
buc[2 * rad[i] - 1]++;//记录最大回文直径
}
if(!(len % 2)) --len;//注意长度为偶数的情况
for (R int i = len; ~i; i -= 2)//累加
{
tot += buc[i];
if(tot >= k)
{
ans = ans * qpow(i, k) % MOD;
break;
}
else
{
ans = ans * qpow(i, tot) % MOD;
k -= tot;
}
}
if(tot >= k) printf("%lld", ans);
else printf("-1");
}
int main(void)
{
scanf("%d%lld", &len, &k);
scanf("%s", dat + 1);
manacher();
}