Greater and Greater

Greater and Greater

题意:

给你一个长度为n的数组A, 和一个长度为m的数组B, 从A中找长度为 m的子串,且 子串的每一位大于等于对应的B数组的每一位, 问符合条件的子串个数。

题解

这题 \(n*m = 6*10^9\) 所以暴力肯定不行, 所以要bitset优化暴力。 可以将复杂度降到 $\frac{n * m}{32} \approx 3 * 10 ^ 8 $

题目给的一秒, 按照一般的想法肯定是过不了, 但是牛客的机子一秒可以过 \(10 ^ 9\)所以可以稳过。

下面是解题思路:

如何用bitset操作?

先举个例子:

6 3
1 4 2 8 5 7
3 2 3

第一步 将 B数组排序:

排完序的值:2 3 3
排完序的下标:2 1 3
然后开一个 bitset<M>cnt[M]
然后
for (i = 1; i <= m; i++) {
	cnt = cnt[i - 1];
	cnt.set(m - B[i].pos); // 至于这里的完整为啥要取后面的,主要是为了后面 右移方便操作。
}
这样得到的 cnt就是

cnt[0]    cnt[1]  cnt[2]  cnt[3]

000		  010	  011		111

也就是说这里 0 1的含义就是, 小于 B[i]的值 位置 (位置取反)

初始化完成也就是求答案了

如果让你写暴力你肯定是从第一位枚举, 上面说了这时 bitset优化的暴力同样也是从第一位枚举。
设一个 bitset<m>ans

A数组中第一值为:1

再B 找最后一个小于等于1 的值位置,
很显然是 0, 那么取cnt[0]
因为之前为值都取反那么现在一样,
ans.set(m -1)这里的意思我给第一位差个1
然后 ans = ans & cnt[0];
如果第 m- 1位是1 (即 第一位取反了)
那么可以得到 第一个数是合法的, 因为你找的cnt[0]就是 所有小于等于 A[1]值的位置。

 如果第一位合法 ans >>=1将 ans右移1位, 如果你这里看懂了就知道我之前为啥把位置取反了

同理, 再找 A[2] 再B 中最后一个小于 它的位置, 我们发现是排序后的第三个, 取cnt[3],
再将 ans.set(m - 1)
ans = ans & cnt[3]
如果这个时候 第 m - 2位是1 说明第二位以合法。
以此类推, 每次至要判断 ans[0]是否等于1, 是就答案加1就行。

看代码模拟几遍即懂了。

#include<bits/stdc++.h>
using namespace std;
const int N = 150007;
 
int a[N], b[N], n, m, pos[N];
 
bitset<40007> cnt[40007], ans;
 
int find(int x) {
    int l = 1, r = m;
    int an = 0;
 
    while (l <= r) {
        int mid = (l + r) / 2;
        if (b[pos[mid]] <= x) {
            an = mid;
            l = mid + 1;
        } else {
            r = mid - 1;
        }
    }
    return an;
}
 
 
int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    for (int i = 1; i <= m; i++) {
        scanf("%d", &b[i]);
        pos[i] = i;
    }
 
    sort(pos + 1, pos + m + 1, [](int x, int y) {
        return b[x] < b[y];
    });
    for (int i = 1; i <= m; i++) {
        cnt[i] = cnt[i - 1];
        cnt[i].set(m - pos[i]);
    }
 
 
    int res = 0;
    for (int i = 1; i < m; i++) {
        ans.set(i, 0);
    }
 
    for (int i = 1; i <= n; i++) {
        int p = find(a[i]);
        ans >>= 1;
        ans.set(m - 1, 1);
        ans &= cnt[p];
        res += ans[0];
    }
    printf("%d\n", res);
 
}
posted @ 2020-07-17 00:39  ccsu_zhaobo  阅读(104)  评论(0编辑  收藏  举报