2020牛客多校第二场 G Greater and Greater

题目
2020牛客多校第二场 G Greater and Greater_第1张图片
给出两个序列,求出第二个序列在第一个序列中能够匹配的次数,匹配是指每个位置都小于等于第一个序列的相应位置
我还以为是kmp魔改…
从样例来讲,我们先求出 m m m串中每个位置与 n n n串中每个位置的相对大小,为1则表示符合,为0表示不符合

1 4 2 8 5 7
2 3 3

那么相对于第二个串2,3,3来说,相对大小就是

(2) 0 1 1 1 1 1
(3) 0 1 0 1 1 1
(3) 0 1 0 1 1 1

我们假设可以匹配成功的位置起始点是 p o s pos pos,那么就需要要求从第1个点的 p o s pos pos到第 m m m个点的 p o s + m − 1 pos+m-1 pos+m1全为一,才可以,为了方便看,我们把每个串都向左平移一下,使得同一起始点的都在同一列中,那就是
2020牛客多校第二场 G Greater and Greater_第2张图片
这个时候,所有在同一列的都是同一个起始点,如果这个起始点所有位置都是1,则表示可以选,全都是1的判断,很明显可以用与运算来实现,可以采用 b i t s e t bitset bitset来操作
大致如下

    sort(a + 1, a + n + 1, comp);
    sort(b + 1, b + m + 1, comp);
    res.set();// 全为1
    tmp.reset();// 全为 0
    for(int i = 1, j = 1; i <= m; ++ i) {
        while(j <= n && a[j].fi >= b[i].fi) {//找出所有大于当前的下标
            tmp.set(a[j ++].se);// 标记这个下标
        }
        res &= (tmp << (m - b[i].se));
    }
    cout << res.count() << endl;// 计算为1的数目

我们首先给两个数组都排个序从大到小,1同时记录下原本的位置,然后我们从大大小求出每一个大于 b i b_i bi的位置的下标,由于b数组是从大到小排列,那么前面计算出来大于的数字,肯定可以大于后面,可以重复利用,

由于bitset的储存是从小到大(从右向左),所以上图中向右移动实际上就是bitset向左移
最后与完直接计算剩下的1的数目就可以了

pii a[maxn], b[maxm];
bitset<maxn> res, tmp;
bool comp (const pii& aa, const pii& bb) {
    return aa.fi > bb.fi;
}
void solve (int& kase) {
    int n, m; cin >> n >> m;
    rep(i,1,n) {
        a[i] = MP(read(), i);
    }
    rep(i,1,m) {
        b[i] = MP(read(), i);
    }
    sort(a + 1, a + n + 1, comp);
    sort(b + 1, b + m + 1, comp);
    res.set();
    tmp.reset();
    for(int i = 1, j = 1; i <= m; ++ i) {
        while(j <= n && a[j].fi >= b[i].fi) {
            tmp.set(a[j ++].se);
        }
        res &= (tmp << (m - b[i].se));
    }
    cout << res.count() << endl;
}

你可能感兴趣的:(多校)