bzoj 2084 Antisymmetry - Manacher

题目传送门

  需要高级权限的传送门

题目大意

  对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作“反对称”字符串。

  问给定长度为$n$的一个01串有多少个子串是反对称的。

  这个反对称子串满足回文串的对称性质,和"子结构"性质(例如$s$的$[a, b]\ (a + 2 < b)$一段是反对称的,那么$s$的$[a + 1, b - 1]$也是反对称的)

  因此我们可以用Manacher来搞这个问题。只是改一下判断的条件罢了。

  当然还有Hash + 二分的做法。

  枚举对称中心,然而二分对称长度。

  jmr同学有一个很神奇的想法,把1变成01,0变成10,然后跑Manacher,算答案的时候处理一下。

Code

 1 /**
 2  * bzoj
 3  * Problem#2084
 4  * Accepted
 5  * Time: 116ms
 6  * Memory: 3728k
 7  */
 8 #include <bits/stdc++.h>
 9 #ifndef WIN32
10 #define Auto "%lld"
11 #else
12 #define Auto "%I64d"
13 #endif
14 using namespace std;
15 typedef bool boolean;
16 
17 const int N = 5e5 + 5;
18 
19 int n;
20 int ps[N];
21 char str[N];
22 
23 inline void init() {
24     scanf("%d", &n);
25     scanf("%s", str + 1);
26 }
27 
28 long long res = 0;
29 inline void solve() {
30     int p = 0, mx = 0;
31     for (int i = 2, l, r; i <= n; i++) {
32         if (i > mx) {
33             l = i - 1, r = i; 
34             while (l > 0 && r <= n && str[l] != str[r])    l--, r++, ps[i]++;
35         } else {
36             ps[i] = min(mx - i + 1, ps[p * 2 - i]);
37             while (i - ps[i] > 1 && i + ps[i] <= n && str[i + ps[i]] != str[i - 1 - ps[i]])    ps[i]++;
38         }
39         if (i + ps[i] - 1 > mx)
40             mx = i + ps[i] - 1, p = i;
41         res += ps[i];
42 ///        cerr << i << " " << ps[i] << endl;
43     }
44     printf(Auto"\n", res);
45 }
46 
47 int main() {
48     init();
49     solve();
50     return 0;
51 }
posted @ 2018-03-30 20:52  阿波罗2003  阅读(126)  评论(0编辑  收藏  举报