SSL-OI夏日合宿 2020.08.18
阿新 • • 發佈: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; }