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