C - Maximize GCD
给定长度为n,(2≤3×105)n, (2 \le 3 \times 10 ^ 5)n,(2≤3×105)的数组a,(1≤ai≤3×105)a, (1 \le a_i \le 3 \times 10 ^ 5)a,(1≤ai≤3×105),一个数字K,(1≤K≤1018)K, (1 \le K \le 10 ^{18})K,(1≤K≤1018),
我们可以对数组aaa进行最多kkk次操作,每次操作选定一个i,(1≤i≤n)i, (1 \le i \le n)i,(1≤i≤n)使ai+1a_i + 1ai+1,为数组最大的可能gcdgcdgcd是多少。
我们设maxn=max({a1,…,an})maxn = max(\{a_1, \dots, a_n\})maxn=max({a1,…,an}),如果最后的答案ansansans大于等于maxnmaxnmaxn,则一定有i∈[1,n],ai=ansi \in [1, n], a_i = ansi∈[1,n],ai=ans。
否则我们假设答案为xxx,则判断是否合法:
∑i=1n⌈aix⌉×x−ai\sum_{i = 1} ^{n} \lceil\frac{a_i}{x}\rceil \times x - a_i\\ i=1∑n⌈xai⌉×x−ai
即上面那个式子求和是否小于等于kkk,这个式子可以前缀和,无穷级数的复杂度算一下就好了,整体复杂度最高maxnlogmaxnmaxn \log maxnmaxnlogmaxn。
#include <bits/stdc++.h>using namespace std;const int N = 3e5 + 10;int a[N], cnt[N], n, maxn;long long sum[N], k, s;int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);cin >> n >> k;for (int i = 1; i <= n; i++) {cin >> a[i];s += a[i], cnt[a[i]]++, sum[a[i]] += a[i];maxn = max(maxn, a[i]);}if (1ll * maxn * n - s <= k) {// x * n - sum <= k -> x * n <= k + sum -> x = (k + sum) / n;cout << (k + s) / n << "\n";return 0;}for (int i = 1; i <= maxn; i++) {cnt[i] += cnt[i - 1];sum[i] += sum[i - 1];}int ans = 1;for (int i = 2; i < maxn; i++) {long long cur = 0;for (int j = i; j <= maxn; j += i) {// [j - i + 1, j] -> icur += 1ll * (cnt[j] - cnt[j - i]) * j - (sum[j] - sum[j - i]);}if (maxn % i) {int l = maxn / i * i, r = maxn;cur += 1ll * (cnt[r] - cnt[l]) * (maxn / i + 1) * i - (sum[r] - sum[l]);}if (cur <= k) {ans = i;}}cout << ans << "\n";return 0;
}