洛谷_1659 拉拉队排练(Manachar)

拉拉队排练

题目链接:https://www.luogu.com.cn/problem/P1659

题解:

利用Manachar算法求出字符串中第 i i i个字母为中心的回文串的半径 p i p_i pi,求出所有 p i p_i pi和,若大于 k k k,则无解。
否则利用快速幂计算前k个长度的成绩即可。

#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define eps 1e-6
   
using namespace std;
typedef long long LL;   
typedef pair<int, int> P;
const int maxn = 1002000;
const int mod = 19930726;
char str[maxn], str1[maxn*2];
int p[maxn*2], b[maxn];
LL Pow(LL a, LL b);
int Insert(char str[]);

int main()
{
    int n, len, mx, id, i, j;
    LL k, sum;
    scanf("%d %lld %s", &n, &k, str);
    len = Insert(str);
    mx = 0;
    for(i=1;i<len;i++){
        p[i] = mx>i?min(mx-i, p[2*id-i]):1;
        while(str1[i-p[i]] == str1[i+p[i]])p[i]++;
        if(i+p[i]>mx){
            mx = i+p[i];
            id = i;
        }
        if(isalpha(str1[i])){
            sum += (p[i])/2;
            b[p[i]-1]++;
        }
    }
    if(k > sum)printf("-1\n");
    else{
        LL ans = 1;
        for(i=n;i>=1;i--){
            
            b[i] += b[i+1];
            if(i%2 == 0)continue;
            if(k > b[i]){
                ans = ans*Pow(i, b[i])%mod;
                k -= b[i];
            }
            else{
                ans = ans *Pow(i, k)%mod;
                break;
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}

int Insert(char str[])
{
    int i, j=2;
    str1[0] = '!';
    str1[1] = '#';
    for(i=0;str[i];i++){
        str1[j] = str[i];
        str1[j+1] = '#';
        j+=2;
    }
    str1[j] = 0;
    return j;
}

LL Pow(LL a, LL b)
{
    LL n = 1;
    while(b)
    {
        if(b&1)n = n*a%mod;
        a = a*a%mod;
        b/=2;
    }
    return n;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值