Codeforces 213E Two Permutations

题目链接

https://codeforces.com/contest/213/problem/E

题目大意

给你一个 1 ~ N的排列 A 和一个 1 ~ M 的排列 B ( N <= M )

问有多少个 d 可以使得排列 A 的每个数 + d 后为排列 B 的子序列

解题思路

权值线段树 + hash

只要满足每个 a[i] + d 在 A 中的相对位置和在 B 中的相对位置相同即可

也就是判断 B 中[1~N]、[2~N+1] ... [M - N + 1~ M]与A中[1, N] 的相对位置是否相同

于是我们先可以定义 pos[i] 表示 i 这个数在 B 中的位置(pos[ b[ i ] ] = i)

要判断相对位置是否相同,我们可以通过 hash 来操作

具体是用线段树维护 1 ~ M 的区间, 第i个区间表示 B 数组第i个位置的数是多少

然后简单来说就是再把这些位置的值提取出来计算hash值是否会和A的hash值相同

(细节看代码)

AC_Coder

#include<bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define int long long
#define ull unsigned long long
using namespace std; 
const int N = 2e5 + 10;
const int P = 13331;
const int mod = 999998639;
ull power[N];
int a[N] , b[N] , pos[N];
struct Seg_ment{
    ull pre , tot;
    int l , r;
}tree[N << 2];
void push_up(int id)
{
    tree[id].tot = tree[id << 1].tot + tree[id << 1 | 1].tot;
    tree[id].pre = (tree[id << 1].pre * power[tree[id << 1 | 1].tot] + tree[id << 1 | 1].pre) % mod;    
}
void build(int l , int r , int id)
{
    tree[id].l = l , tree[id].r = r;
    tree[id].pre = 0;
    if(l == r)
        return ;
    int mid = l + r >> 1;
    build(l , mid , id << 1);
    build(mid + 1 , r , id << 1 | 1);
    push_up(id);
}
void update(int id , int pos , int val)
{
    if(tree[id].l == tree[id].r)
    {
        if(!val) tree[id].tot -= 1;
        else tree[id].tot += 1;
        tree[id].pre = val;
        return ;        
    }
    int mid = tree[id].l + tree[id].r >> 1;
    if(pos <= mid) update(id << 1 , pos , val);
    if(pos > mid)  update(id << 1 | 1 , pos , val);
    push_up(id);
}
void init()
{
    power[0] = 1;
    rep(i , 1 , 200000)
    power[i] = power[i - 1] * P % mod;
}
signed main()
{
    init();
    int n , m , ans = 0;
    cin >> n >> m;
    build(1 , m , 1);
    ull sum = 0 , add = 0;
    rep(i , 1 , n)
        cin >> a[i] , sum = (sum * P + a[i]) % mod , add += power[i - 1] , add %= mod;
    rep(i , 1 , m)
        cin >> b[i] , pos[b[i]] = i;
    rep(i , 1 , m)
    {
        if(i > n) update(1 , pos[i - n] , 0);
        update(1 , pos[i] , i);
        int cha = i - n;
        if(cha >= 0 && tree[1].pre % mod == (sum + cha * add) % mod) ans ++ ;
    }
    cout << ans << '\n';
    return 0;
}
posted @ 2020-06-01 17:51  GsjzTle  阅读(186)  评论(0编辑  收藏  举报