• 2020 计蒜之道 线上决赛


    2020 计蒜之道 线上决赛

    C. 攀登山峰

    题目连接

    题解: 这题我比赛的时候想着如果用莫队解决这题, 想了 很久都是 (o(n ^ {1.5} * log(n))) 的算法, 就是优化不了log

    后来看了题解才知道直接用主席树, 模板主席不是可以记录区间的数的总个数嘛, 就所有总共数大于(r - l + 1) / t

    的都找一般最后在取一个最大值就好了。

    那么问题来这样复杂度可以过吗?

    可以的因为t也就是20所以最坏的情况也就是将20个区间都找了一边每次询问的复杂度就是 log(n) * t

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e5 + 7;
    
    struct hjt{
        int sum, l, r;
    } tree[40 * N];
    
    int n, q, a[N], rt[N], top = 1;
    #define m (l + r) / 2
    
    void update(int pos, int l, int r, int last, int &now) {
        now = top++;
        tree[now] = tree[last];
        tree[now].sum++;
        if (l == r) return;
        if (pos <= m) update(pos, l, m, tree[last].l, tree[now].l);
        else update(pos, m + 1, r, tree[last].r, tree[now].r);
    }
    
    int query(int k, int l, int r, int last, int now) {
        if (l == r) {
            return l;
        }
        int sum = tree[tree[now].l].sum - tree[tree[last].l].sum;
        int sum1 = tree[tree[now].r].sum - tree[tree[last].r].sum;
        int ans = -1;
        if (sum1 >= k) {
            ans = max(ans, query(k, m + 1, r, tree[last].r, tree[now].r));
        }
        if (sum >= k) {
            ans = max(ans, query(k, l, m, tree[last].l, tree[now].l));
        } 
        return ans;
    }
    
    vector<int> g;
    
    int get_id(int x) {
        return lower_bound(g.begin(), g.end(), x) - g.begin() + 1;
    }
    
    int main() {
        scanf("%d %d", &n, &q);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            g.push_back(a[i]);
        }
        sort(g.begin(), g.end());
        g.erase(unique(g.begin(), g.end()));
    
        for (int i = 1; i <= n; i++) {
            a[i] = get_id(a[i]);
            update(a[i], 1, n, rt[i - 1], rt[i]);
        }
        while (q--) {
            int l, r, t;
            scanf("%d %d %d", &l, &r, &t);
            int k = (r - l + 1) / t;
            k++;
            int ans = query(k, 1, n, rt[l - 1], rt[r]);
            if (ans == -1) {
                printf("%d
    ", ans);
            } else {
                printf("%d
    ", g[ans - 1]);
            }
        } 
        
    }
    
    

    E. 矩阵

    题目连接

    题解:这题很容易想到单调栈取维护。枚举(i,j) , 然后计算 以(i, j)这点为矩阵且(i, j)在底边的贡献。

    这样子计算就解决了去重的问题。

    具体话, 等于每一层, 用一个(lmin[j])表示右边第一个小于 (h[j])的元素(h[j]表示当前这层 j的最大高度)

    那么 ([j, lmin[j] - 1])就可以构造一个高度为 (h[j]) 的矩阵, 左边也同理, 用(lmin[j])表示左边第一个小于或等于

    h[j]的元素, 注意这个加粗, 这样做的目的是为去重。仔细想想你就明白了

    然后等于 j这个点就可以构造出一个 ([rmin[j] - 1, lmin[j] - 1])高度为h[j]的全1矩阵, 至于这个矩阵的贡献前期预处理,直接o(1)求了。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1e3 + 7;
    int mp[N][N];
    ll  h[N], cnt[N][N] ,lmin[N], rmin[N];
    ll sum[N][N];
    
    stack<int> q;
    
    int main() {
        int n; scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                scanf("%1d", &mp[i][j]);
            }
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                if (i % j == 0 || j % i == 0) {
                    cnt[i][j]++;
                    
                    
                }
            }
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                cnt[i][j] += cnt[i - 1][j] + cnt[i][j - 1] - cnt[i - 1][j - 1];
            }
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                sum[i][j] += sum[i - 1][j] + 1ll * cnt[i][j];
            }
        }
        ll ans = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                if (mp[i][j] == 0) {
                    h[j] = 0;
                } else {
                    h[j]++;
                }
            }
    
            for (int j = 1; j <= n; j++) {
                while (!q.empty() && h[j] < h[q.top()]) {
                    lmin[q.top()] = j;
                    q.pop();
                }
                q.push(j);
            }
            while (!q.empty()) {
                lmin[q.top()] = n + 1;
                q.pop();
            }
    
            for (int j = n; j; j--) {
                while (!q.empty() && h[j] <= h[q.top()]) {
                    rmin[q.top()] = j;
                    q.pop();
                }
                q.push(j);
            }
            while (!q.empty()) {
                rmin[q.top()] = 0;
                q.pop();
            }
    
            for (int j = 1; j <= n; j++) {
                int len = lmin[j] - rmin[j] - 1;
                int l1 = j - rmin[j];
                int l2 = lmin[j] - j;
                ll cat = sum[l1 + l2 - 1][h[j]] - sum[l1 - 1][h[j]] - sum[l2 - 1][h[j]];
                ans += cat;
    
            }
            
    
        }
        printf("%lld
    ", ans);
    
        
    
    }
    
  • 相关阅读:
    mac 安装Windows系统
    各种镜像源
    应用官方下载地址汇总
    centos7 升级openssh
    ubuntu16.04升级openssh
    腾讯云
    msdeploy 远程发布到lls
    Java Script 什么是闭包?
    JavaScript我的怀疑
    HTML 之 js是干什么的
  • 原文地址:https://www.cnblogs.com/BOZHAO/p/13880947.html
Copyright © 2020-2023  润新知