BZOJ 2084 [Poi2010]Antisymmetry

来源:互联网 发布:js的string是不可变 编辑:程序博客网 时间:2024/05/16 18:54

2084: [Poi2010]Antisymmetry

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 446  Solved: 281
[Submit][Status][Discuss]

Description

对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作“反对称”字符串。比如00001111和010101就是反对称的,1001就不是。
现在给出一个长度为N的01字符串,求它有多少个子串是反对称的。

Input

第一行一个正整数N (N <= 500,000)。第二行一个长度为N的01字符串。

Output


一个正整数,表示反对称子串的个数。

Sample Input

8
11001011

Sample Output

7

hint
7个反对称子串分别是:01(出现两次), 10(出现两次), 0101, 1100和001011

HINT


【题目分析】

      可以想到用manacher算法对于一个节点进行前后的匹配(0=1,#=#) 然后一个算法的框架就出来了。但是要注意,刚开始的时候,r[i]要赋值成0,不能为一(有可能自己与自己的反串并不是匹配的。这样就不行)。然而自己的min函数敲错了(a,b翻了),然后半个小时的懵逼。


【代码】

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <queue>using namespace std;char s[500010],ss[1000010];int l,r[1000010];inline bool cmp(char a,char b){if ((a=='1')&&(b=='0')) return true;if ((a=='0')&&(b=='1')) return true;if ((a=='#')&&(b=='#')) return true;return false;}inline int min(int a,int b){return a>b?b:a;}int main(){scanf("%d",&l);scanf("%s",s+1);ss[1]='#';for (int i=1;i<=l;++i){ss[i*2]=s[i];ss[i*2+1]='#';}l=l*2+1;    int id=0,mx=0,ans=0;    for (int i=1;i<=l;++i){        if (mx>i) r[i]=min(r[2*id-i],mx-i);else r[i]=0;        while (cmp(ss[i-r[i]],ss[i+r[i]])) r[i]++;        if (i+r[i]>mx) mx=i+r[i],id=i;        ans+=(r[i]>>1);    }    printf("%d\n",ans);}

0 0
原创粉丝点击