zoukankan      html  css  js  c++  java
  • Codeforces #442 Div2 F

    #442 Div2 F

    题意

    给出一些包含两种类型(a, b)问题的问题册,每本问题册有一些题目,每次查询某一区间,问有多少子区间中 a 问题的数量等于 b 问题的数量加 (k)

    分析

    令包含 a 问题的问题册的问题数取正值,包含 b 问题的问题册的问题数取负值,那么问题就是求有多少子区间的和为 (k)

    先求前缀和,记录 (i) 出现的次数 (cnt[i])。当计算完前缀和 (b[i-1]) 后,考虑前缀和 (b[i])(cnt[b[i]-k])为对答案的贡献。

    对于这种多个区间的询问,且区间从 ([L,R])([L,R+1])([L-1,R]) 只需要 (O(1)) 的复杂度时,可以用莫队算法去优化,离线 + 分块。

    注意,并不能直接用数组去存 (cnt) ,用 (map) 也会超时,这里可以离散化掉所有可能的值,因为我们只关心某种数字出现的次数。

    code

    #include<bits/stdc++.h>
    typedef long long ll;
    using namespace std;
    const int MAXN = 1e5 + 10;
    const int BLOCK = 300;
    int n, k;
    ll a[MAXN], b[MAXN];
    ll s[MAXN << 2];
    int x[MAXN], y[MAXN], z[MAXN];
    ll O[MAXN << 2];
    struct P {
        int l, r, b, i;
        bool operator < (const P& o) const {
            if(b != o.b) return b < o.b;
            return r < o.r;
        }
    }p[MAXN];
    ll ans[MAXN];
    int main() {
        scanf("%d%d", &n, &k);
        for(int i = 0; i < n; i++) {
            scanf("%lld", &a[i]);
            if(a[i] != 1) a[i] = -1;
        }
        for(int i = 0; i < n; i++) {
            scanf("%lld", &b[i]);
            if(!i) b[i] = a[i] * b[i];
            else b[i] = b[i - 1] + a[i] * b[i];
        }
        int c = 0;
        b[n] = 0;
        for(int i = 0; i <= n; i++) {
            s[c++] = b[i];
            s[c++] = b[i] + k;
            s[c++] = b[i] - k;
        }
        sort(s, s + c);
        int cc = unique(s, s + c) - s;
        for(int i = 0; i <= n; i++) {
            x[i] = lower_bound(s, s + cc, b[i] - k) - s;
            y[i] = lower_bound(s, s + cc, b[i]) - s;
            z[i] = lower_bound(s, s + cc, b[i] + k) - s;
        }
        int q;
        scanf("%d", &q);
        for(int i = 0; i < q; i++) {
            scanf("%d%d", &p[i].l, &p[i].r);
            p[i].l--;
            p[i].r--;
            p[i].b = p[i].l / BLOCK;
            p[i].i = i;
        }
        sort(p, p + q);
        int L = 0, R = 0;
        ll res = 0;
        for(int i = 0; i < q; i++) {
            int l = p[i].l, r = p[i].r;
            if(!i) {
                if(l == 0) O[y[n]]++;
                else O[y[l - 1]]++;
                for(int j = l; j <= r; j++) {
                    res += O[x[j]];
                    O[y[j]]++;
                }
            } else {
                for(int j = R + 1; j <= r; j++) {
                    res += O[x[j]];
                    O[y[j]]++;
                }
                for(int j = L - 1; j >= l; j--) {
                    if(j == 0) { res += O[z[n]]; O[y[n]]++; }
                    else { res += O[z[j - 1]]; O[y[j - 1]]++; }
                }
                for(int j = R; j > r; j--) {
                    O[y[j]]--;
                    res -= O[x[j]];
                }
                for(int j = L; j < l; j++) {
                    if(j == 0) { O[y[n]]--; res -= O[z[n]]; }
                    else { O[y[j - 1]]--; res -= O[z[j - 1]]; }
                }
            }
            L = l;
            R = r;
            ans[p[i].i] = res;
        }
        for(int i = 0; i < q; i++) printf("%lld
    ", ans[i]);
        return 0;
    }
    
  • 相关阅读:
    css 样式库
    css命名规则
    css选择器
    清除浏览器自带样式
    导航菜单制作
    清除浮动和样式重置快捷代码
    程序练习网站
    各种布局样式模板
    使用gulp解决外部编辑器修改Eclipse文件延迟刷新
    jQuery Validate 表单验证 — 用户注册简单应用
  • 原文地址:https://www.cnblogs.com/ftae/p/7769206.html
Copyright © 2011-2022 走看看