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;
}
标签:2020.08,cnt,合宿,OI,int,res,scanf,MXN,++ 来源: https://www.cnblogs.com/mxxr/p/13522900.html