Div3

CF 2008 G

题目描述

给定一个 \(N\) 个整数的数组,你可以选择 \(i\ne j\) 并使 \(A_i\leftarrow A_i+A_j\)\(A_i\leftarrow A_i-A_j\)

求经过若干次操作后的第 \(k\) 小的不出现在数组中的非负整数的最大值。

思路

根据裴蜀定理,我们可知所有能变成的数均为整个数组的 \(\gcd\) 的倍数,所以最有情况下数组就是 \(0,\gcd,2\gcd,\dots,(N-1)\gcd\)。按照这种方案求解即可。

空间复杂度 \(O(1)\),时间复杂度 \(O(N\log \max\{A_i\})\)

代码

#include<bits/stdc++.h>
using namespace std;

int T, n, k, g;

int gcd(int a, int b) {
  return (!b ? a : gcd(b, a % b));
}

void Solve() {
  cin >> n >> k;
  g = 0;
  int x;
  for(int i = 1; i <= n; ++i) {
    cin >> x;
    g = gcd(x, g);
  }
  if(n == 1) {
    cout << k + (k > x) - 1 << "\n";
    return;
  }
  cout << min(n, (g == 1 ? n : (k + g - 2) / (g - 1))) + k - 1 << "\n";
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  for(cin >> T; T--; Solve()) {
  }
  return 0;
}

CF 2008 H

题目描述

给定一个长度为 \(N\) 的序列 \(A\),以及 \(Q\) 次询问,每次询问给定一个 \(x\)

你可以执行以下操作任意次:

  • 选择一个 \(1\le i \le N\) 使得 \(A_i \ge x\)
  • \(A_i \leftarrow A_i - x\)

\(A\) 的最小中位数。

这里中位数是 \(A\) 排序后的第 \(\lfloor \frac{n}{2}\rfloor+1\) 个元素。

思路

很显然,令一个 \(A_i-x\) 一定不会使答案更劣,所以肯定会把所有操作进行到底,也就是 \(A_i\leftarrow A_i \bmod x\)。然后让你求这种情况下的中位数。

首先对 \(A_i\) 的值做一个前缀和。对于每个 \(x\),二分其中位数。

二分的 check 也很简单,直接枚举 \(x\) 的倍数 \(y\),求 \(y\)\(y+mid\) 有多少个数,如果总数 \(\ge \lfloor \frac{n}{2}\rfloor+1\) 则合法,否则不合法。

这样的时间复杂度是 \(O(N\log^2 N)\),因为这里面是一个调和级数,所以时间不会炸。

空间复杂度 \(O(N)\),时间复杂度 \(O(N \log^2 N + Q)\)

代码

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 100005;

int T, n, q, a[MAXN], sum[MAXN], ans[MAXN];

bool check(int x, int y) {
  int res = 0;
  for(int i = 0; i * x <= n; ++i) {
    res += sum[min(n, i * x + y)] - (i * x - 1 >= 0 ? sum[i * x - 1] : 0);
  }
  return res >= n / 2 + 1;
}

int Binary_Search(int x) {
  int l = 0, r = x - 1;
  for(; l < r; ) {
    int mid = (l + r) >> 1;
    (check(x, mid) ? r = mid : l = mid + 1);
  }
  return l;
}

void Solve() {
  cin >> n >> q;
  for(int i = 1; i <= n; ++i) {
    sum[i] = 0;
  }
  for(int i = 1; i <= n; ++i) {
    cin >> a[i];
    sum[a[i]]++;
  }
  for(int i = 1; i <= n; ++i) {
    sum[i] += sum[i - 1];
  }
  for(int i = 1; i <= n; ++i) {
    ans[i] = Binary_Search(i);
  }
  for(int i = 1, x; i <= q; ++i) {
    cin >> x;
    cout << ans[x] << " \n"[i == q];
  }
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  for(cin >> T; T--; Solve()) {
  }
  return 0;
}
posted @ 2024-09-28 15:28  Yaosicheng124  阅读(4)  评论(0编辑  收藏  举报