1. 程式人生 > 實用技巧 >SSL-OI夏日合宿 2020.08.18

SSL-OI夏日合宿 2020.08.18

SSL-OI夏日合宿 2020.08.18

今天大佬們都去打NOI網路同步賽了, 就我一個沒報名QwQ.

於是就只有一個組別, 好像題還挺簡單.(不是

然後就被初一爆踩了 /doge

T1 分火腿

題意

給出\({n}\)根火腿, 要求切成大小相等的\({m}\)份. 求最小切幾刀.

故事

顯然這是一道給小學生寫的水題. 對於每\((n,m)\)根火腿, 我們都可以少切一刀. 於是直接輸出\((m-1)-((n,m)-1)\)\(m-(n,m)\)就好.

#include <stdio.h>

int T;

int gcd(int a, int b) { return (b == 0) ? (a) : gcd(b, a % b); }

signed main() {
    freopen("A.in", "r", stdin);

    scanf("%d", &T);

    for (int i, n, m; T-- > 0;)
        scanf("%d%d", &n, &m), printf("%d\n", m - gcd(n, m));

    return 0;
}

實際上這也是正解.

T2 工資

題意

給出一個數組\(arr\), 最多劃分成\(m\)塊. 對劃分出的每一塊求和, 求最大值最小.

故事

T2就開始不會了QwQ.

求最大值最小的問題一般就二分答案吧? 那麼我們對於二分出的最大值\(lim\), 貪心地遍歷\(arr\), 一旦求和超過\(lim\)就另起一段. 總覺得貪心哪裡不對, 但又不會證, 也想不出更好的方法.

#define MXN (100020)

#include <stdio.h>

#include <algorithm>

int n, m;
long long a[MXN];

int check(int lim) {
    int res = 1, i = 0, cnt = 0;
    for (; i < n; ++i)
        if ((cnt += a[i]) > lim)
            cnt = a[i], ++res;
        else if (cnt == lim)
            cnt = 0, ++res;
    return res;
}

long long l, r = MXN * MXN, md;

signed main() {
    freopen("B.in", "r", stdin);
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; ++i)
        scanf("%lld", &a[i]), l = std::max(l, a[i]);

    while (l < r) {
        if (check(md = (l + r) / 2) <= m)
            r = md;
        else
            l = md + 1;
    }

    printf("%d", r);

    return 0;
}

結果WA90? 奇奇怪怪.

T3 欠扁的CD

題意

給出\(n\)個數, 從中選\(k\)個, 使他們的\(gcd\)最大.

故事

T3就已經完全不會了, 於是乎沒有故事...

正解

好像果然是讀題的問題, 如果多讀幾遍說不定就讀懂了. 不出意外地, 這題也是大水題.

我們開一個\(500000\)的陣列, 記錄每個值出現的次數. 再從大到小列舉答案\(ans\), 然後統計它的所有倍數出現次數的和, 若大於等於\(k\)即為答案. 是的, 正解非常暴力.

複雜度為\(O(N\log{N})\).

#define MXN (500020)

#include <stdio.h>

#include <algorithm>

int n, k, top, ans;
int cnt[MXN];

signed main() {
    freopen("C.in", "r", stdin);

    scanf("%d%d", &n, &k);

    for (int i = 0, x; i < n; ++i)
        scanf("%d", &x), ++cnt[x], top = std::max(top, x);

    for (int i = top, j, res; i > 0; --i) {
        for (j = i, res = 0; j <= top; ++j)
            res += cnt[j];
        if (res >= k) {
            ans = i;
            break;
        }
    }

    printf("%d", ans * k);

    return 0;
}