CF2090 A-F1

赛时只做了 A-D,赛后看了家乐的码把剩下的题改了

A. Treasure Hunt

比较 \(a\bmod (x+y)\)\(x\) 的大小即可

时间复杂度:\(O(1)\)

cin >> x >> y >> a, t = x + y, a %= t;
pr(a >= x);

B. Pushing Balls

一个点一定是从右往左或从上往下堆起来的,那么如果右边或下面有空格则一定无解。否则一定可以找出一种可行解

时间复杂度:\(O(n^3)\)(假定 \(n,m\) 同阶)

cin >> n >> m;
for (int i = 1; i <= n; i++) {
  for (int j = 1; j <= m; j++) {
    cin >> ch, a[i][j] = ch - '0';
  }
}
for (int i = 1; i <= n; i++) {
  for (int j = 1; j <= m; j++) {
    if (a[i][j] == 1) {
      bool F = 1, G = 1;
      for (int k = 1; k < i; k++) {
        F &= a[k][j];
      }
      for (int k = 1; k < j; k++) {
        G &= a[i][k];
      }
      ans &= (F || G);
    }
  }
}
pr(ans);

C. Dining Hall

link

D. Simple Permutation

考虑让连续一段的 \(c_i\) 是同一个数,找到最大的质数 \(k\) 使得 \(2k \le n\),那么在 \(p_{1\sim 2k}\) 中直接最小最大交替放。就可以最大化 \(c_i=k\) 的个数,剩下的数直接 \(p_i=i\) 即可

时间复杂度:\(O(n)\)

cin >> n, ans = n / 3 - 1;
for (int i = n; i; i--) {
  if (!vis[i / 2]) {
    lim = i / 2;
    break;
  }
}
for (int i = 1; i <= lim; i++) {
  a[i * 2 - 1] = b[i], a[i * 2] = b[lim * 2 - i];
}
for (int i = lim * 2; i <= n; i++) {
  a[i] = i;
}
int cnt = 0, t = 0;
for (int i = 1; i <= n; i++) {
  cnt += a[i];
  t += !vis[(cnt + i - 1) / i];
  cout << a[i] << " \n"[i == n];
}

E. Canteen

E1 和 E2 基本一样,\(-1\) 的操作进行的时间不重要,于是可以计算 \(\sum a_i\),在操作的过程中将 \(\text{sum}\) 同时减去,当 \(\text{sum}\le k\) 时直接输出答案

用两个 set 存下两个数组中非零的数,每一轮对于 a 中的数在 blower_bound,如果找到了则直接对应删除

时间复杂度:\(O(n\log n)\)

cin >> n >> k;
for (int i = 1; i <= n; i++) {
  cin >> a[i], sum += a[i], a[i] && (s[0].insert(i), 0);
}
for (int i = 1; i <= n; i++) {
  cin >> b[i], b[i] && (s[1].insert(i), 0);
}
for (int i = 0; i <= n + 2; i++) {
  if (sum <= k) {
    cout << i << '\n';
    break;
  }
  tmp.clear();
  for (auto L = s[0].begin(), R = s[1].begin(); !s[0].empty();) {
    L == s[0].end() && (L = s[0].begin(), 0);
    if (tmp.count(*L)) {
      break;
    }
    tmp.insert(*L), R = s[1].lower_bound(((*L + i - 1) % n) + 1);
    if (R == s[1].end() || *R != ((*L + i - 1) % n) + 1) {
      if (s[1].empty()) {
        break;
      }
      R == s[1].end() && (R = s[1].begin(), 0), L = s[0].lower_bound(((*R + n - i - 1) % n) + 1);
    } else {
      o = min(a[*L], b[*R]), a[*L] -= o, b[*R] -= o, sum -= o;
      if (!a[*L]) {
        L = s[0].erase(L), !b[*R] && (R = s[1].erase(R), 0);
      } else {
        R = s[1].erase(R);
        if (s[1].empty()) {
          break;
        }
        R == s[1].end() && (R = s[1].begin(), 0), L = s[0].lower_bound(((*R + n - i - 1) % n) + 1);
      }
    }
  }
}

F1. Key of Like (Easy Version)

枚举每一轮钥匙的选择,根据小学奥数知识,在剩下 \(k\) 把锁时接下来 \(k\) 个人开锁成功的概率都是 \(\frac{1}{k}\),但是需要考虑 \(k>n\) 的情况,那么有些人的概率会增加,但解决方法直接向 \(n\) 取模即可。但是需要用树状数组维护概率的差分来计算

时间复杂度:\(O(nk\log^2 n)\)

cin >> n >> k >> Joler_Is_SB, v[n] = 1, tr.sz = k + n << 2;
for (int i = k; i; i--) {
  for (int j = 1; j <= n; j++) {
    tr.update(j + 1, v[j] * P(i, kP - 2) % kP), tr.update(j + i + 1, kP - (v[j] * P(i, kP - 2) % kP));
  }
  fill(v, v + n + 2, 0);
  for (int j = 1; j <= n; j++) {
    for (int l = j; l <= n + k + 1; l += n) {
      (v[j] += tr.query(l)) %= kP;
    }
    (ans[j] += v[j]) %= kP;
  }
  tr.init();
}
for (int i = 1; i <= n; i++) {
  cout << ans[i] << " \n"[i == n];
}

家乐也不会 F2,哈哈哈哈哈哈哈

posted @ 2025-03-26 19:57  BluemoonQwQ  阅读(22)  评论(0)    收藏  举报