W
H
X

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\n", 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\n", 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\n", 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\n", 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\n", 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\n", mx + res);
    printf ("%d %d %d\n", a, b, c);
    return 0;
}
posted @ 2020-03-09 00:41  -敲键盘的猫-  阅读(220)  评论(0编辑  收藏  举报