• Codeforces Round #615 (Div. 3) (CF1294D、E、F)题解


    题目链接

    官方英文题解

    A、B、C直接上代码吧

    A

    #include <bits/stdc++.h>
    using namespace std;
    signed main() {
        int T; scanf ("%d", &T);
        while (T--) {
            int a, b, c, n;
            scanf ("%d %d %d %d", &a, &b, &c, &n);
            int s = a + b + c + n;
            if (s % 3 == 0 && s / 3 >= max (a, max (b, c))) puts ("YES");
            else puts ("NO");
        }
        return 0;
    }
    
    

    B

    #include <bits/stdc++.h>
    using namespace std;
    struct node {
        int x, y;
        bool operator < (const node &t) {
            return x == t.x ? y < t.y : x < t.x;
        }
    } p[1024];
    char ch[100000];
    signed main() {
        int T; scanf ("%d", &T);
        while (T--) {
            int n; scanf ("%d", &n);
            for (int i = 1; i <= n; ++i) scanf ("%d %d", &p[i].x, &p[i].y);
            sort (p + 1, p + n + 1);
            int s = 0, h = 0;
            bool ok = 1;
            for (int i = 1; i <= n; ++i) {
                if (p[i].y < h) {ok = 0; break;}
                for (int j = 1; j <= p[i].x - p[i - 1].x; ++j) ch[++s] = 'R';
                for (int j = 1; j <= p[i].y - p[i - 1].y; ++j) ch[++s] = 'U';
                h = max (h, p[i].y);
            }
            if (ok) {
                puts ("YES");
                for (int i = 1; i <= s; ++i) cout << ch[i]; puts ("");
            }else puts ("NO");
        }
        return 0;
    }
    

    C

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1E5, M = 1E9;
    int k[N], p[N], tot, c[N];
    inline void Pre_work () { 
        for (int i = 2; i * i <= M; ++i) {
            if (!k[i]) p[++tot] = i;
            for (int j = 1; j <= tot && 1ll * i * i * p[j] * p[j] <= M; ++j) {
                k[i * p[j]] = 1;
                if (i % p[j] == 0) break;
            }
        }
    }
    inline int Pow (int a, int b) {
        int res (1);
        while (b) {
            if (b & 1) res *= a;
            b >>= 1, a *= a;
        } return res;
    }
    signed main() {
        int T; scanf ("%d", &T);
        Pre_work ();
        while (T--) {
            int n, a (0), b (0), c (0); scanf ("%d", &n); int t = n;
            for (int i = 1; i <= tot; ++i) {
                int cnt = 0, mx = 1;
                while (n % p[i] == 0) n /= p[i], ++cnt;
                if (!cnt) continue;
                if (!a) {
                    a = Pow (p[i], mx);
                    cnt -= mx, ++mx;
                    if (cnt >= mx) {
                        b = Pow (p[i], mx), cnt -= mx, ++mx;
                        if (t / a / b != a && t / a / b != b && t / a / b > 1) {c = t / a / b; break;}
                    }
                }
                else if (!b) {
                    b = Pow (p[i], mx);
                    cnt -= mx, ++mx;
                    if (t / a / b != a && t / a / b != b && t / a / b > 1) {c = t / a / b; break;}
                }
                else if (!c) {
                    if (t / a / b != a && t / a / b != b && t / a / b > 1) {c = t / a / b; break;}
                } else break;
            }
            if (c) puts ("YES"), printf ("%d %d %d
    ", a, b, c);
            else puts ("NO");
        }
        return 0;
    }
    

    D

    题意:向序列中每次加入一个数,可以把序列中的任意一个数a变为b,满足b=a+k*x,b>=0且k为整数,每次回答当前序列中不存在的最小自然数的最大可能值

    显然与取模运算有关,a[i]表示%x结果为i的数中最小的没有的数,为了让最小的数最大,一定先从小的数开始向上填补空缺,即假设有m个数%n=i,则让第一个数为i,第二个为x+i,第三个为2*x+i......

    当加入一个数p的时候,就让a[p%x]加上x,a[i]的初值为i,得到的答案最优,最终答案为所有a[i]的min值

    由于蒟蒻比较菜,想都不想就直接上线段树了

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N = 5e5;
    int a[N], mx;
    int c[N << 2];
    void build (int p, int l, int r) {
        if (l == r) {c[p] = l; return;}
        int mid (l + r >> 1);
        build (p << 1, l, mid), build (p << 1 | 1, mid + 1, r);
        c[p] = min (c[p << 1], c[p << 1 | 1]);
    }
    inline void update (int p, int l, int r, int pos, int val) {
    //    printf ("%d %d %d
    ", p, l, r);
        if (l == r) {c[p] = val; return;}
        int mid = l + r >> 1;
        pos <= mid ? update (p << 1, l, mid, pos, val) : update (p << 1 | 1, mid + 1, r, pos, val);
        c[p] = min (c[p << 1], c[p << 1 | 1]);
    }
    signed main() {
        int n, x;
        scanf ("%lld %lld", &n, &x);
        for (int i = 0; i < x; ++i) a[i] = i; mx = 0;
        build (1, 0, x - 1);
        for (int i = 1, y; i <= n; ++i) {
            scanf ("%lld", &y);
            if (y > 0) y %= x; a[y] += x;
            update (1, 0, x - 1, y, a[y]);
            printf ("%lld
    ", c[1]);
        }
        return 0;
    }
    

    E

    题意:给定一个矩阵,有两种操作:1、改变某个位置的数 2、将任意一列“滚动一位”(具体看题面),使其转换到目标矩阵

    由题意易得每列互不相关,对每列单独考虑

    在一列中,有些数本来就是目标状态中这一列的数,可以通过若干次移动操作使其在正确的位置,有些数则只能修改,统计这一列如果移动 k 次(0 <= k <= n - 1)有多少数不需要修改

    设第 i 行第 j 列的数为 x,若 x <= n * m && (x - j) % m == 0, 说明 x 在目标状态中是第 j 列第 (x - j) / m + 1 行的数,(注意这里一定要判断x <= n * m,比赛时没判断查了半天也没发现)

    可以通过 p = (i - (x - j) / m - 1 + n) % n 次移动操作使 x 在正确的位置(+ n 在 % n 是为了处理负数)并在计数数组 c 中使 c[p]++

    最后枚举移动次数 k,这一列需要的步骤 ans = min (k + n - c[k]),并将 ans 累加到最终答案res中

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N = 5e5;
    int a[N], mx;
    int c[N << 2];
    void build (int p, int l, int r) {
        if (l == r) {c[p] = l; return;}
        int mid (l + r >> 1);
        build (p << 1, l, mid), build (p << 1 | 1, mid + 1, r);
        c[p] = min (c[p << 1], c[p << 1 | 1]);
    }
    inline void update (int p, int l, int r, int pos, int val) {
    //    printf ("%d %d %d
    ", p, l, r);
        if (l == r) {c[p] = val; return;}
        int mid = l + r >> 1;
        pos <= mid ? update (p << 1, l, mid, pos, val) : update (p << 1 | 1, mid + 1, r, pos, val);
        c[p] = min (c[p << 1], c[p << 1 | 1]);
    }
    signed main() {
        int n, x;
        scanf ("%lld %lld", &n, &x);
        for (int i = 0; i < x; ++i) a[i] = i; mx = 0;
        build (1, 0, x - 1);
        for (int i = 1, y; i <= n; ++i) {
            scanf ("%lld", &y);
            if (y > 0) y %= x; a[y] += x;
            update (1, 0, x - 1, y, a[y]);
            printf ("%lld
    ", c[1]);
        }
        return 0;
    }
    

    F

    题意:在树上找三个点a,b,c,使a到b,b到c,c到a的路径上覆盖的边权之和最大(一条边算一次)

    先贪心求出一条直径,把直径上边权改为0,再从直径两个端点分别出发找距离最远的点取最大值

    #include <bits/stdc++.h>
    using namespace std;
    inline void read (int &x) {
        char ch = getchar(); x = 0;
        while (!isdigit(ch)) ch = getchar();
        while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar();
    }
    const int N = 2e5 + 10;
    int n;
    int cnt, to[N << 1], nxt[N << 1], h[N], d[N << 1];
    inline void add (int u, int v) {
        to[++cnt] = v, d[cnt] = 1, nxt[cnt] = h[u], h[u] = cnt;
    }
    int tmp, mx, c[N], fr[N], fd[N];
    void dfs (int u, int la, int deep) {
        if (deep > mx) mx = deep, tmp = u;
        for (int i = h[u]; i; i = nxt[i])
            if (to[i] != la) fr[to[i]] = u, fd[to[i]] = i, dfs (to[i], u, deep + d[i]);
    }
    int res;
    signed main() {
        read (n); cnt = 1;
        for (int i = 1, u, v; i < n; ++i)
            read (u), read (v), add (u, v), add (v, u);
        dfs (1, 0, 0); mx = 0; fr[tmp] = 0;
        int a = tmp; dfs (tmp, 0, 0); int b = tmp; res = mx;
        while (fr[tmp]) d[fd[tmp]] = d[fd[tmp] ^ 1] = 0, tmp = fr[tmp];
        mx = 0; tmp = 0;
        dfs (a, 0, 0); dfs (b, 0, 0);
        int c = tmp; if (!c) c = 1;
        while (c == a || c == b) ++c;
        printf ("%d
    ", mx + res);
        printf ("%d %d %d
    ", a, b, c);
        return 0;
    }
    
  • 相关阅读:
    Linux下vim中文乱码问题
    phoniex初始化
    [Android] 修改ImageView的图片颜色
    [osx] android studio下修改avd的hosts文件
    [osx] 设置crontab
    [osx] 查看端口被占用
    [Ubuntu] change mouse scrolling between standard and natural
    [Vuejs] 关于vue-router里面的subRoutes
    [nodejs] Error: unable to verify the first certificate
    [SublimeText] 安装包管理
  • 原文地址:https://www.cnblogs.com/whx666/p/12446151.html
Copyright © 2020-2023  润新知