CF 213E Two Permutations(线段树,hash)

转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove 

尼玛,这是研究题解都研究了半天,巨弱啊

开始看成是连续的子串,然后就直接HASH枚举了一下,果断跪。

然后就想到可以不连续,然后就没啥想法了。

最终还是用线段树去维护一个HASH

按数字顺序,依次插入线段树,然后对整个区间求HASH。其实就是比较的是整个区间的相对顺序是否 和A串一致。

比如说A串中是1 3 2

那么将第二个串的1 2 3插入到线段树中后,如果其相对顺序也是1 3 2 那么HASH值肯定一样。

但是注意的是,如果继续插入4,肯定要把1删掉,那么这时候的HASH值是2,3,4的组合HASH。

可以发现每一权都加了1,那么这个预处理一下就可以了

HASH我还是习惯性地两次HASH,减少错误的可能性


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
#define lson step<<1
#define rson step<<1|1
#define N 200005
#define H1 1000003LL
#define H2 999997LL
#define LL long long 
using namespace std;
struct Seg_tree{
    int left,right;
    int size;
    LL hash1,hash2;
}L[N<<2];
int n,m;
int a[N],b[N],p[N];
LL fact_2[N]={1},fact_1[N]={1};
LL hash_a_1,hash_a_2;
LL sum_1,sum_2;
void bulid(int step,int l,int r){
    L[step].left=l;
    L[step].right=r;
    L[step].hash1=L[step].hash2=0LL;
    L[step].size=0;
    if(l==r) return;
    int m=(l+r)>>1;
    bulid(lson,l,m);
    bulid(rson,m+1,r);
}
void push_up(int step){
    L[step].size=L[lson].size+L[rson].size;
    L[step].hash1=L[lson].hash1*fact_1[L[rson].size]+L[rson].hash1;
    L[step].hash2=L[lson].hash2*fact_2[L[rson].size]+L[rson].hash2;
}
void update(int step,int pos,int val,int k){
    if(L[step].left==pos&&L[step].right==pos){
        L[step].size+=k;
        L[step].hash1+=k*val;
        L[step].hash2+=k*val;
        return ;
    }
    int m=(L[step].left+L[step].right)>>1;
    if(pos<=m) update(lson,pos,val,k);
    else update(rson,pos,val,k);
    push_up(step);
}
int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        hash_a_1=hash_a_2=0;
        sum_1=sum_2=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            hash_a_1=hash_a_1*H1+a[i];
            hash_a_2=hash_a_2*H2+a[i];
            sum_1+=fact_1[i-1];
            sum_2+=fact_2[i-1];
            fact_1[i]=fact_1[i-1]*H1;
            fact_2[i]=fact_2[i-1]*H2;
        }
        for(int i=1;i<=m;i++){
            scanf("%d",&b[i]);
            p[b[i]]=i;
        }
        int ans=0;
        bulid(1,1,m);
        for(int i=1;i<=m;i++){
            update(1,p[i],i,1);
            if(i>n) update(1,p[i-n],i-n,-1);
            int d=i-n;
            if(d>=0&&L[1].hash1==d*sum_1+hash_a_1&&L[1].hash2==d*sum_2+hash_a_2)
                ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值