SPOJ Antisymmetry 回文串manacher

来源:互联网 发布:数据恢复精灵的注册码 编辑:程序博客网 时间:2024/06/07 18:36

Antisymmetry

Byteasar studies certain strings of zeroes and ones. Let S be such a string. By Sr we will denote the reversed (i.e., “read backwards”) string S, and by SI we will denote the string obtained from S by changing all the zeroes to ones and ones to zeroes.

Byteasar is interested in antisymmetry, while all things symmetric bore him. Antisymmetry however is not a mere lack of symmetry. We will say that a (nonempty) string S is antisymmetric if, for every position i in S, the i-th last character is different than the i-th (first) character. In particular, a string S consisting of zeroes and ones is antisymmetric if and only if S=SIr. For example, the strings 00001111 and 010101 are antisymmetric, while 1001 is not.

In a given string consisting of zeroes and ones we would like to determine the number of contiguous nonempty antisymmetric fragments. Different fragments corresponding to the same substrings should be counted multiple times.

Input

The first line of the standard input contains an integer N (1 <= N <= 500000) that denotes the length of the string. The second line gives a string of 0 and/or 1 of length N. There are no spaces in the string.

Output

The first and only line of the standard output should contain a single integer, namely the number of contiguous (non empty) fragments of the given string that are antisymmetric.

Example

For the input data:

8
11001011
the correct result is:

7
Antisymmetric fragments are: 01 (occurs twice), 10 (also twice), 0101, 1100, and 001011.

题目链接

题意:一个只含有0、1的字符串,这个字符串在将0变成1,将1变成0后进行反转,如果和原来的字符串完全相同,则称之为反对称字符串,现在给你一个0、1的字符串,让你求有多少个子字符串为反对称字符串。

解题思路:因为经过0变1,1变0和反转两个操作,所以如果这个字符串的长度为奇数,它是不可能成为反对称字符串的(因为最中间那个肯定不相同),对于一个长度为偶数且为l的字符串,我们只要让它的第i个字符与第l-i+1(也就是倒数第i个字符)不相同即可,因此我们可以用manacher来解决这个问题。

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#define maxn 500005using namespace std;typedef long long ll;ll n,ans,f[maxn*2],pos;char st[maxn],st1[maxn*2];bool fuhe(ll a,ll b){    if((st1[a]=='0'&&st1[b]=='1')||(st1[a]=='1'&&st1[b]=='0')||(st1[a]=='#'&&st1[b]=='#'))  return true;    return false;}int main(){    scanf("%lld",&n);    scanf("%s",st);    st1[0]='*';    for(ll i=0;i<n;i++){        st1[2*i+2]=st[i];        st1[2*i+1]='#';    }    st1[2*n+1]='#';    ll l=strlen(st1),maxright=0;    for(ll i=1;i<l;i++){        if(maxright>i)  f[i]=min(f[2*pos-i],maxright-i);        else f[i]=1;        while(i-f[i]>=1&&i+f[i]<=l&&fuhe(i+f[i],i-f[i]))    f[i]++;          if(st1[i]=='#'&&i>1&&i<l){  //只有以#为中心的字符串才为偶数长             ans+=f[i]/2;            if(i+f[i]>maxright){                maxright=i+f[i];                pos=i;            }        }    }    printf("%lld\n",ans);    return 0;}
0 0