zoukankan      html  css  js  c++  java
  • BZOJ 2084: [Poi2010]Antisymmetry [Manacher]

    2084: [Poi2010]Antisymmetry

    Time Limit: 10 Sec  Memory Limit: 259 MB
    Submit: 609  Solved: 387
    [Submit][Status][Discuss]

    Description

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

    Input

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

    Output

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


    重新定义一个相等:(a=='#'&&b=='#')||((a^b)==1) 然后就是裸题啊

    注意:

    显然答案反对称只可能长度为偶数,这个地方r[i]=i<p?min(p-i+1,r[2*a-i]):0要用0!!!因为如果i是1的话它本身就不能成为回文串,所以用0然后回文扩展的时候会判断cmp(s[i],s[i])

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N=1e6+5;
    typedef long long ll;
    int n;
    char s[N],a[N];
    int r[N];
    void iniStr(char s[]){
        for(int i=1;i<=n;i++)
            a[(i<<1)-1]='#',a[i<<1]=s[i]-'0';
        a[(n<<1)+1]='#';
        a[0]='@';a[(n<<1)+2]='$';
    }
    ll ans;
    inline bool cmp(char a,char b){
        return (a=='#'&&b=='#')||((a^b)==1);
    }
    void Manacher(char s[],int n){
        int p=0,a;
        for(int i=1;i<=n;i++){
            r[i]=i<p?min(p-i+1,r[2*a-i]):0;
            while(cmp(s[i-r[i]],s[i+r[i]])) r[i]++;
            if(i+r[i]-1>p) p=i+r[i]-1,a=i;
            ans+=r[i]>>1;
            //printf("r %d %d
    ",i,r[i]);
        }
    }
    int main(){
        freopen("in","r",stdin);
        scanf("%d",&n);
        scanf("%s",s+1);
        iniStr(s);
        Manacher(a,n<<1|1);
        printf("%lld",ans);
    }
  • 相关阅读:
    450. K组翻转链表
    6. 合并排序数组 II
    64. 合并排序数组
    165. 合并两个排序链表
    103. 带环链表 II
    102. 带环链表
    [web安全原理]PHP命令执行漏洞基础
    [原题复现]-HITCON 2016 WEB《babytrick》[反序列化]
    《将博客搬至CSDN》
    PHP反序列化漏洞-CVE-2016-7124(绕过__wakeup)复现
  • 原文地址:https://www.cnblogs.com/candy99/p/6395439.html
Copyright © 2011-2022 走看看