[比赛记录] Codeforces Round #680 Div. 2

传送🚪

A. Array Rearrangment

\(a\) 从小到大排序, \(b\) 从大到小排序, 对所有 \(a_i + b_i\) 判断它们是否小于等于 \(x\) 即可.

#include <algorithm>
#include <cstdio>
#include <iostream>

using namespace std;

const int _ = 50 + 7;

int n, X, a[_], b[_];

bool cmp(int i, int j) { return i > j; }

int main() {
  int T;
  cin >> T;
  while (T--) {
    cin >> n >> X;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    for (int i = 1; i <= n; ++i) cin >> b[i];
    sort(a + 1, a + n + 1);
    sort(b + 1, b + n + 1, cmp);
    bool flag = 1;
    for (int i = 1; i <= n; ++i)
      if (a[i] + b[i] > X) { flag = 0; break; }
    puts(flag ? "Yes" : "No");
  }
  return 0;
}

B. Elimination

结论: 答案为 \(\max(a + b, c + d)\).

证明:

\(a + b > c + d\).

必要性: 因为现在已知至少有 100 个人的分数是大于等于 \(a+b\) 的, 所以如果一个人的分数小于 \(a+b\), 那他肯定不能在前 100 名内.

充分性: 因为 \(c+d < a+b\), 所以我们可以使第二场排名中的所有人的第一场得分为 \(c\),第二场得分为 \(d\), 并使第一场排名在 100 后的人的分数都小于 \(a +b\), 那么 \(a+b\) 就能进入前 100 名.

#include <cstdio>
#include <iostream>

using namespace std;

int T, a, b, c, d;

int main() {
  cin >> T;
  while (T--) {
    cin >> a >> b >> c >> d;
    cout << max(a + b, c + d) << endl;
  }
  return 0;
}

C. Division

考场上因为写法太 sb 导致炸了 long long, 然后就 gg 了

首先, 如果 \(q \not \mid p\) , 直接输出 \(p\) 即可.

如果要满足 \(q \not \mid x\), 那么 \(q\) 必然有一个 \(x\) 没有的因子 \(d\), 又因为 \(q \mid p\), 所以 \(p\) 除去 \(d\) 后就是一个合法的 \(x\). 枚举所有 \(d\) 后取个最大值就行了.

#include <cstdio>
#include <iostream>

using namespace std;

typedef long long ll;

int T;
ll p, q, x;

int main() {
  cin >> T;
  while (T--) {
    cin >> p >> q;
    if (p % q) { cout << p << endl; continue; }
    x = 0;
    for (int i = 1; i * i <= q; ++i)
      if (!(q % i)) {
        if (i != 1) {
          ll tmp = p; while (!(tmp % q)) tmp /= i;
          x = max(x, tmp);
        }
        ll tmp = p; while (!(tmp % q)) tmp /= q / i;
        x = max(x, tmp);
      }
    cout << x << endl;
  }
  return 0;
}

D. Divide and Sum

一道奇(shen)妙(xian)的题目.

结论: 所有分组的贡献都是一样的.

证明:

先假设所有 \(a_i\) 互不相同. 相同的情况可以感性推得.

先把 \(a\) 从小到大排序, 假设 \(i > j > n\) 并且 \(|a_i - a_j|\) 对答案有贡献, 那么就要有 \(n\) 个数大于 \(a_j\), 与 \(j > n\) 相矛盾. 所以不存在这种情况. \(n > i > j\) 的情况也类似.

所以, 对答案做出贡献的点对只可能是 \(i > n,\ j < n\) 的情况.

所以所有分组的贡献都是后 \(n\)\(a_i\) 的和 - 前 \(n\)\(a_i\) 的和, 答案乘个 \(\binom{2n}{n}\) 就好了.

#include <algorithm>
#include <cstdio>
#include <iostream>

using namespace std;

typedef long long ll;

const int _ = 3e5 + 7;
const int mod = 998244353;

int n, a[_], sum[2], fac[_], inv[_], ifac[_];

int main() {
  cin >> n, n += n;
  fac[0] = ifac[0] = 1, inv[1] = 1;
  for (int i = 1; i <= n; ++i) {
    cin >> a[i];
    fac[i] = (ll)fac[i - 1] * i % mod;
    if (i != 1) inv[i] = (ll)inv[mod % i] * (mod - mod / i) % mod;
    ifac[i] = (ll)ifac[i - 1] * inv[i] % mod;
  }
  sort(a + 1, a + n + 1);
  for (int i = 1; i <= n / 2; ++i) sum[0] = (sum[0] + a[i]) % mod;
  for (int i = n / 2 + 1; i <= n; ++i) sum[1] = (sum[1] + a[i]) % mod;
  cout << (ll)(sum[1] - sum[0] + mod) * fac[n] % mod * ifac[n / 2] % mod * ifac[n / 2] % mod << endl;
  return 0;
}

E. Team-Building

先 bfs 一遍, 把有奇环的颜色判掉, 并对每个联通块求出它的染色关系, 可以用并查集维护连通块.

然后枚举每一类端点颜色不同的边, 根据这些边的连边关系和之前求出的染色关系进行黑白染色即可.

(说起来好像很简单, 但是我调了一个半小时...)

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <vector>

#define pb push_back

using namespace std;

typedef long long ll;

const int _ = 5e5 + 7;
const int __ = 1e6 + 7;

int n, m, K, col[_], ol[_], nw[_], fa[_], box[__], cnt, pl[_], num;
bool ban[_];
ll ans;
vector<int> to[_], tt[_], p[_];
queue<int> q;
struct EDGE { int u, v; } e[_];

void Init() {
  cin >> n >> m >> K, num = K;
  for (int i = 1; i <= n; ++i) scanf("%d", &col[i]), p[col[i]].pb(i);
  for (int i = 1, x, y; i <= m; ++i) {
    scanf("%d%d", &x, &y);
    if (col[x] > col[y]) swap(x, y);
    to[x].pb(y), to[y].pb(x);
    e[i] = { x, y };
  }
}

int Find(int x) { return x == fa[x] ? x : fa[x] = Find(fa[x]); }

bool Bfs(int x) {
  while (!q.empty()) q.pop();
  ol[x] = 0, q.push(x);
  while (!q.empty()) {
    int u = q.front(); q.pop();
    int fu = Find(u), fv;
    for (int v: to[u]) {
      if (col[v] != col[x]) continue;
      fv = Find(v);
      if (fu != fv) fa[fv] = fu;
      if (ol[v] == -1) ol[v] = ol[u] ^ 1, q.push(v);
      else if (ol[v] == ol[u]) { ans -= num - 1, --num, ban[col[x]] = 1; return 1; }
    }
  }
  return 0;
}

void Dye(int x) {
  int pt = pl[x] + 1, fx = Find(x);
  while (Find(box[pt]) == fx) q.push(box[pt]), nw[box[pt]] = nw[x] ^ (ol[box[pt]] != ol[x]), ++pt;
  pt = pl[x] - 1;
  while (pt and Find(box[pt]) == fx) q.push(box[pt]), nw[box[pt]] = nw[x] ^ (ol[box[pt]] != ol[x]), --pt;
}

bool Work(int x) {
  while (!q.empty()) q.pop();
  nw[x] = 0, Dye(x), q.push(x);
  while (!q.empty()) {
    int u = q.front(); q.pop();
    for (int v: tt[u]) {
      if (nw[u] == nw[v]) return 1;
      else if (nw[v] == -1) nw[v] = nw[u] ^ 1, Dye(v), q.push(v);
    }
  }
  return 0;
}

bool cmp1(int i, int j) { return Find(i) == Find(j) ? i < j : Find(i) < Find(j); }

bool cmp(EDGE a, EDGE b) { return col[a.u] == col[b.u] ? col[a.v] < col[b.v] : col[a.u] < col[b.u]; }

void Run() {
  ans = (ll)K * (K - 1) / 2;
  
  memset(ol, -1, sizeof ol);
  for (int i = 1; i <= n; ++i) fa[i] = i;
  for (int i = 1; i <= K; ++i)
    for (int x: p[i])
      if (ol[x] == -1 and Bfs(x)) {
        break;
      }
  
  sort(e + 1, e + m + 1, cmp);
  for (int i = 1, j; i <= m; i = j) {
    j = i, cnt = 0;
    while (col[e[j].u] == col[e[i].u] and col[e[j].v] == col[e[i].v]) {
      box[cnt + 1] = e[j].u, box[cnt + 2] = e[j].v;
      cnt += 2, ++j;
    }
    if (col[e[i].u] == col[e[i].v] or ban[col[e[i].u]] or ban[col[e[i].v]]) continue;
    sort(box + 1, box + cnt + 1, cmp1);
    cnt = unique(box + 1, box + cnt + 1) - box - 1;
    for (int k = 1; k <= cnt; ++k) pl[box[k]] = k, nw[box[k]] = -1;
    for (int k = i; k < j; ++k) tt[e[k].u].pb(e[k].v), tt[e[k].v].pb(e[k].u);
    for (int k = i; k < j; ++k)
      if (nw[e[k].u] == -1 and Work(e[k].u)) { --ans; break; }
    for (int k = 1; k <= cnt; ++k) tt[box[k]].clear();
  }

  cout << ans << endl;
}

int main() {
  Init();
  Run();
  return 0;
}
posted @ 2020-11-02 10:02  BruceW  阅读(110)  评论(0编辑  收藏  举报