zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 77 (Rated for Div. 2)

    A - Heating

    题意:一个房间,最多装c个加热器,若某个加热器长度为k,则花费为k*k,覆盖这n个长度求最小花费。

    题解:首先每个格子只装最多一个,先取min。然后肯定是最平均最好,小平均值是n/d取下整,大平均值是小平均值+1,大平均值的个数是n%d,小平均值的个数即剩下的。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    void test_case() {
        ll c, n;
        scanf("%lld%lld", &c, &n);
        c = min(n, c);
        ll L = n / c;
        ll R = L + 1;
        ll cntR = n % c;
        ll cntL = (n - (cntR * R)) / L;
        ll ans = cntL * (L * L) + cntR * (R * R);
        printf("%lld
    ", ans);
    }
    
    int main() {
    #ifdef KisekiPurin
        freopen("KisekiPurin.in", "r", stdin);
    #endif // KisekiPurin
        int t = 1;
        scanf("%d", &t);
        for(int ti = 1; ti <= t; ++ti) {
            //printf("Case #%d: ", ti);
            test_case();
        }
    }
    

    B - Obtain Two Zeroes

    题意:两个数x,y,每次可以选择:1、x:=x-d, y:=y-2d 或 2、x:=x-2d, y:=y-d ,d是正整数,求x,y是否可以同时为0。

    题解:首先先把两个拉到同一个大小,这是必须的,两个数第一次相遇的时机。当这个时机出现在负数,NO。出现这个时机之后两个数轮流减,直接模3。

    void test_case() {
        int a, b;
        Scanf(a, b);
        if(a > b)
            swap(a, b);
        a -= b - a;
        if(a < 0 || a % 3)
            return NO();
        return YES();
    }
    

    C - Infinite Fence

    题意:有一串砖,凡是r的倍数而不是b的倍数必须涂红,凡是b的倍数而不是r的倍数必须涂蓝,是公倍数则选一个涂。把涂色的砖选出来之后,问是否一定有连续的k个砖是同一种颜色。

    题解:首先,假如两个数有公因子,那么他们都会跳过一系列砖,除掉不影响答案。然后必有他们的gcd为1,若b和a相等,则NO。否则设b更大,那么必须贪心,有b涂就涂b打断r的连续。那么因为公因子是1,那么在某个时刻会存在这样的情形:

    br---r---r---rb
    br---r---r---r.b
    br---r---r---r..b
    br---r---r---r...b
    

    也就是一个b之后若干个r周期,然后剩下至多r-1个空格不够再放一个r。已知放k个r需要d=(k-1)*r+1的长度,求b-1的长度是否超过d,注意溢出。然后若b和a相等,也满足此式,合并一起。

    void YES() {
        //puts("YES");
        puts("REBEL");
    }
    
    void NO() {
        //puts("NO");
        puts("OBEY");
    }
    
    void test_case() {
        ll r, b, k;
        Scanf(r, b, k);
        if(r > b)
            swap(r, b);
        ll g = __gcd(r, b);
        r /= g, b /= g;
        if((b - 1) >= (k - 1) * r + 1)
            return YES();
        else
            return NO();
    }
    

    D - A Game with Traps

    题意:有m个士兵,t秒,你要带尽可能多的士兵从0去n+1,且他们不能被杀死。路上有一些陷阱,陷阱d[i]会杀死能力比它小的士兵,陷阱位置在l[i],当你走到r[i]时可以拆除它。每次你可以向左或者向右移动,然后立刻拆除当前位置的陷阱。你的士兵必须被你带着移动,且移动到格子时该位置不能有陷阱。

    题解:首先可以二分士兵的数量,然后贪心选最强的士兵出来。check的时候也是直接贪心,发现一个规律,就是假如遇到了一个陷阱,则必须要拆除它,经过2次R-L再把士兵带过来。而如果拆的路上还有其他陷阱的话就一路拆过去,因为这些路拆除陷阱至少都要走两次,走过去一起拆了不会更差,拆完一路之后干脆就一起带过来所以走了3倍路程。否则若没有陷阱肯定贪心直接带着士兵右移1格。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    int m, n, k, t;
    int a[200005];
    int R[200005];
    vector<int> l[200005];
    int d[200005];
    
    bool check(int p) {
        int predp = 0, curdp = 0;
        for(int i = 1, prei = 0; i <= n + 1; ++i) {
            int maxR = -1;
            for(auto id : l[i]) {
                if(d[id] <= a[p])
                    continue;
                maxR = max(maxR, R[id]);
            }
            while(i < maxR) {
                ++i;
                for(auto id : l[i]) {
                    if(d[id] <= a[p])
                        continue;
                    maxR = max(maxR, R[id]);
                }
            }
            if(maxR != -1)
                curdp = predp + 3 * (i - prei);
            else
                curdp = predp + 1;
            prei = i;
            predp = curdp;
        }
        return curdp <= t;
    }
    
    void test_case() {
        scanf("%d%d%d%d", &m, &n, &k, &t);
        for(int i = 1; i <= m; ++i)
            scanf("%d", &a[i]);
        for(int i = 1, L; i <= k; ++i) {
            scanf("%d%d%d", &L, &R[i], &d[i]);
            l[L].push_back(i);
        }
        sort(a + 1, a + 1 + m, greater<int>());
        int l = 0, r = m;
        while(1) {
            int mid = (l + r) >> 1;
            if(l == mid) {
                if(check(r)) {
                    printf("%d
    ", r);
                    return;
                }
                printf("%d
    ", l);
                return;
            }
            if(check(mid))
                l = mid;
            else
                r = mid - 1;
        }
    }
    
    int main() {
    #ifdef KisekiPurin
        freopen("KisekiPurin.in", "r", stdin);
    #endif // KisekiPurin
        int t = 1;
        //scanf("%d", &t);
        for(int ti = 1; ti <= t; ++ti) {
            //printf("Case #%d: ", ti);
            test_case();
        }
    }
    
    /*
        1. 小数据问题退化:
            输入为0或1会不会有特殊情况?其他的比如最小环要有三个点,强连通分量缩到最后一个点等等。
        2. 内存:
            内存的空间有没有开够?有时有反向边,有时有额外新加的边。线段树开了4倍了吗?
            可持久化数据结构会不会内存溢出?多组数据时vector会不会翻车?
            多组数据有进行初始化吗?memset会不会翻车?
        3. 算术溢出:
            乘法上溢出了?忘记取模了?输入输出用了%d?让无符号数越到负数了?
        4. 习惯:
            函数都有指定返回值吗?返回值非void函数的每一个分支都有显式的返回值吗?确定不会进入的分支可以assert一把。
            Yes和No有没有反?有没有搞错n和m?离散化之后的cn有没有错?换行和空格要怎么整?priority要把符号反过来。
        5. 其他bug:
            基环树是树加环,不是链加环。
    */
    

    E - Tournament

    题意:有n个选手,n是2的幂。n个人的能力值分别是[1,n],两两配对参加淘汰赛,每次高手会淘汰掉低手,然后高手们参加下一轮。你的朋友也参加,安排适当的顺序让他获胜,你可以贿赂其中的某些人,使得他和你朋友打的时候放水。求最便宜的贿赂总价。

    题解:若朋友是天下第一,则0。否则必定会和天下第一打,所以要贿赂天下第一。然后天下第一可以带走[n/2+1,n]这群高手,若朋友在[n/2+1,n]里则直接结束了,否则递归到一半规模的问题。不过这一次不一定要贿赂天下第一(感谢样例2),你可以贿赂一个比天下第一更强的又更便宜的人和天下第一交换。所以维护一个小根堆是最简单的方法,当然也可以动态保留至多logn个人,更贵的就没用了,或者整个归并排序,这样复杂度可能会变小,但是麻烦还容易错。要注意贿赂的人不用重复入队。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    int a[(1 << 18) + 5];
    priority_queue<int, vector<int>, greater<int> >pq;
    
    ll solve(int pos, int n) {
        if(pos >= n)
            return 0;
        else {
            ll res = 0;
            if(pq.empty() || a[n] < pq.top()) {
                res += a[n];
                for(int i = n / 2 + 1; i < n; ++i)
                    pq.push(a[i]);
            } else {
                res += pq.top();
                pq.pop();
                for(int i = n / 2 + 1; i <= n; ++i)
                    pq.push(a[i]);
            }
            res += solve(pos, n / 2);
            return res;
        }
    }
    
    void test_case() {
        int n;
        scanf("%d", &n);
        int p = -1;
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
            if(a[i] == -1)
                p = i;
        }
        printf("%lld
    ", solve(p, n));
    }
    
    int main() {
    #ifdef KisekiPurin
        freopen("KisekiPurin.in", "r", stdin);
    #endif // KisekiPurin
        int t = 1;
        //scanf("%d", &t);
        for(int ti = 1; ti <= t; ++ti) {
            //printf("Case #%d: ", ti);
            test_case();
        }
    }
    
  • 相关阅读:
    html5--6-56 阶段练习5-翻转效果
    html5--6-55 动画效果-关键帧动画
    html5--6-53 阶段练习4-画廊
    html5--6-52 动画效果-过渡
    navicat常用快捷键
    Mysql语句示例
    mysql语句大全
    intellij IDEA怎样打war包
    如何将java web项目上线/部署到公网
    jsp的4大作用域
  • 原文地址:https://www.cnblogs.com/KisekiPurin2019/p/11949314.html
Copyright © 2011-2022 走看看