1 /*
2 线段树 + hash:
3 首先我们可以知道A序列是1~n的排列,那么我们可以先在B序列中把1~n的排列找出来,看其相对位置是否与A相同(hash可做),相同即表明存在一个d满足条件。
4 以此类推,我们接下来可以把B中 2~ n + 1的排列找出来,如果其每位-1后相对顺序还是与A序列一致,即存在d-1也满足。。。
5 线段树中保存一个长度为n的序列的hash。具体看代码
6 */
7 #include <bits/stdc++.h>
8
9 using namespace std;
10
11 #define lson l, m ,rt<<1
12 #define rson m + 1, r, rt <<1|1
13 const int maxn = 2e5 + 5;
14 const int M = 10007;//hash底数
15 typedef long long ll;
16 int pw[maxn], s, h;
17 int n, m;
18
19 int hash[maxn << 2],sz[maxn << 2];
20 void pushUp(int rt){
21 hash[rt] = hash[rt<<1] * pw[sz[rt<<1|1]] + hash[rt<<1|1];
22 sz[rt] = sz[rt<<1] + sz[rt<<1|1];
23 }
24 void update(int p, int val, int tag, int l, int r, int rt){
25 if (l == r){
26 hash[rt] += tag * val;
27 sz[rt] += tag;
28 return ;
29 }
30 int m = (l + r) >> 1;
31 if (p <= m) update(p, val, tag, lson);
32 else update(p, val, tag, rson);
33 pushUp(rt);
34 }
35 int pos[maxn];
36 int main(){
37 int x;
38 while (~scanf("%d%d", &n, &m)){
39 pw[0] = 1;
40 h = s = 0;
41 for (int i = 1; i <= n; ++i){
42 scanf("%d", &x);
43 h = h * M + x;
44 pw[i] = pw[i - 1] * M;//M的i次方
45 s += pw[i - 1];//1 ~n的排列的hash转化成 2 ~ n + 1的hash需要+s.......自己算算
46 }
47 for (int i = 1; i <= m; ++i){
48 scanf("%d", &x);
49 pos[x] = i;
50 }
51 memset(hash, 0, sizeof(hash));
52 memset(sz, 0, sizeof(sz));
53 int ans = 0;
54 for (int i = 1; i <= m; ++i){
55 update(pos[i], i, 1, 1, m, 1);
56 if (i >= n){
57 if ((hash[1] - (s * (i - n)) == h))
58 ans++;
59 update(pos[i - n + 1], i - n + 1, -1, 1, m, 1);
60 }
61 }
62 printf("%d\n", ans);
63 }
64 return 0;
65 }