题目传送门
题目大意
对于一个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 }