题目链接:https://codeforces.com/contest/1201
A - Important Exam
送分题。
B - Zero Array
题意:给一个数组,每次选两个不同位置的数字,然后同时-1。问是否能全部变成0。
题解:好像做过。首先和必须是偶数,其次最大的数字不能超过和的一半,这两个显然是必要条件,但是为什么这样就充分了呢?貌似可以归纳,每次取最大和次大同时-1,问题会变成和-2的,且最大的数字依然不超过和的一半的子问题,因为新的最大值要么是原本的最大值-1,要么原本有至少3个值都是原本的最大值,两种情况下新的最大值都不会超过和的一半。即:已知sum>=3x,求证x<=(sum-2)/2。显然当sum>=6时上式成立,当sum<6时,枚举掉这种情况即可。
void test_case() { int n; scanf("%d", &n); ll sum = 0, maxa = 0; while(n--) { ll x; scanf("%lld", &x); sum += x; maxa = max(maxa, x); } if(sum % 2 == 1 || maxa > sum / 2) puts("NO"); else puts("YES"); }
C - Maximum Median
题意:给一个奇数个数的数组,每次操作可以把一个数字+1,求最多k次操作能变到的最大的中位数。
题解:很明显有二分的做法:枚举中位数x,需要把中间及其之后的所有小于x的数变成x,求出这个花费是否超过k,求花费的时候还要再进行一次二分,带两个log。
int n, k, mid; int a[200005]; ll sum[200005]; bool check(int x) { int pos = lower_bound(a + 1, a + 1 + n, x) - a; --pos; if(pos < mid) return 1; int cnt = pos - mid + 1; ll cost = 1ll * (pos - mid + 1) * x - (sum[pos] - sum[mid - 1]); return cost <= k; } void test_case() { scanf("%d%d", &n, &k); for(int i = 1; i <= n; ++i) scanf("%d", &a[i]); sort(a + 1, a + 1 + n); for(int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + a[i]; mid = (n + 1) / 2; int L = a[mid], R = a[mid] + k; while(1) { int M = (L + R) >> 1; if(L == M) { if(L == R || check(R)) { printf("%d\n", R); return; } printf("%d\n", L); return; } if(check(M)) L = M; else R = M - 1; } }
但是居然T了。卡一下常数试试。最后发现是二分的时候加法溢出了。
int n, k, mid; int a[200005]; ll sum[200005]; bool check(ll x) { int pos = lower_bound(a + 1, a + 1 + n, x) - a; --pos; if(pos < mid) return 1; ll cost = 1ll * (pos - mid + 1) * x - (sum[pos] - sum[mid - 1]); return cost <= k; } void test_case() { scanf("%d%d", &n, &k); for(int i = 1; i <= n; ++i) scanf("%d", &a[i]); sort(a + 1, a + 1 + n); for(int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + a[i]; mid = (n + 1) / 2; ll L = a[mid], R = a[mid] + k; while(1) { ll M = (L + R) >> 1; if(L == M) { if(L == R || check(R)) { printf("%d\n", R); return; } printf("%d\n", L); return; } if(check(M)) L = M; else R = M - 1; } }
启示:上了1e9的都用ll比较好,说不定哪天就溢出了。在二分lower_bound的时候起点其实不一定要是1,直接从mid开始也可以,不过也就快了一次?
挑战一下主体部分线性的做法,因为这题自带一个排序,本身的一个log是逃不掉的。
来源:https://www.cnblogs.com/KisekiPurin2019/p/12448054.html