线段树维护序列哈希。
CF213E
题意
给出两个排列 a,b,长度分别为 n,m,你需要计算有多少个 x,使得 a1+x,a2+x,…,an+x 是 b 的子序列,n≤m≤2×105。
题解
枚举 x,由于 ai 是排列,此时对应 a 的值域为 [1+x,n+x],此时我们只需要将 bi 中在这个值域内的数提取出来(不改变顺序),判断与 a1+x,a2+x,…,an+x 是否相同即可。
考虑序列相同这里用到序列哈希,对于 a1,a2,…,an,先预处理其哈希值 f,那么 a1+x,a2+x,…,an+x 哈希值为 f+x×∑i=0nbi(b 为底数),对于 b,枚举 x 时会在某种位置 删除/加入 一个数,用 线段树/平衡树 维护序列哈希即可。
CODE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #include <bits/stdc++.h> #define fi first #define se second #define ls (x<<1) #define rs (x<<1|1) #define mid ((l+r)>>1) using namespace std; typedef long long ll; const int N = 200010; typedef pair<ll,ll> pll; const int p1 = 1019260817; const int p2 = 1019260819;
const int bs = 1000; pll operator*(const pll &a,const ll &b) {return pll(a.fi * b % p1, a.se * b % p2);} pll operator*(const pll &a,const pll &b) {return pll(a.fi * b.fi % p1, a.se * b.se % p2);} pll operator+(const pll &a,const ll &b) {return pll((a.fi + b) % p1, (a.se + b) % p2);} pll operator-(const pll &a,const pll &b) {return pll((a.fi - b.fi + p1) % p1, (a.se - b.se + p2) % p2);} pll operator+(const pll &a,const pll &b) {return pll((a.fi + b.fi) % p1, (a.se + b.se) % p2);} pll pw[N], pws[N]; void init(int n) { pw[0] = pws[0] = {1, 1}; for (int i = 1; i <= n; ++i) pw[i] = pw[i - 1] * bs, pws[i] = pws[i - 1] + pw[i]; } struct dat { pll f; int len; dat() { f = {0, 0}; len = 0; } dat(const pll &_f,const int &_len) { f = _f; len = _len; } }; dat operator*(const dat &a,const dat &b) { return dat(a.f * pw[b.len] + b.f, a.len + b.len); } ostream &operator<<(ostream &out,const dat &a) { return out<<"dat{ ("<<a.f.first<<", "<<a.f.second<<"), l="<<a.len<<" } "; }
int a[N],b[N],p[N],n,m; dat D[N<<2]; void pushup(int x) {D[x]=D[ls]*D[rs];} void modify(int ps,int vl,int l=1,int r=m,int x=1) { if(l==r) { if(vl==-1) D[x]=dat(); else D[x]=dat(pll(vl,vl),1); return ; } if(ps<=mid) modify(ps,vl,l,mid,ls); else modify(ps,vl,mid+1,r,rs); pushup(x); }
int main() { scanf("%d%d",&n,&m); init(m); dat Ha; for(int i=1;i<=n;++i) scanf("%d",&a[i]),Ha=Ha*dat(pll(a[i],a[i]),1); for(int i=1;i<=m;++i) scanf("%d",&b[i]),p[b[i]]=i; for(int i=1;i<n;++i) modify(p[i],b[p[i]]); int ans=0; for(int x=0;n+x<=m;++x) { modify(p[n+x],b[p[n+x]]); if(x>0) modify(p[x],-1); if(D[1].f==(Ha.f+pws[n-1]*x)) ++ans; } printf("%d\n",ans); return 0; }
|