比赛链接:Here

AB水题,

C - management

题意:给一棵 AtCoder Beginner Contest 163 - 图1#card=math&code=N%282%5Cle%20N%5Cle2e5%29) 个节点的有根树,求每个节点的儿子数。

思路:由于输入直接给的是每个节点的父节点,直接计数即可。

  1. const int N = 2e5 + 10;
  2. int a[N];
  3. int main() {
  4. ios::sync_with_stdio(false), cin.tie(nullptr);
  5. int n; cin >> n;
  6. for (int i = 1, x; i < n; ++i)
  7. cin >> x, a[x] += 1;
  8. for (int i = 1; i <= n; ++i) cout << a[i] << "\n";
  9. }

D - Sum of Large Numbers

题意:当前有 AtCoder Beginner Contest 163 - 图2 个整数:AtCoder Beginner Contest 163 - 图3,求取不少于 AtCoder Beginner Contest 163 - 图4 个数的和的可能值的数量(mod 1e9+7)。

数据范围:AtCoder Beginner Contest 163 - 图5

思路:因为 AtCoder Beginner Contest 163 - 图6 明显很大,所以取 AtCoder Beginner Contest 163 - 图7 个总和不可能等于取 AtCoder Beginner Contest 163 - 图8 个数的综合,所以只需要枚举取多少个数即可。

对于取 AtCoder Beginner Contest 163 - 图9 个数可以求出取 AtCoder Beginner Contest 163 - 图10 个值的最小最大值,在这两个值之间的值都可以取到,个数就是最大值-最小值+1。

  1. const int mod = 1e9 + 7;
  2. int ans = 0;
  3. void add(int &x, int y) {
  4. x += y;
  5. if (x >= mod) x -= mod;
  6. if (x < 0) x += mod;
  7. }
  8. int cal(int l, int r) {
  9. return 1ll * (l + r) * (r - l + 1) / 2 % mod;
  10. }
  11. int main() {
  12. ios::sync_with_stdio(false), cin.tie(nullptr);
  13. int n, k;
  14. cin >> n >> k;
  15. for (int i = k; i <= n + 1; i += 1)
  16. add(ans, cal(n + 1 - i, n) - cal(0, i - 1) + 1);
  17. cout << ans;
  18. }

E - Active Infants

题意:有 AtCoder Beginner Contest 163 - 图11 个小孩,第 AtCoder Beginner Contest 163 - 图12 个孩子的位置为 AtCoder Beginner Contest 163 - 图13,活跃值为 AtCoder Beginner Contest 163 - 图14,现在将 AtCoder Beginner Contest 163 - 图15 个小孩重新排列,每个小孩获得的开心值为 AtCoder Beginner Contest 163 - 图16 与重新排列前后位置差的乘积,求最大可能的开心值总和。

数据范围:AtCoder Beginner Contest 163 - 图17

题解:可以发现将 AtCoder Beginner Contest 163 - 图18 较大的值放在边上更优,以A降序,然后就是一个区间dp,枚举当前值放左边、右边进行更新。

AtCoder Beginner Contest 163 - 图19#card=math&code=f%5Bl%5D%5Br%5D%3D%5Cmax%20%5Cleft%28f%5Bl%2B1%5D%5Br%5D%2BA%7Bn%20o%20w%7D%20%5Ctimes%5Cleft%7Cp%7B%5Ctext%20%7Bnow%20%7D%7D-l%5Cright%7C%2C%20f%5Bl%5D%5Br-1%5D%2BA%7B%5Ctext%20%7Bnow%20%7D%7D%20%5Ctimes%5Cleft%7Cp%7B%5Ctext%20%7Bnow%20%7D%7D-r%5Cright%7C%5Cright%29)

  1. const int N = 2e3 + 5;
  2. ll f[N][N];
  3. pair<int, int> p[N];
  4. ll cal(int cnt, int l, int r) {
  5. if (l > r) return 0;
  6. if (~f[l][r]) return f[l][r];
  7. ll ans = 1LL * p[cnt].first * abs(p[cnt].second - l) + cal(cnt + 1, l + 1, r);
  8. ans = max(ans, 1LL * p[cnt].first * abs(p[cnt].second - r) + cal(cnt + 1, l, r - 1));
  9. return f[l][r] = ans;
  10. }
  11. int main() {
  12. int n; cin >> n;
  13. for (int i = 1, x; i <= n; i++) {
  14. scanf("%d", &x);
  15. p[i] = {x, i};
  16. }
  17. sort(p + 1, p + n + 1, [](pair<int, int> a, pair<int, int> b) {
  18. return a.first > b.first;
  19. });
  20. memset(f, -1, sizeof f);
  21. cout << cal(1, 1, n);
  22. return 0;
  23. }

F - path pass i

题意:给一棵N个节点的无根树,每个节点有一个颜色属性c,对于每个颜色,求经过这种颜色的简单路径的数量。

数据范围:AtCoder Beginner Contest 163 - 图20

题解:把问题转换成不经过这种颜色的简单路径的数量,总数 AtCoder Beginner Contest 163 - 图21%2F2#card=math&code=f%5BN%5D%20%3D%20N%2A%28N%2B1%29%2F2) 减去它即可。

其中不经过颜色 AtCoder Beginner Contest 163 - 图22 的简单路径的数量为:AtCoder Beginner Contest 163 - 图23%2C%20c%7Bu%7D%3Di%7D%20f%5B%5Coperatorname%7Bdis%7D(u%2C%20v)-1%5D%7B%5Ccirc%7D#card=math&code=%5Csum%5Climits%7Bu%20%21%3Dv%2C%20u%20%21%3Dw%2C%20v%20%21%3Dw%2C%20c%7Bu%7D%3Dc%7Bv%7D%3Di%2C%20%5Cforall%20w%20%5Cin%20%5Coperatorname%7Bpath%7D%28u%2C%20v%29%2C%20c%7Bu%7D%3Di%7D%20f%5B%5Coperatorname%7Bdis%7D%28u%2C%20v%29-1%5D_%7B%5Ccirc%7D)

  1. const int N = 2e5 + 5;
  2. vector<int> G[N];
  3. int C[N], num[N], sum[N];//num[i]代表i子树的节点数目,sum[i]代表以颜色为i的节点(其祖先没有颜色为i的节点)为根节点的子树大小总和
  4. ll ans[N];
  5. ll cal(int x) {
  6. return 1LL * x * (x + 1) / 2;
  7. }
  8. void dfs(int u, int fa) {
  9. int c = C[u], save = sum[c];
  10. num[u] = 1;
  11. for (auto v : G[u]) {
  12. if (v == fa) continue;
  13. int t = sum[c];
  14. dfs(v, u);
  15. int dt = sum[c] - t;
  16. ans[c] -= cal(num[v] - dt);//num[v]-dt代表相邻两个节点之间的节点数
  17. num[u] += num[v];
  18. }
  19. sum[c] = save + num[u];
  20. }
  21. int main() {
  22. int n; cin >> n;
  23. for (int i = 1; i <= n; i++) cin >> C[i];
  24. for (int i = 1, u, v; i < n; i++) {
  25. cin >> u >> v;
  26. G[u].push_back(v);
  27. G[v].push_back(u);
  28. }
  29. for (int i = 1; i <= n; i++)
  30. ans[i] = cal(n);
  31. dfs(1, -1);
  32. for (int i = 1; i <= n; i++) {
  33. int t = n - sum[i]; //多出来的节点还要减掉
  34. ans[i] -= cal(t);
  35. cout << ans[i] << "\n";
  36. }
  37. }