C - Maximize GCD(简单数论)

C - Maximize GCD

给定长度为 n , ( 2 ≤ 3 × 1 0 5 ) n, (2 \le 3 \times 10 ^ 5) n,(23×105)的数组 a , ( 1 ≤ a i ≤ 3 × 1 0 5 ) a, (1 \le a_i \le 3 \times 10 ^ 5) a,(1ai3×105),一个数字 K , ( 1 ≤ K ≤ 1 0 18 ) K, (1 \le K \le 10 ^{18}) K,(1K1018)

我们可以对数组 a a a进行最多 k k k次操作,每次操作选定一个 i , ( 1 ≤ i ≤ n ) i, (1 \le i \le n) i,(1in)使 a i + 1 a_i + 1 ai+1,为数组最大的可能 g c d gcd gcd是多少。

我们设 m a x n = m a x ( { a 1 , … , a n } ) maxn = max(\{a_1, \dots, a_n\}) maxn=max({a1,,an}),如果最后的答案 a n s ans ans大于等于 m a x n maxn maxn,则一定有 i ∈ [ 1 , n ] , a i = a n s i \in [1, n], a_i = ans i[1,n],ai=ans

否则我们假设答案为 x x x,则判断是否合法:
∑ i = 1 n ⌈ a i x ⌉ × x − a i \sum_{i = 1} ^{n} \lceil\frac{a_i}{x}\rceil \times x - a_i\\ i=1nxai×xai
即上面那个式子求和是否小于等于 k k k,这个式子可以前缀和,无穷级数的复杂度算一下就好了,整体复杂度最高 m a x n log ⁡ m a x n maxn \log maxn maxnlogmaxn

#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] -> i
      cur += 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值