zoukankan      html  css  js  c++  java
  • Codeforces Round #611 (Div. 3)

    A - Minutes Before the New Year

    题意:问现在的时间距离0点0分有多少分钟,提问的时间在0点0分之前,且不是0点0分。

    题解:?

    void test_case() {
        int h, m;
        scanf("%d%d", &h, &m);
        int ans = 0;
        if(m == 0)
            ans += (24 - h) * 60;
        else {
            ans += (23 - h) * 60;
            ans += 60 - m;
        }
        printf("%d
    ", ans);
    }
    

    B - Candies Division

    题意:把n颗糖分给k个人,可以留下一些糖,要求分配的最大值与最小值的差不超过1(尽可能平均),且比最小值多1的人数量不超过一半,在此基础上尽可能多分配。

    题解:先平均分配下整,然后零头加上去。

    void test_case() {
        int n, k;
        scanf("%d%d", &n, &k);
        int a = n / k;
        int ans = k * a;
        int surplus = min(k / 2, n - ans);
        ans += surplus;
        printf("%d
    ", ans);
    }
    

    C - Friends and Gifts

    题意:每个人必须恰好给出1颗糖果,恰好得到1颗糖果,p[i]表示他要给谁,0表示他等待分配,输入保证不矛盾。分配每个人要给谁,使得满足题目约束。

    题解:这张图就是若干条链和若干个环,环不影响直接去掉,然后链全部首尾相连。

    int s[200005];
    int p[200005];
    int h[200005];
    int t[200005];
    int cnt;
     
    int dfs(int u) {
        if(s[u] != 0)
            return dfs(s[u]);
        else
            return u;
    }
     
    void test_case() {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &p[i]);
            s[p[i]] = i;
        }
        cnt = 0;
        for(int i = 1; i <= n; ++i) {
            if(p[i] == 0) {
                if(s[i] == 0) {
                    ++cnt;
                    h[cnt] = i;
                    t[cnt] = i;
                } else {
                    ++cnt;
                    h[cnt] = i;
                    t[cnt] = dfs(i);
                }
                //printf("h=%d
    ",h[cnt]);
                //printf("t=%d
    ",t[cnt]);
            }
        }
        int j = 1;
        for(int i = 1; i <= n; ++i) {
            if(p[i] == 0) {
                p[i] = t[++j];
                if(j > cnt)
                    p[i] = t[1];
            }
        }
        for(int i = 1; i <= n; ++i)
            printf("%d%c", p[i], " 
    "[i == n]);
    }
    

    D - Christmas Trees

    题意:数轴上有n棵圣诞树,位置分别是xi。给m个人分配位置,使得所有人到离他最近的圣诞树的距离的和最小。

    题解:直接贪心往每棵树两边加人即可。用了一个丑陋的实现,先二分确定可以加的值,然后再加。

    int n, m;
    int x[200005];
     
    bool check(int mlen) {
        ll sumpoints = 2 * mlen;
        for(int i = 2; i <= n; ++i) {
            sumpoints += min(x[i] - x[i - 1] - 1, 2 * mlen);
            if(sumpoints >= m) {
                //printf("check mlen=%d, suc.
    ", mlen);
                return true;
            }
        }
        if(sumpoints >= m) {
            //printf("check mlen=%d, suc.
    ", mlen);
            return true;
        }
        //printf("check mlen=%d, fail.
    ", mlen);
        return false;
    }
     
    int ans[200005];
     
    priority_queue<pii> pq;
     
    ll answer(int mlen) {
        for(int j = 1; j <= mlen; ++j)
            pq.push({-j, x[1] - j});
        for(int j = 1; j <= mlen; ++j)
            pq.push({-j, x[n] + j});
        for(int i = 1; i < n; ++i) {
            if(x[i + 1] - x[i] - 1 > 2 * mlen) {
                for(int j = 1; j <= mlen; ++j)
                    pq.push({-j, x[i] + j});
                for(int j = 1; j <= mlen; ++j)
                    pq.push({-j, x[i + 1] - j});
            } else {
                int dis = (x[i + 1] - x[i]);
                for(int j = 1; ; ++j) {
                    if(x[i] + j == x[i + 1])
                        break;
                    pq.push({-(min(j, dis - j)), x[i] + j});
                }
            }
        }
     
        ll res = 0;
        for(int j = 1; j <= m; ++j) {
            ans[j] = pq.top().second;
            res += (-pq.top().first);
            //cout << "x=" << pq.top().second << endl;
            //cout << "d=" << (-pq.top().first) << endl;
            pq.pop();
        }
        while(pq.size())
            pq.pop();
        return res;
    }
     
    ll bs() {
        int l = 1, r = m;
        while(1) {
            int mid = l + r >> 1;
            if(l == mid) {
                if(check(l))
                    return answer(l);
                assert(check(r));
                return answer(r);
            }
            if(check(mid))
                r = mid;
            else
                l = mid + 1;
        }
    }
     
     
    void test_case() {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++i)
            scanf("%d", &x[i]);
        if(n == 1) {
            ll sum = 0;
            int l = x[1], r = x[1];
            for(int i = 1; i <= m; ++i) {
                if(i & 1) {
                    ans[i] = --l;
                    sum += x[1] - l;
                } else {
                    ans[i] = ++r;
                    sum += r - x[1];
                }
            }
            printf("%lld
    ", sum);
            sort(ans + 1, ans + 1 + m);
            for(int i = 1; i <= m; ++i)
                printf("%d%c", ans[i], " 
    "[i == m]);
            return;
        }
        sort(x + 1, x + 1 + n);
        printf("%lld
    ", bs());
        sort(ans + 1, ans + 1 + m);
        for(int i = 1; i <= m; ++i)
            printf("%d%c", ans[i], " 
    "[i == m]);
    }
    

    但是其实可以存每棵树的l指针和r指针,当某棵树的r指针遇到另一棵树的l指针的时候就把这两个指针去掉。不过这样写起来不见得比二分好写。先二分的原因是可以避免把过多的点插进优先队列。

    E - New Year Parties

    题意:有n个人,每个人可以左移1、右移1或者留在原地。求最小覆盖多少个点和最大覆盖多少个点。

    题解:很明显满足dp的性质。只是很容易漏掉一些转移。

    int n;
    int x[200005];
    int dp[200005][8];
     
    void test_case() {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &x[i]);
            ++x[i];
        }
        sort(x + 1, x + 1 + n);
        //xi value range [2,n+1]
        //can move to value range [1,n+2]
     
        //MIN
        memset(dp, INF, sizeof(dp));
        dp[0][0] = 0;
        for(int i = 1; i <= n; ++i) {
            if(i == 1 || x[i] == x[i - 1]) {
                //move to left
                dp[i][4] = min(dp[i - 1][4], dp[i - 1][0] + 1);
                dp[i][5] = min(dp[i - 1][5], dp[i - 1][1] + 1);
                dp[i][6] = min(dp[i - 1][6], dp[i - 1][2] + 1);
                dp[i][7] = min(dp[i - 1][7], dp[i - 1][3] + 1);
                //stay here
                dp[i][2] = min(dp[i - 1][2], dp[i - 1][0] + 1);
                dp[i][3] = min(dp[i - 1][3], dp[i - 1][1] + 1);
                dp[i][6] = min(dp[i][6], min(dp[i - 1][6], dp[i - 1][4] + 1));
                dp[i][7] = min(dp[i][7], min(dp[i - 1][7], dp[i - 1][5] + 1));
                //move to right
                dp[i][1] = min(dp[i - 1][1], dp[i - 1][0] + 1);
                dp[i][3] = min(dp[i][3], min(dp[i - 1][3], dp[i - 1][2] + 1));
                dp[i][5] = min(dp[i][5], min(dp[i - 1][5], dp[i - 1][4] + 1));
                dp[i][7] = min(dp[i][7], min(dp[i - 1][7], dp[i - 1][6] + 1));
            } else {
                if(x[i] == x[i - 1] + 1) {
                    //move to left
                    dp[i][4] = min(min(dp[i - 1][2], dp[i - 1][6]), min(dp[i - 1][0], dp[i - 1][4]) + 1);
                    dp[i][6] = min(min(dp[i - 1][3], dp[i - 1][7]), min(dp[i - 1][1], dp[i - 1][5]) + 1);
                    //stay here
                    dp[i][2] = min(min(dp[i - 1][1], dp[i - 1][5]), min(dp[i - 1][0], dp[i - 1][4]) + 1);
                    dp[i][6] = min(dp[i][6], min(min(dp[i - 1][3], dp[i - 1][7]), min(dp[i - 1][2], dp[i - 1][6]) + 1));
                    //move to right
                    dp[i][1] = min(dp[i - 1][0], dp[i - 1][4]) + 1;
                    dp[i][3] = min(dp[i - 1][1], dp[i - 1][5]) + 1;
                    dp[i][5] = min(dp[i - 1][2], dp[i - 1][6]) + 1;
                    dp[i][7] = min(dp[i - 1][3], dp[i - 1][7]) + 1;
                } else if(x[i] == x[i - 1] + 2) {
                    //move to left
                    dp[i][4] = min(min(dp[i - 1][1], dp[i - 1][3]), min(dp[i - 1][5], dp[i - 1][7]));
                    for(int j = 0; j <= 7; j += 2)
                        dp[i][4] = min(dp[i][4], dp[i - 1][j] + 1);
                    //stay here
                    for(int j = 0; j <= 7; j += 2)
                        dp[i][2] = min(dp[i][2], dp[i - 1][j] + 1);
                    for(int j = 1; j <= 7; j += 2)
                        dp[i][6] = min(dp[i][6], dp[i - 1][j] + 1);
                    //move to right
                    for(int j = 0; j <= 7; j += 2)
                        dp[i][1] = min(dp[i][1], dp[i - 1][j] + 1);
                    for(int j = 1; j <= 7; j += 2)
                        dp[i][5] = min(dp[i][5], dp[i - 1][j] + 1);
                } else {
                    //move to left
                    for(int j = 0; j <= 7; ++j)
                        dp[i][4] = min(dp[i][4], dp[i - 1][j] + 1);
                    //stay here
                    for(int j = 0; j <= 7; ++j)
                        dp[i][2] = min(dp[i][2], dp[i - 1][j] + 1);
                    //move to right
                    for(int j = 0; j <= 7; ++j)
                        dp[i][1] = min(dp[i][1], dp[i - 1][j] + 1);
                }
            }
            /*for(int j = 0; j <= 7; ++j)
                printf("dp[%d][%d]=%d
    ", i, j, dp[i][j]);
            printf("
    ");*/
        }
        int ans1 = INF;
        for(int j = 0; j <= 7; ++j)
            ans1 = min(ans1, dp[n][j]);
     
     
        //MAX
        memset(dp, -INF, sizeof(dp));
        dp[0][0] = 0;
        for(int i = 1; i <= n; ++i) {
            if(i == 1 || x[i] == x[i - 1]) {
                //move to left
                dp[i][4] = max(dp[i - 1][4], dp[i - 1][0] + 1);
                dp[i][5] = max(dp[i - 1][5], dp[i - 1][1] + 1);
                dp[i][6] = max(dp[i - 1][6], dp[i - 1][2] + 1);
                dp[i][7] = max(dp[i - 1][7], dp[i - 1][3] + 1);
                //stay here
                dp[i][2] = max(dp[i - 1][2], dp[i - 1][0] + 1);
                dp[i][3] = max(dp[i - 1][3], dp[i - 1][1] + 1);
                dp[i][6] = max(dp[i][6], max(dp[i - 1][6], dp[i - 1][4] + 1));
                dp[i][7] = max(dp[i][7], max(dp[i - 1][7], dp[i - 1][5] + 1));
                //move to right
                dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + 1);
                dp[i][3] = max(dp[i][3], max(dp[i - 1][3], dp[i - 1][2] + 1));
                dp[i][5] = max(dp[i][5], max(dp[i - 1][5], dp[i - 1][4] + 1));
                dp[i][7] = max(dp[i][7], max(dp[i - 1][7], dp[i - 1][6] + 1));
            } else {
                if(x[i] == x[i - 1] + 1) {
                    //move to left
                    dp[i][4] = max(max(dp[i - 1][2], dp[i - 1][6]), max(dp[i - 1][0], dp[i - 1][4]) + 1);
                    dp[i][6] = max(max(dp[i - 1][3], dp[i - 1][7]), max(dp[i - 1][1], dp[i - 1][5]) + 1);
                    //stay here
                    dp[i][2] = max(max(dp[i - 1][1], dp[i - 1][5]), max(dp[i - 1][0], dp[i - 1][4]) + 1);
                    dp[i][6] = max(dp[i][6], max(max(dp[i - 1][3], dp[i - 1][7]), max(dp[i - 1][2], dp[i - 1][6]) + 1));
                    //move to right
                    dp[i][1] = max(dp[i - 1][0], dp[i - 1][4]) + 1;
                    dp[i][3] = max(dp[i - 1][1], dp[i - 1][5]) + 1;
                    dp[i][5] = max(dp[i - 1][2], dp[i - 1][6]) + 1;
                    dp[i][7] = max(dp[i - 1][3], dp[i - 1][7]) + 1;
                } else if(x[i] == x[i - 1] + 2) {
                    //move to left
                    for(int j = 1; j <= 7; j += 2)
                        dp[i][4] = max(dp[i][4], dp[i - 1][j]);
                    for(int j = 0; j <= 7; j += 2)
                        dp[i][4] = max(dp[i][4], dp[i - 1][j] + 1);
                    //stay here
                    for(int j = 0; j <= 7; j += 2)
                        dp[i][2] = max(dp[i][2], dp[i - 1][j] + 1);
                    for(int j = 1; j <= 7; j += 2)
                        dp[i][6] = max(dp[i][6], dp[i - 1][j] + 1);
                    //move to right
                    for(int j = 0; j <= 7; j += 2)
                        dp[i][1] = max(dp[i][1], dp[i - 1][j] + 1);
                    for(int j = 1; j <= 7; j += 2)
                        dp[i][5] = max(dp[i][5], dp[i - 1][j] + 1);
                } else {
                    //move to left
                    for(int j = 0; j <= 7; ++j)
                        dp[i][4] = max(dp[i][4], dp[i - 1][j] + 1);
                    //stay here
                    for(int j = 0; j <= 7; ++j)
                        dp[i][2] = max(dp[i][2], dp[i - 1][j] + 1);
                    //move to right
                    for(int j = 0; j <= 7; ++j)
                        dp[i][1] = max(dp[i][1], dp[i - 1][j] + 1);
                }
            }
            /*for(int j = 0; j <= 7; ++j)
                printf("dp[%d][%d]=%d
    ", i, j, dp[i][j]);
            printf("
    ");*/
        }
        int ans2 = 0;
        for(int j = 0; j <= 7; ++j)
            ans2 = max(ans2, dp[n][j]);
     
        printf("%d %d
    ", ans1, ans2);
    }
    

    好像有贪心的写法?

    最小的贪心:首先把最左侧的元素往右移,然后记录当前的lst(最右)位置,假如某个元素x<=lst+1说明他可以通过某些移动叠到lst中,跳过这种情况,否则一定断开了,递归到小规模的问题。

    最大的贪心:首先把最左侧的元素往左移,然后记录当前的lst(最右位置),假如某个元素xlst,则可以把x右移;假如某个元素xlst+1那么它可以不移动,其他情况说明断开了,递归到小规模的问题。

    int n;
    int x[200005];
    
    int solve_min() {
        int ans = 0;
        int lst = -INF;
        for(int i = 1; i <= n; ++i) {
            if(x[i] <= lst + 1)
                continue;
            else {
                ++ans;
                lst = x[i] + 1;
            }
        }
        return ans;
    }
    
    int solve_max() {
        int ans = 0;
        int lst = -INF;
        for(int i = 1; i <= n; ++i) {
            if(x[i] <= lst - 1)
                continue;
            else {
                ++ans;
                if(x[i] == lst)
                    lst = x[i] + 1;
                else if(x[i] == lst + 1)
                    lst = x[i];
                else
                    lst = x[i] - 1;
            }
        }
        return ans;
    }
    
    void test_case() {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &x[i]);
            ++x[i];
        }
        sort(x + 1, x + 1 + n);
        printf("%d %d
    ", solve_min(), solve_max());
    }
    
  • 相关阅读:
    跟结束进程相关的那些信号
    tcpdump使用示例
    Linux在bash history当中添加timestamp
    CentOS中在/etc/rc.local添加开机自启动项启动失败
    CentOS配置通过DHCP的方式动态获取IP
    CentOS桌面安装
    MySQL二进制安装
    对okhttp参数的一些思考
    依赖倒置原则(DIP)
    Liskov替换原则(LSP)
  • 原文地址:https://www.cnblogs.com/KisekiPurin2019/p/12221463.html
Copyright © 2011-2022 走看看