zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    unity-疑难杂症(一)
    unity-【UI】点击交互(一)
    asp.net core 附加进程调试、指令等
    几种定时器(timer)的区别
    ObjectDisplay 对象属性展示 Display
    IEnumerable,ICollection,IList,List 比较
    Excel等格式文件从服务端调用导出
    Azure DevOps 与VS 2019
    从 数据库表 生成 项目实体 文件
    Border样式
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/9605805.html
Copyright © 2011-2022 走看看