zoukankan      html  css  js  c++  java
  • HGOI 20190710 提高组模拟41

    Day2, 贼差。 NMD OI赛制变成 ACM 可还行
    结果交流了个鸡儿。
    该治治了

    1. 取整(round)

    这题还算简单
    可以考虑贪心
    预处理出每个语言想进位需要的试卷数
    然后贪心依次选择小的
    剩余的就考虑最小的试卷能晋级的数 (min)
    然后就是加进去 (dfrac{n-sum}{min})(min)
    还有剩就不管了,直接扔进去

    #include <bits/stdc++.h>
    using namespace std ;
    
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define per(i, a, b) for (int i = a; i >= b; i--)
    #define siz(a) (int) a.size()
    #define pb push_back
    #define mp make_pair
    #define ll long long
    #define fi first
    #define se second
    
    const int N = 300010 ;
    
    int n, m, rest ;
    int a[N], b[N], id[N], need[N] ;
    vector <int> valid ;
    
    bool up(int i, int n)  {
        return (int)floor(1.0 * i / n * 100 + 0.5) - (int)floor(1.0 * i / n * 100) == 1 ;
    }
    
    bool cmp(int i, int j) {
        return need[i] < need[j] ;
    }
    
    void clear() {
        valid.clear() ;
    }
    
    signed main() {
        int t ; scanf("%d", &t) ;
        rep(rnd, 1, t) {
            clear() ;
            scanf("%d%d", &n, &m) ;
            rest = n ;
            rep(i, 1, m) scanf("%d", &a[i]), rest -= a[i] ;
            int mi = -1 ;
            rep(i, 1, n) 
            if (up(i, n)) {
                valid.pb(i) ;
                if (mi == -1) mi = i ;
            }
            rep(i, 1, m) b[i] = a[i] ;
            rep(i, 1, m) need[i] = 0 ;
            rep(i, 1, m) {
                id[i] = i ;
                int pos = lower_bound(valid.begin(), valid.end(), a[i]) - valid.begin() ;
                if (pos != siz(valid)) {
                    int cost = valid[pos] - a[i] ;
                    need[i] = cost ; 
                } 
            }
            sort(id + 1, id + m + 1, cmp) ;
            rep(i, 1, m) {
                if (need[id[i]] < mi && rest >= need[id[i]]) {
                    rest -= need[id[i]] ;
                    b[id[i]] += need[id[i]] ;
                }
            }
            int cnt = m ;
            if (mi != -1) {
                while (rest >= mi) {
                    rest -= mi ;
                    b[++cnt] = mi ;
                }
            }
            if (rest) b[++cnt] = rest ;
            int ans = 0 ;
            rep(i, 1, cnt) ans += (int) floor(1.0 * b[i] / n * 100 + 0.5) ;
            printf("Case #%d: %d
    ", rnd, ans) ;
        }
        return 0 ;
    }
    
    1. 路标(sign)

    观察能力太弱了。
    可以发现如果我们固定一个端点 (l), 如果右端点 (r) 符合要求,
    那么 (r-1) 也必定符合要求。

    所以答案有带调性

    考虑枚举一个点,滑动另一个点

    (a_i=D_i+A_i,b_i=D_i-B_i)

    考虑如何维护

    1. 区间内只有一种 (a_i) 或者只有一种$ b_i$, 肯定可以
    2. 当区间内有两种或者以上的 (a_i) 的时候
      对于当前的 (a_i) 如果选择, 那么上一个不同的 (a_i) 对应的 (b_i) 一定要选,
      如果选择这一对数能覆盖到所有的位置就可行
      对于当前的 (a_i) 如果不选择,那么当前的 (b_i) 一定要选,
      一个不同的 (b_i) 对应的 (a_i) 一定要选,
      如果选择这一对数能覆盖到所有的位置就可行

    可以通过三个 (map) 实现

    #include <bits/stdc++.h>
    using namespace std ;
    
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define per(i, a, b) for (int i = a; i >= b; i--)
    #define siz(a) (int) a.size()
    #define pb push_back
    #define mp make_pair
    #define ll long long
    #define fi first
    #define se second
    
    const int N = 100010 ;
    
    map <int,int> ma ;
    map <int,int> mb;
    map<pair<int, int>, int> mab ;
    int a[N], b[N] ;
    
    signed main() {
        int n;
        cin >> n;
        rep(i, 1, n) {
          int x, y, z; scanf("%d%d%d", &x, &y, &z) ;
          a[i] = x + y ;
          b[i] = x - z ;
        }
        int j = 1;
        int la = 0, lb = 0;
        int ans = -1, ways = -1;
        rep(i, 1, n) {
            ma[a[i]]++;
            mb[b[i]]++;
            mab[mp(a[i], b[i])]++;
            if (i > 1 && a[i] != a[i - 1]) la = i - 1;
            if (i > 1 && b[i] != b[i - 1]) lb = i - 1;
            while (j <= i) {
                if (la < j || lb < j) break ;
                int cnt = ma[a[i]] + mb[b[la]] - mab[mp(a[i], b[la])];
                if (cnt == i - j + 1) break;
                cnt = ma[a[lb]] + mb[b[i]] - mab[mp(a[lb], b[i])];
                if (cnt == i - j + 1) break;
                ma[a[j]]--;
                mb[b[j]]--;
                mab[mp(a[j], b[j])]--;
                j++;
            }
            int len = i - j + 1;
            if (len > ans) {
                ans = len;
                ways = 0;
            }
            if (len == ans) {
                ways++;
            }
        }
        printf("%d %d
    ", ans, ways) ;
        return 0;
    }
    
    1. 树袋(tree)

    这道题本来想尝试些一下 (100),结果可想而知,连暴力分都莫得。

    某奕同学 (A) 了这题,讲解把我搞得更糊涂了。

    然后我就看 (solution) 去了

    我感觉 (solution) 足够明确

    注意到能影响当前点的操作是当前点到根的路径上的点以及根这些点
    相关联的所有操作,其他都无关

    所以我们只需要在进入 (u) 子树的时候将 (u) 相关的操作全部作用进去,
    离开u子树的时候将 (u) 相关的操作全部取消,
    相当于时刻维护着根到当前节点的所有修改.

    (dfs) 序转换之后就变成了, 有若干次区间的覆盖,删除操作,跟 (u) 相关的所
    有操作会插入一次,删除一次,

    每批量插入完一次后会查询全局覆盖的长度的并

    这个可以用线段树解决, 线段树的处理技巧类似于求矩形面积并(可以
    自行学习)

    简单说来就是在区间合并的时候,如果发现当前区间的懒惰标记大于0,
    那么当前区间被覆盖的总长就可以直接记为区间长度, 否则就等于左右
    儿子之和

    注意这个线段树下面的 (sum) 值可能是假的(因为很多点的标记不下传
    了),但是 (sum[1]) 一定是真的

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define per(i, a, b) for (int i = a; i >= b; i--)
    #define siz(a) (int)a.size()
    #define pb push_back
    #define mp make_pair
    #define ll long long
    #define fi first
    #define se second
    
    const int N = 100010 ;
    
    int tot, n, m ;
    int l[N], r[N], ans[N] ;
    vector <int> e[N], G[N] ;
    int t[N * 10], tag[N * 10];
    
    void modify(int u, int l, int r, int x, int y, int k) {
        if (l >= x && r <= y) {
            tag[u] += k ;
            if (!tag[u]) t[u] = t[u << 1] + t[u << 1 | 1] ;
            else t[u] = r - l + 1 ;
            return ;
        }
        int mid = (l + r) >> 1 ; 
        if (x <= mid) modify(u << 1, l, mid, x, y, k) ;
        if (y > mid) modify(u << 1 | 1, mid + 1, r, x, y, k) ;
        if (!tag[u]) t[u] = t[u << 1] + t[u << 1 | 1] ;
        else t[u] = r - l + 1 ;
        return ;
    }
    
    void DFN(int u, int fa) {
        l[u] = ++tot ;
        rep(i, 0, siz(e[u]) - 1) {
            int v = e[u][i] ;
            if (v == fa) continue ;
            DFN(v, u) ;
        }
        r[u] = tot ;
    }
    
    void dfs(int u, int fa) {
        rep(i, 0, siz(G[u]) - 1) modify(1, 1, n, l[G[u][i]], r[G[u][i]], 1);
        ans[u] = t[1];
        rep(i, 0, siz(e[u]) - 1) if (e[u][i] != fa) dfs(e[u][i], u);
        rep(i, 0, siz(G[u]) - 1)  modify(1, 1, n, l[G[u][i]], r[G[u][i]], -1);
    }
    
    signed main() {
    //  freopen("tree.in", "r", stdin) ;
    //  freopen("tree.out", "w", stdout) ; 
        scanf("%d%d", &n, &m) ;
        rep(i, 1, n - 1) {
            int u, v ; scanf("%d%d", &u, &v) ;
            e[u].pb(v) ; e[v].pb(u) ;
        }
        DFN(1, 0);
        rep(i, 1, m) {
            int a, b ; scanf("%d%d", &a, &b) ;
            G[a].pb(a) ; G[a].pb(b) ;
            G[b].pb(a) ; G[b].pb(b) ;
        }
        dfs(1, 0);
        rep(i, 1, n) printf("%d ", max(ans[i] - 1, 0)) ;
        return 0 ;
    }
    
  • 相关阅读:
    php安全编程&python测试实例编写
    MySQL注入技巧性研究
    第一届“百度杯”信息安全攻防总决赛
    不想在315“中奖”?你得躲过这些坑!
    这些故事你尽管听,不奇葩算我输!
    str2-045漏洞事件,你想要的这里都有
    python多线程在渗透测试中的应用
    【ZCTF】easy reverse 详解
    UVA
    用Thinphp发送电子邮件的方法
  • 原文地址:https://www.cnblogs.com/harryhqg/p/13290852.html
Copyright © 2011-2022 走看看