《如 何 速 通 一 套 题》 10.0

邮寄

菜到不能再菜的 hhc 一个题都不会,光速撤退了。

A

nm 没想到只要 \(S\) 中有一种数出现了奇数次 C 必胜。

然后直接 xorhash 就可以了。

#include <bits/stdc++.h>
#define int unsigned long long
using namespace std;

struct node {
  int v, w;
};

int t, n, u, v, w, d[500050], ans;
vector<node> to[500050];
map<int, int> cnt;

int qpow(int x, int y) {
  int rs = 1;
  for(; y; y >>= 1) {
    if(y & 1) {
      rs *= x;
    }
    x *= x;
  }
  return rs;
}

void DFS(int x = 1, int pa = 0) {
  cnt[d[x]]++;
  for(auto i : to[x]) {
    if(i.v != pa) {
      d[i.v] = d[x] ^ qpow(11451, i.w);
      DFS(i.v, x);
    }
  }
}

signed main() {
  freopen("game.in", "r", stdin);
  freopen("game.out", "w", stdout);
  for(cin >> t; t--; ) {
    cin >> n;
    for(int i = 1; i < n; i++) {
      cin >> u >> v >> w;
      to[u].push_back({v, w});
      to[v].push_back({u, w});
    }
    DFS();
    ans = n * (n - 1) / 2;
    for(auto i : cnt) {
      ans -= i.second * (i.second - 1) / 2;
    }
    cout << ans << '\n';
    for(int i = 1; i <= n; i++) {
      to[i].clear();
      d[i] = 0;
    }
    cnt.clear();
  }
  return 0;
}

B 跳跃

我们充分发挥人类智慧,猜测答案一定会在前 \(5000\) 轮内更新完。

直接暴力 dp 即可。

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

const int kInf = 1e17;

int t, n, k, dp[1010], arr[1010], sum[1010], ml[1010], mr[1010];

signed main() {
  freopen("jump.in", "r", stdin);
  freopen("jump.out", "w", stdout);
  for(cin >> t; t--; ) {
    cin >> n >> k;
    for(int i = 1; i <= n; i++) {
      cin >> arr[i];
      sum[i] = sum[i - 1] + arr[i];
    }
    int m = 0;
    for(int i = 1; i <= n; i++) {
      ml[i] = sum[i] - m;
      m = min(m, sum[i]);
    }
    m = -kInf;
    for(int i = n; i >= 1; i--) {
      m = max(m, sum[i]);
      mr[i] = m - sum[i - 1];
    }
    fill(dp + 1, dp + n + 1, -kInf);
    dp[1] = 0;
    int ans = 0;
    for(int i = 1; i <= min(k, 5000ll); i++) {
      if(i & 1) {
        int mx = -kInf;
        for(int j = 1; j <= n; j++) {
          mx = max(mx, dp[j] - sum[j - 1]);
          dp[j] = mx + sum[j];
          if(dp[j] < 0) {
            dp[j] = -kInf;
          }
          ans = max(ans, dp[j] + (k - i) * ml[j]);
        }
      }else {
        int mx = -kInf;
        for(int j = n; j >= 1; j--) {
          mx = max(mx, dp[j] + sum[j]);
          dp[j] = mx - sum[j - 1];
          if(dp[j] < 0) {
            dp[j] = -kInf;
          }
          ans = max(ans, dp[j] + (k - i) * mr[j]);
        }
      }
    }
    cout << ans << '\n';
  }
  return 0;
}

C 大陆

可以观察到每一个省要么是一个连通块,要么加上一个省会后变成连通块。

所以我们 DFS,并且启发式合并维护每一个点上还没有分好省的节点的集合(开一个 set),并在集合大小 \(\ge B\) 时把 set 里面的所有节点全部分为一个省,省会为当前节点。

可以证明这样一定可以构造出来(省大小 \(\le 2 * B\))。

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

int n, k, u, v, fs[10010], cnt, bel[10010];
vector<int> to[10010], ps[10010];
set<int> st[10010];

void trigger(int x) {
  if(st[x].size() >= k) {
    cnt++;
    for(auto i : st[x]) {
      //ps[cnt].push_back(i);
      bel[i] = cnt;
    }
    fs[cnt] = x;
    st[x].clear();
  }
}

void DFS(int x = 1, int pa = 0) {
  for(auto i : to[x]) {
    if(i != pa) {
      DFS(i, x);
      if(st[x].size() < st[i].size()) {
        swap(st[x], st[i]);
      }
      for(auto j : st[i]) {
        st[x].insert(j);
      }
      st[i].clear();
      trigger(x);
    }
  }
  st[x].insert(x);
  trigger(x);
}

int main() {
  freopen("mainland.in", "r", stdin);
  freopen("mainland.out", "w", stdout);
  cin >> n >> k;
  for(int i = 1; i < n; i++) {
    cin >> u >> v;
    to[u].push_back(v);
    to[v].push_back(u);
  }
  DFS();
  cout << cnt << '\n';
  for(int i = 1; i <= n; i++) {
    cout << bel[i] << ' ';
  }
  cout << '\n';
  for(int i = 1; i <= cnt; i++) {
    cout << fs[i] << ' ';
  }
  cout << '\n';
  return 0;
}
posted @ 2024-10-03 21:36  hhc0001  阅读(11)  评论(0)    收藏  举报