zoukankan      html  css  js  c++  java
  • 【BZOJ 2160】 拉拉队排练

    【题目链接】

                https://www.lydsy.com/JudgeOnline/problem.php?id=2160

    【算法】

               先简化题意 : 给定一个字符串,求最长的k个奇回文子串长度的乘积

               先运行Manacher算法,对于每个位置i,我们知道以i为中心的回文串的最长半径为pi,那么i这个位置对半径为1-p[i]的回文串的个数都产生了1的”贡献“

               因此,我们可以用差分求出任意半径的回文串个数,然后统计答案即可,注意要用快速幂

    【代码】

               

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 1000010
    const int P = 19930726;
    typedef long long ll;
    
    int i,len,n;
    ll sum,ans,k;
    int p[MAXN];
    ll cnt[MAXN];
    char s[MAXN];
    
    inline ll power(ll a,ll n)
    {
            ll ans = 1,b = a;
            while (n)
            {
                    if (n & 1) ans = 1ll * ans * b % P;
                    n >>= 1;
                    b = 1ll * b * b % P;
            }    
            return ans;
    }
        
    inline void Manacher()
    {
            int i,pos = 0,mx = 0;
            for (i = 1; i <= len; i++)    
            {
                    if (mx > i)    p[i] = min(p[2*pos-i],mx-i);
                    else p[i] = 1;
                    while (i - p[i] >= 1 && i + p[i] <= len && s[i-p[i]] == s[i+p[i]]) p[i]++;
                    if (i + p[i] - 1 > mx)
                    {
                            mx = i + p[i] - 1;
                            pos = i;        
                    } 
            }    
    }
    
    int main() 
    {
            
            scanf("%d%lld%s",&n,&k,s+1);
            len = strlen(s+1);
            Manacher();
            for (i = 1; i <= len; i++)
            {
                    cnt[1]++;
                    cnt[p[i]+1]--;        
            }
            for (i = 1; i <= (len + 1) / 2; i++) cnt[i] += cnt[i-1];
            sum = 0; ans = 1;
            for (i = (len + 1) / 2; i >= 1; i--)
            {
                    if (cnt[i] <= 0) continue;
                    if (sum + cnt[i] < k) 
                    {
                            sum += cnt[i];
                            ans = 1ll * ans * power(2*i-1,cnt[i]) % P;
                    } else
                    {
                            ans = 1ll * ans * power(2*i-1,k-sum) % P;
                            sum += cnt[i];
                            break; 
                    }
            }
            if (sum < k) printf("-1
    ");
            else printf("%lld
    ",ans);
            
            return 0;
         
    }
  • 相关阅读:
    net8:XML的读写操作【广告控件的XML文件实例】
    挺喜欢这个网站的
    问的问题的答案~
    zookeeper集群搭建
    solrCloud简介
    e3商城_day07
    solrj实现增删查
    solr后台管理界面-数据导入
    solr后台管理界面-增删改
    s5p6818 从SD卡启动程序(制作SD启动卡)
  • 原文地址:https://www.cnblogs.com/evenbao/p/9249405.html
Copyright © 2011-2022 走看看