zoukankan      html  css  js  c++  java
  • 反对称 Antisymmetry (manacher)(hash+二分)

    对于一个 0/1 字符串,如果将这个字符串 0 和 1 取反后,再将整个串反过来和原串一样,就称作「反对称」字符串。比如 00001111 和 010101 就是反对称的,而 1001 就不是。
    现在给出一个长度为 n的 0/1字符串,求它有多少个子串是反对称的,注意这里相同的子串出现在不同的位置会被重复计算。


    这道题有两种做法

    1:用hash加快判断,二分长度

    2:用manacher的变形,改变判断条件

    hash就不讲了

    直接上代码:

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #define base 10000000007
    #define min(a,b) (a) > (b) ? (b) : (a)
    using namespace std;
    inline long long rd(){
        long long x=0,f=1;
        char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
        return x*f;
    }
    inline void write(long long x){
        if(x<0) putchar('-'),x=-x;
        if(x>9) write(x/10);
        putchar(x%10+'0');
        return ;
    }
    long long n;
    char a[1000006],s[1000006];
    long long x[1000006],y[1000006];
    long long po[1000006];
    inline bool check(long long h,long long v){
        if(v-h-1<0&&v==(n/2)||v+h+2>n+1&&v+1==(n/2)+1) return 0;
        long long sum1=x[v]-x[v-h-1]*po[h+1];
        long long sum2=y[v+1]-y[v+h+2]*po[h+1];
        //cout<<h<<" "<<sum1<<" "<<sum2<<endl; 
        return (sum1==sum2);
    }
    int main(){
        po[0]=1;
        for(long long i=1;i<=500006;i++) po[i]=po[i-1]*base;
        n=rd();
        scanf("%s",a+1);
        for(long long i=1;i<=n;i++){
            s[i]=a[i]-'0';
            x[i]=x[i-1]*base+s[i]+1;
        }
        for(long long i=n;i>=1;i--) y[i]=y[i+1]*base+(s[i]^1)+1;
        long long ans=0;
        for(long long i=1;i<n;i++){
            if(s[i]!=s[i+1]) ans++;
            else continue;
            long long set=0;
            long long l=0,r=min(i,n-i);
            while(l<=r){
                long long mid=(l+r)/2;
                if(check(mid,i)){
                    l=mid+1;
                    set=mid;
                }
                else r=mid-1;
            }
            ans+=set;
        }
        write(ans);
        return 0;
    }

    然后来看如何改manacher

    manacher是一种线性算法,用来求最长回文子串。不会的看这里:https://www.cnblogs.com/WWHHTT/p/10460258.html

    然后改的时候将会问的判断条件改为一个0一个1对应,最后在将所有的中心位于#的p值除以二再相加即可 (因为反对称的字符串长度必须为偶数)

    下面给出代码:

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    using namespace std;
    inline long long rd(){
        long long x=0,f=1;
        char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
        return x*f;
    }
    inline void write(long long x){
        if(x<0) putchar('-');
        if(x>9) write(x/10);
        putchar(x%10+'0');
        return ;
    }
    char s[1000006];
    char c[2000006];
    long long n;
    long long p[2000006];
    int main(){
        n=rd();
        scanf("%s",s+1);
        c[0]='$';
        for(long long i=1;i<=n;i++){
            c[i*2-1]='#';
            c[i*2]=s[i];
        }
        c[2*n+1]='#';
        long long mx=0,id=0;
        long long ans=0;
        for(long long i=1;i<=2*n;i+=2){
            if(mx>i) p[i]=min(p[2*id-i],mx-i);
            else p[i]=1;
            while((c[i+p[i]]==c[i-p[i]]&&c[i-p[i]]=='#')||(c[i+p[i]]=='0'&&c[i-p[i]]=='1')||(c[i-p[i]]=='0'&&c[i+p[i]]=='1')) p[i]++;
            if(i+p[i]>mx) mx=i+p[i],id=i;
            if(i%2) ans+=p[i]>>1;
        }
        /*for(long long i=1;i<=2*n;i++){
            cout<<c[i]<<" ";
        }
        cout<<endl;
        for(long long i=1;i<=2*n;i++){
            cout<<p[i]<<" ";
        }*/
        write(ans);
        return 0;
    }
  • 相关阅读:
    最新的Zynq资料整理
    异步FIFO的FPGA实现
    Mac 下安装PHP遇到的问题
    php 实现推技术comet(转)
    高性能分布式内存队列系统beanstalkd(转)
    应对Memcached缓存失效,导致高并发查询DB的四种思路(l转)
    memcache 缓存失效问题(转)
    PHP.ini文件读取不到
    PHP5中魔术方法
    python mysql 单引号字符串过滤
  • 原文地址:https://www.cnblogs.com/WWHHTT/p/10460262.html
Copyright © 2011-2022 走看看