[国家集训队]拉拉队排练

题面:

洛谷

一句话题意:找前k大回文串(不要求本质不同)

题解:

  我们进行一遍manacher即可求出对于每个回文中心而言的最长回文半径。

  我们考虑求出f[i]表示回文半径为i的回文串的个数。

  那么对于一个i而言,它可以对哪些长回文半径产生贡献呢?   [1, r[i]]。(这个应该是很明显的)

  因此每次就相当于区间加1,最后统计一次,用差分维护即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define R register int
 4 #define mod 19930726
 5 #define AC 1000100
 6 #define LL long long
 7 
 8 int n, pos, maxn, cnt;
 9 int r[AC], d[AC], num[AC];
10 LL k, ans = 1;
11 char s[AC];
12 
13 void pre()
14 {
15     scanf("%d%lld", &n, &k);
16     scanf("%s", s + 1);
17 }
18 
19 void manacher()
20 {
21     s[0] = '#';
22     for(R i = 1; i <= n; i ++)
23     {
24         r[i] = maxn > i ? min(r[2 * pos - i], maxn - i + 1) : 1;
25         while(s[i - r[i]] == s[i + r[i]]) ++ r[i]; 
26         if(r[i] + i - 1 > maxn) maxn = r[i] + i - 1, pos = i;//maxn赋值错了....
27         ++ d[1], -- d[r[i] + 1];
28     }
29 }
30 
31 inline bool cmp(int a, int b){
32     return a > b;
33 }
34 
35 inline void up(LL &a, LL b)
36 {
37     a *= b;
38     if(a > mod) a %= mod;
39 }
40 
41 inline LL qpow(LL x, int have)
42 {
43     LL rnt = 1;
44     while(have)
45     {
46         if(have & 1) up(rnt, x);
47         up(x, x), have >>= 1;
48     }
49     return rnt;
50 }
51 
52 void work()
53 {
54     for(R i = 1; i <= n; i ++) d[i] += d[i - 1];
55     int t = n / 2 + 1;
56     for(R i = t; i; i --)
57     {
58         if(!d[i]) continue;
59         if(d[i] >= k) up(ans, qpow(i * 2 - 1, k)), k = 0;
60         else up(ans, qpow(i * 2 - 1, d[i])), k -= d[i];
61         if(!k) break;
62     }
63     if(k) printf("-1\n");
64     else printf("%lld\n", ans);
65 }
66 
67 int main()
68 {
69     //freopen("in.in", "r", stdin);
70     pre();
71     manacher();
72     work();
73 //    fclose(stdin);
74     return 0;
75 }
View Code

 

posted @ 2018-12-02 00:22  ww3113306  阅读(145)  评论(0编辑  收藏  举报
知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。