[国家集训队]拉拉队排练 P1659拉拉队排练
题目描述
艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了。拉拉队是篮球比赛的一个看点,好的拉拉队往往能帮助球队增加士气,赢得最终的比赛。所以作为拉拉队队长的楚雨荨同学知道,帮助篮球队训练好拉拉队有多么的重要。
拉拉队的选拔工作已经结束,在雨荨和校长的挑选下,n位集优秀的身材、舞技于一体的美女从众多报名的女生中脱颖而出。这些女生将随着篮球队的小伙子们一起,和对手抗衡,为艾利斯顿篮球队加油助威。
一个阳光明媚的早晨,雨荨带领拉拉队的队员们开始了排练。n个女生从左到右排成一行,每个人手中都举了一个写有26个小写字母中的某一个的牌子,在比赛的时候挥舞,为小伙子们呐喊、加油。
雨荨发现,如果连续的一段女生,有奇数个,并且他们手中的牌子所写的字母,从左到右和从右到左读起来一样,那么这一段女生就被称作和谐小群体。
现在雨荨想找出所有和谐小群体,并且按照女生的个数降序排序之后,前K个和谐小群体的女生个数的乘积是多少。由于答案可能很大,雨荨只要你告诉她,答案除以19930726的余数是多少就行了。
输入格式
输入为标准输入。
第一行为两个正整数n和K,代表的东西在题目描述中已经叙述。
接下来一行为n个字符,代表从左到右女生拿的牌子上写的字母。
输出格式
输出为标准输出。
输出一个整数,代表题目描述中所写的乘积除以19930726的余数,如果总的和谐小群体个数小于K,输出一个整数-1。
样例 #1
样例输入 #1
5 3
ababa
样例输出 #1
45
提示
样例说明
和谐小群体女生所拿牌子上写的字母从左到右按照女生个数降序排序后为ababa, aba, aba, bab, a, a, a, b, b,前三个长度的乘积为 。
数据范围与约定
| 测试点 | 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 |
分析:
可以理解为跑一遍马拉车之后再开始乱搞。首先,马拉车求的是每个回文中心的最长回文子串,所以如果这个串的长度为9,那么7,5,3,1的长度是没有算在内的,这个题是说所有的回文子串,所以还需要算上不是最长的回文子串,这里有一个巧妙的设计,就是先设桶,然后先把最长的加进去,如果长度为9,那么7、5、3、1也算在内,只要在最后算的时候把9的数量加到7上去,算完7之后再把这个这个数量加到5上去,这样就很方便的算上的所有的长度。本题需要快速幂,记得模数。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005;
const int mod = 19930726;
int p[N << 1];
char a[N], ma[N << 1];
int vis[N];
long long binpow(long long a, long long b) { // 非递归
// if(b==0)return 1;
long long res = 1;
while (b > 0) {
if (b & 1) res = res * a % mod; // b&1:取第一位,如果是1说明需要,0说明不需要
a = a * a % mod;
b >>= 1; // 右移,1011 -> 101
}
return res;
}
void manacher(char s[], int len) {
int k = 0;
ma[k++] = '$';
ma[k++] = '#';
for (int i = 0; i < len; i++) {
ma[k++] = s[i];
ma[k++] = '#';
}
ma[k] = '&';
int mr = 0, c = 0;
for (int i = 0; i < k; i++) {
if (i < mr) {
p[i] = min(p[(c << 1) - i], p[c] + c - i);
} else {
p[i] = 1;
}
while (ma[p[i] + i] == ma[i - p[i]])
p[i]++;
if (mr < p[i] + i) {
mr = p[i] + i;
c = i;
}
if (p[i] - 1 > 0 && (p[i] - 1) & 1) {
vis[p[i] - 1]++;
}
}
}
signed main() {
int n, k;
cin >> n >> k;
cin >> a;
manacher(a, n);
int ans = 1;
int sum = 0;
for (int i = N; i >= 1; i--) {//一个一个乘,一个一个减下去
if (i % 2 == 0) continue;
sum += vis[i];
if (k >= sum) {
ans = ans * binpow(i, sum) % mod;
k -= sum;
} else {
ans = ans * binpow(i, k) % mod;
k = 0;
break;
}
}
if (k == 0)
cout << ans;
else {
cout << "-1";
}
}
文章描述了一种计算拉拉队中和谐小群体的方法,即找到所有奇数长度且正读反读相同的子序列。通过马拉车算法找到所有回文子串,然后使用快速幂计算指定数量的最小子串乘积。该问题涉及字符串处理和数学算法的应用。
2009

被折叠的 条评论
为什么被折叠?



