bzoj 3325 密码 - Manacher

题目传送门

  需要root权限的传送点

题目大意

  已知一个串,以每个字符为中心的最长回文串长,以及每两个字符中间为中心的最长回文串长。求字典序最小的这样一个串。题目保证有解。

  考虑Manacher的过程,假设当前扩展得最远的端点是$mx$。

  $mx$之内的部分可以根据回文串的性质直接判掉,当$mx$被更新的时候才会出现新的相等关系。

  由于题目给出的是最长回文串串长,所以还需要一些不等关系。

  因为字符集很小,所以直接开数组打标记就好了。

Code

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef bool boolean;
 4 
 5 const int N = 1e5 + 3, alpha = 26;
 6 
 7 int n;
 8 int ar[N], br[N];
 9 boolean ban[N][alpha];
10 char s[N];
11 
12 inline void init() {
13     scanf("%d", &n);
14     for (int i = 1; i <= n; i++)
15         scanf("%d", ar + i);
16     for (int i = 1; i < n; i++)
17         scanf("%d", br + i);
18 }
19 
20 inline void solve() {
21     int mx = 1, r, l;
22     for (int i = 1; i < n; i++) {
23         if (!s[i]) {
24             for ( ; ban[i][s[i]]; s[i]++);
25             s[i] += 'a';
26         }
27         r = i + (ar[i] >> 1), l = i - (ar[i] >> 1);
28         if (mx < r) {
29             for (mx = mx + 1 ; mx < r; mx++)
30                 s[mx] = s[2 * i - mx];
31             s[mx] = s[2 * i - mx];
32         }
33         if (l > 1)
34             ban[r + 1][s[l - 1] - 'a'] = true;
35         r = i + (br[i] >> 1), l = r - br[i] + 1;
36         if (mx < r) {
37             for (mx = mx + 1 ; mx < r; mx++)
38                 s[mx] = s[2 * i - mx + 1];
39             s[mx] = s[2 * i - mx + 1];
40         }
41         if (l > 1)
42             ban[r + 1][s[l - 1] - 'a'] = true;
43     }
44     if (!s[n]) {
45         for ( ; ban[n][s[n]]; s[n]++);
46         s[n] += 'a';
47     }
48     puts(s + 1);
49 }
50 
51 int main() {
52     init();
53     solve();
54     return 0;
55 }
posted @ 2018-03-25 10:20  阿波罗2003  阅读(157)  评论(0编辑  收藏  举报