2084: [Poi2010]Antisymmetry
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 596 Solved: 379
[Submit][Status][Discuss]
Description
对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作“反对称”字符串。比如00001111和010101就是反对称的,1001就不是。
现在给出一个长度为N的01字符串,求它有多少个子串是反对称的。
Input
第一行一个正整数N (N <= 500,000)。第二行一个长度为N的01字符串。
Output
一个正整数,表示反对称子串的个数。
Sample Input
8
11001011
11001011
Sample Output
7
hint
7个反对称子串分别是:01(出现两次), 10(出现两次), 0101, 1100和001011
hint
7个反对称子串分别是:01(出现两次), 10(出现两次), 0101, 1100和001011
HINT
Source
改版的Manacher,将判断条件改为两字符一个是'0'一个是'1'即可,最后用半径统计答案,莫名其妙的边界处理……
1 #include <cstdio> 2 3 const int siz = 1000005; 4 5 int n; 6 int s[siz]; 7 int r[siz]; 8 char str[siz]; 9 10 inline int min(int a, int b) 11 { 12 return a < b ? a : b; 13 } 14 15 inline bool check(int a, int b) 16 { 17 return 18 (a == 0 && b == 1) 19 || (a == 1 && b == 0) 20 || (a == 3 && b == 3); 21 } 22 23 signed main(void) 24 { 25 scanf("%d%s", &n, str + 1); 26 27 /*<--- Prework --->*/ 28 29 30 for (int i = 1; i <= n; ++i) 31 { 32 static int tot = 0; 33 s[++tot] = 3; 34 s[++tot] = str[i] - '0'; 35 } 36 37 n = 2*n + 1; 38 39 s[n] = 3; 40 s[0] = 4; 41 s[n + 1] = 4; 42 43 /*<--- Manacher --->*/ 44 45 for (int i = 1; i <= n; i += 2) 46 { 47 static int maxi = 0, id = 0; 48 49 if (i <= maxi) 50 r[i] = min(maxi - i + 1, r[2*id - i]); 51 else 52 r[i] = 1; 53 54 while (check(s[i + r[i]], s[i - r[i]])) 55 ++r[i]; 56 57 if (maxi < r[i] + i - 1) 58 maxi = r[i] + i - 1, id = i; 59 } 60 61 /*<--- Calculate --->*/ 62 63 long long ans = 0LL; 64 65 for (int i = 1; i <= n; i += 2) 66 ans += (r[i] - 1) >> 1; 67 68 printf("%lld ", ans); 69 }
@Author: YouSiki