「赛后总结」Codeforces Round #680 (Div. 2)

题目/题解

A. Array Rearrangment

题意:

给定两个序列 \(a,b\) 和一个数 \(x\),判断能否对 \(b\) 进行排序使得 \(\forall \ i \in[1,n]\)\(a_i+b_i \le x\)

题解:

\(a\) 升序排列,\(b\) 降序排列。

\(m_a\)\(a\) 中最小的,\(m_b\)\(b\) 中最大的,如果 \(p+m_b\le x\) 并且 \(m_a + q \le x\)\(m_a\le p\)\(q \le m_b\)),那么 \(m_a+m_b\le x\)\(p+q\le x\)。可知不会变差。

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define M 51

int t, n, m, a[M], b[M];

bool cmp(int x, int y) {
    return x > y;
}

int main() {
    scanf("%d", &t);
    while (t--) {
        scanf("%d %d", &n, &m); bool flag = true;
        for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        for (int i = 1; i <= n; ++i) scanf("%d", &b[i]);
        std::sort(a + 1, a + n + 1), std::sort(b + 1, b + n + 1, cmp);
        for (int i = 1; i <= n; ++i) {
            if (a[i] + b[i] > m) {
                flag = false;
                puts("No");
                break;
            }
        }
        if (flag) puts("Yes");
    }
    return 0;
}

B. Elimination

题意:

两场比赛,排名按分数降序。知道第一场比赛的第一百名选手第一场得分为 \(a\),并且前一百名选手第二场比赛的得分不低于 \(b\)。知道第二场比赛的第一百名选手第二场比赛的得分为 \(c\),并且前一百名选手第一场比赛的得分不低于 \(d\)。求总分第一百名分最少是多少。

题解:

已知有一百人总分不低于 \(a+b\),一百人总分不低于 \(c+d\),所以总分第一百名分最少为 \(\max(a+b,c+d)\)

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>

int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }

int t, a, b, c, d;

int main() {
    std::cin >> t;
    while (t--) {
        std::cin >> a >> b >> c >> d;
        std::cout << max(a + b, c + d) << '\n';
    }
    return 0;
}

C. Division

题意:

多测,给定 \(p,q\),求出一个最大的 \(x\) 使得 \(x\mid p\) 并且 \(q\nmid x\)

\(1 \leq p \leq 10^{18}\)\(1 \leq q \leq 10^9\)

题解:

对于 \(p < q\) 的情况答案是 \(p\)

对于 \(p \ge q\) 的情况,如果 \(q \nmid p\) 答案是 \(p\)

如果 \(q \mid p\),对 \(p,q\) 分解质因数。

\(p = {p_1}_{a_1}\times {p_2}^{a_2}\times \dots \times {p_k} ^{a_k}\)

\(q = {p_1}_{b_1}\times {p_2}^{b_2}\times \dots \times {p_k} ^{b_k}\)

因为 \(q \mid p\) 所以 \(\forall \ i \in[1,k]\)\(a_i\ge b_i\),目的就是找一个最小的除数 \(d\) 使得 \(\dfrac{p}{d}\)(对 \(d\) 分解质因数指数记为 \(c\))不再满足 \(\forall \ i \in[1,k]\)\(a_i\ge b_i - c_i\)

最小的 \(d\) 可以在对 \(q\) 分解质因数的过程中求出。

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>

typedef long long ll;
inline void read(ll &T) {
    ll x = 0;
    bool f = 0;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') f = !f;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    T = f ? -x : x;
}

int t;
ll p, q;

ll qpow(int a, int b) {
    ll ans = 1, base = a;
    while (b) {
        if (b & 1) ans = base * ans;
        base = base * base;
        b >>= 1;
    }
    return ans;
}

ll div(ll x, ll y) {
    ll minn = 1e18;
    for (int i = 2; i * i <= x; ++i) {
        if (x % i == 0) {
            int t1 = 0, t2 = 0;
            while (x % i == 0) x /= i, ++t1;
            bool flag = false;
            while (y % i == 0) {
                flag = true;
                y /= i;
                ++t2;
            }
            ll tot = qpow(i, t2 - t1 + 1);
            if (flag && tot < minn) minn = tot;
        }
    }
    if (x != 1 && y % x == 0) {
        int t = 0;
        bool flag = false;
        while (y % x == 0) {
            flag = true;
            y /= x;
            ++t;
        }
        ll tot = qpow(x, t);
        if (flag && tot < minn) minn = tot;
    }
    return minn;
}

int main() {
    scanf("%d", &t);
    while (t--) {
        read(p), read(q);
        if (p < q) std::cout << p << '\n';
        if (p >= q) {
            if (p % q == 0) std::cout << p / div(q, p) << '\n';
            else std::cout << p << '\n';
        }
    }
    return 0;
}

D. Divide and Sum

题意:

给一个 \(2n\) 长的序列,将其随意分成两个长为 \(n\) 的序列 \(p,q\)\(p\) 按不减小的顺序排列,\(q\) 按不增加的顺序排列。计算每种分法的 \(\sum\limits_{i=1}^{n} \mid p_i-q_i \mid\) 的和。

题解:

将原序列升序排序后分成两半,前面记为 \(L\),后面记为 \(R\),结论为不论怎么划分序列,贡献都是 \(\mid R-L\mid\)

证明
假设存在一个位置 \(i\) 使得 \(p_i,q_i\) 都属于 \(L\)
\(p\) 的前 \(i\) 个元素都属于 \(L\)
\(q\) 的后面 \(n-i+1\) 个元素也都属于 \(L\)
那么 \(L\) 中的元素至少有 \(n + 1\) 个,与事实不符。
证毕。

序列的分法一共有 \(C_{2n}^{n}\) 种,答案就是 \(C_{2n}^{n} \times \mid R-L\mid\)

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define M 300001
#define int long long

int mod = 998244353;
int n, a[M], sum[M];

int qpow(int a, int b) {
    int ans = 1, base = a;
    while (b) {
        if (b & 1) ans = base * ans % mod;
        base = base * base % mod;
        b >>= 1;
    }
    return ans % mod;
}

signed main() {
    scanf("%d", &n);
    for (int i = 1; i <= 2 * n; ++i) scanf("%d", &a[i]);
    std::sort(a + 1, a + 2 * n + 1);
    for (int i = 1; i <= 2 * n; ++i) {
        sum[i] = (sum[i - 1] + a[i]) % mod;
    }
    int fm, fz = 1;
    for (int i = 1; i <= 2 * n; ++i) {
        fz = fz * i % mod;
        if (i == n) fm = fz * fz % mod;
    }
    fm = qpow(fm, mod - 2);
    int mul = ((sum[2 * n] - sum[n]) - sum[n] + 10 * mod) % mod;
    std::cout << mul * (fz * fm % mod) % mod << '\n';
    return 0;
}
posted @ 2020-11-02 07:55  yu__xuan  阅读(180)  评论(0编辑  收藏  举报