2084: [Poi2010]Antisymmetry
Time Limit: 10 Sec Memory Limit: 259 MBDescription
对于一个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
#include<map> #include<cmath> #include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define ll long long #define N 1000100 int n,p[N],mx,md,len; string s; char c[N]; ll ans; inline bool ck(int x) { if(c[x+p[x]]!=c[x-p[x]]) return (c[x+p[x]]-'0')+(c[x-p[x]]-'0')==1; return c[x+p[x]]=='#'; } int main() { scanf("%d",&n); cin>>s; c[0]='&'; for(int i=0;i<=n;i++) { c[i<<1|1]='#'; c[(i<<1)+2]=s[i]; } len=(n<<1)+2; for(int i=1;i<len;i++) { p[i]=mx>i?min(p[(md<<1)-i],mx-i):1; for(;ck(i);p[i]++); if((i&1)&&p[i]+i>mx) { mx=p[i]+i; md=i; } if(i&1) ans+=(p[i]-1)>>1; } printf("%lld ",ans); return 0; }