[Poi2010]Antisymmetry
阿新 • • 發佈:2018-02-05
void nac const output 什麽 string 增加 while printf
Description
對於一個01字符串,如果將這個字符串0和1取反後,再將整個串反過來和原串一樣,就稱作“反對稱”字符串。比如00001111和010101就是反對稱的,1001就不是。
現在給出一個長度為N的01字符串,求它有多少個子串是反對稱的。
Input
第一行一個正整數N (N <= 500,000)。第二行一個長度為N的01字符串。
Output
一個正整數,表示反對稱子串的個數。
Sample Input
8
11001011
Sample Output
7
//7個反對稱子串分別是:01(出現兩次), 10(出現兩次), 0101, 1100和001011?
Manacher,不多說……不過,怎麽匹配呢?肯定不是直接匹配。我們將原串轉換一下,把1改為2,0不變,中間添加1,那麽我們匹配的時候就看看兩個點是否相加等於2即可
統計答案?由於反對稱子串一定是偶串,所以我們只要枚舉1所在的位置。
那麽答案是什麽?p[i]/2。為什麽?因為我們匹配的時候,是看兩個點是否相加為2,那麽匹配的兩個點要麽是1,要麽是0和2。這樣,回文半徑每增加2,答案的個數就增加了1,所以直接累加 p[i]/2 即可。
初始值為1?整除把它幹掉了……
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define inf 0x7f7f7f7f using namespace std; typedef long long ll; typedef unsigned int ui; typedef unsigned long long ull; inline int read(){ int x=0,f=1;char ch=getchar(); for (;ch<‘0‘||ch>‘9‘;ch=getchar()) if (ch==‘-‘) f=-1; for (;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) x=(x<<1)+(x<<3)+ch-‘0‘; return x*f; } inline void print(int x){ if (x>=10) print(x/10); putchar(x%10+‘0‘); } const int N=5e5; char s[N+10]; int val[N*2+10],p[N*2+10]; ll Ans; int main(){ int len=read(); scanf("%s",s+1); for (int i=1;i<=len;i++) val[i<<1]=s[i]-‘0‘?2:0,val[i<<1|1]=1; len=len<<1|1; val[1]=1,val[0]=val[len+1]=-1; int Max=0,ID=0; for (int i=1;i<=len;i++){ p[i]=Max>i?min(p[ID*2-i],Max-i):1; while (val[i+p[i]]+val[i-p[i]]==2) p[i]++; if (Max<p[i]+i-1) Max=p[ID=i]+i-1; } for (int i=1;i<=len;i+=2) Ans+=p[i]>>1; printf("%lld\n",Ans); return 0; }
[Poi2010]Antisymmetry