• P3501 [POI2010]ANT-Antisymmetry


    P3501 [POI2010]ANT-Antisymmetry

    二分+hash

    注意:答案超出int范围


    ------------

    先拿一个反对称串来做栗子:010101

    我们可以发现 0101(左边右边各削掉1个),01(左边右边各削掉2个)都是反对称串

    多举几个例子,我们可以总结出一个性质:一个反对称串的所有同中心的子串都是反对称串

    ∴长为 n 的子串中的反对称子串数= n/2 

    ------------
    于是我们就可以设计算法了

    每次枚举中心点,然后二分查找反对称串的最长长度。

    对于反对称的问题,我们可以将主串正序逆序都计算一遍hash值。为了方便逆序的可以直接取反

    每次判断时将子串取出,就可以达O(1)判断


    复杂度O(nlogn)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    typedef unsigned long long ull;
    inline int min(int &a,int &b) {return a<b ?a:b;}
    const int base=19260817;
    char q[500002]; int n;
    ull h1[500002],h2[500002],fac[500002],ans; //自然溢出hash
    int main(){
        scanf("%d",&n); fac[0]=1;
        scanf("%s",q);
        for(int i=1;i<=n;++i){
            h1[i]=h1[i-1]*base+(q[i-1]=='1');
            fac[i]=fac[i-1]*base; //通用取串方法:利用fac数组取出子串hash值,其中fac[i]=base^i
        }
        for(int i=n;i>=1;--i) h2[i]=h2[i+1]*base+(q[i-1]=='0'); //逆序计算(直接取反)
        for(int i=1;i<n;++i){
            int l=0,r=min(i,n-i),mid;
            while(l<r){ //二分查找长度的一半
              mid=l+((r-l)>>1)+1;
              ull p1=h1[i+mid]-h1[i-mid]*fac[mid*2];
              ull p2=h2[i-mid+1]-h2[i+mid+1]*fac[mid*2]; //取出子串
              if(p1==p2) l=mid;
              else r=mid-1;
            }
            ans+=l;
        }cout<<ans;
        return 0;
    }
  • 相关阅读:
    Neko Performs Cat Furrier Transform CodeForces
    Neko does Maths CodeForces
    Game HDU
    HDU
    CF1155D Beautiful Array 贪心,dp
    二维差分
    B
    一维差分
    状压dpHDU
    [转载] HBase vs Cassandra:我们迁移系统的原因
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/9605805.html
Copyright © 2020-2023  润新知