zoukankan      html  css  js  c++  java
  • [国家集训队]拉拉队排练(Manacher)

    传送门

    题意

    题意其实很简单,就是给你一个字符串让你求所有长度为奇数的回文串从大到小排序前k大的串的长度的乘积。

    题解

    先跑一遍 $Manacher$,由于是奇数所以直接在原串上跑即可。我们发现对于一个中心 $i$ 和其最长回文半径 $p_i$,所有以 $i$ 为中心,半径小于 $p_i$ 的串也是回文串。

    所以我们只需对每个中心最长的回文串的长度的次数+1,然后做一遍后缀和即可求出每个长度的回文串出现的次数。(当然我们只用统计奇数长度的。)

    之后从大到小枚举这些长度,如果 $当前k geq 当前回文串长度出现次数$,说明当前长度的回文串一定都在前k个里,设当前长度为len,答案直接加上 $len^{len出现的次数}$, k减去len出现的次数。

    否则当前长度的串只有k个符合题目要求,答案只能加上 $len^k$,k直接置位0。

    如果所有长度都遍历完了k的值还大于0,则输出-1。

     1 #include <iostream>
     2 #include <cstdio>
     3 using namespace std;
     4 typedef long long ll;
     5 const int N = 2000010;
     6 const int mod = 19930726;
     7 ll n, k;
     8 char s[2000010], ss[1000010];
     9 int top;
    10 ll p[2000010], cnt[2000010], sum, ans = 1;
    11 ll ksm(ll a, ll b) {
    12     ll ret = 1;
    13     while (b) {
    14         if (b & 1) ret = (ret * a) % mod;
    15         a = (a * a) % mod;
    16         b >>= 1;
    17     }
    18     return ret;
    19 }
    20 void Manacher() {
    21     ll mx = 0, id = 0;
    22     for (int i = 1; i <= top; i++) {
    23         p[i] = ((mx > i) ? min(mx - i, p[id * 2 - i]) : 1);
    24         while (s[i + p[i]] == s[i - p[i]]) p[i]++;
    25         if (i + p[i] > mx) {
    26             mx = i + p[i];
    27             id = i;
    28         }
    29         cnt[p[i] - 1]++;
    30     }
    31 }
    32 int main() {
    33     cin >> n >> k;
    34     scanf("%s", ss + 1);
    35     s[++top] = '$';
    36     for (int i = 1; i <= n; i++) {
    37         s[++top] = '#';
    38         s[++top] = ss[i];
    39     }
    40     s[++top] = '#';
    41     Manacher();
    42     for (int i = n; i >= 1; i--) {
    43         if (i % 2) {
    44             sum += cnt[i];
    45             if (sum <= k) {
    46                 ans = (ans * ksm(i, sum)) % mod;
    47                 k -= sum;
    48             } else {
    49                 ans = (ans * ksm(i, k)) % mod;
    50                 k -= sum;
    51                 break;
    52             }
    53         }
    54     }
    55     if (k > 0) cout << -1;
    56     else cout << ans;
    57     return 0;
    58 } 
  • 相关阅读:
    ActiveReports中如何在后台导出运行时绑定数据源报表
    ActiveReports中如何控制页面的记录数
    WordPress建站固定链接问题
    Linux环境下使用g++编译C++
    Git diff结果显示分析
    VTK使用过程中遇到的问题
    右值引用、移动语义和完美转发(下)
    右值引用、移动语义和完美转发(中)
    右值引用、移动语义和完美转发(上)
    new和malloc的联系与区别(下)
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/12558189.html
Copyright © 2011-2022 走看看