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;
}

 

转载于:https://www.cnblogs.com/kafuuchino/p/9605805.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值