转载请注明出处,谢谢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;
}