2019-2020 ICPC, NERC, Southern and Volga Russian Regional Contest (Online Mirror, ICPC Rules, Teams Preferred)
题目链接:https://codeforces.com/contest/1250
B - The Feast and the Bus
题意:有n个人,每个人分别属于某个队伍,共有k个队伍。要租车,要求至多两个队伍坐同一次车,不能有多于三个队伍在同一次车上。同一个队伍的人不能分开。设车的容量为s,要开的次数为r,花费为s*r,求最小的花费。
题解:想了一个n+k^2的题解?统计好每个人的队伍的siz之后按照siz排序,显然要两个队伍坐同一次车的,是siz最小的连续一段的偶数个队伍。因为换个siz大的队伍进来只会徒增车的容量。且这些拼车的队伍肯定是首尾拼接。看了下复杂度刚好够。
int n, k;
int siz[8005];
void test_case() {
scanf("%d%d", &n, &k);
while(n--) {
int x;
scanf("%d", &x);
++siz[x];
}
sort(siz + 1, siz + 1 + k);
ll ans = 1ll * siz[k] * k;
for(int i = 2; i <= k; i += 2) {
int maxsiz = siz[k];
for(int j = 1; j <= i / 2; ++j)
maxsiz = max(maxsiz, siz[j] + siz[i + 1 - j]);
ans = min(ans, 1ll * maxsiz * (i / 2 + k - i));
}
printf("%lld\n", ans);
}
收获:为什么最小的一定是首尾拼接呢?可以从1+4=2+3看出一点端倪。设a1<=a2<=a3<=a4,且a2=a1+d2,a3=a1+d3,a4=a1+d4则max(a1+a4,a2+a3)=
max(2a1+d4,2a1+d2+d3)=2a1+max(d4,d2+d3)。其他的几种组合:max(d3,d2+d4)显然d2+d4>=d2+d3且d2+d4>=d4。max(d2,d3+d4)同理。
J - The Parade
题意:有n种数字,第i种数字有ci个。要求分为恰好k行,每行的数字的个数相等,且同一行的数字两两之间的差不超过1。求最多选出多少个数字。
题解:很显然是满足单调性的(能选出多的数字,就全部砍掉一部分,就变成少的数字)。二分答案,然后根据“同一行的数字两两之间的差不超过1”来check。
int n;
ll k;
ll cnt[30005], sum;
bool check(ll x) {
if(x == 0)
return true;
ll pre = 0, r = 0;
for(int i = 1; i <= n; ++i) {
ll cur = pre + cnt[i];
if(cur >= x) {
r += cur / x;
pre = cur % x;
} else
pre = cnt[i];
}
return r >= k;
}
ll bs() {
ll L = 0, R = sum / k;
while(1) {
ll M = (L + R) / 2;
if(L == M) {
if(check(R))
return R * k;
else
return L * k;
}
if(check(M))
L = M;
else
R = M - 1;
}
}
void test_case() {
scanf("%d%lld", &n, &k);
sum = 0;
for(int i = 1; i <= n; ++i) {
scanf("%lld", &cnt[i]);
sum += cnt[i];
}
printf("%lld\n", bs());
}
反思:除以一个可以为零的数之前都要先特判。或者当初定二分的上下界都要定为正数。然后不存在的时候就输出0。
K - Addition Robot
题意:维护一个数据结构。这个数据结构本身存有一个01串。操作1:[L,R],把[L,R]中的串翻转。操作2:(L,R,A,B):遍历[L,R]中的串,遇到一个0,执行:A=A+B,遇到一个1,执行B=B+A。输出每次操作2后的A和B。
题解:看起来就很线段树。