补题链接:Here

1529A. Eshag Loves Big Arrays

【题意描述】

给定一个长度为 Codeforces Round #722 (这场难,需要注意) - 图1 的正整数数组 Codeforces Round #722 (这场难,需要注意) - 图2 ,现在可执行若干次操作(可为 Codeforces Round #722 (这场难,需要注意) - 图3

具体操作为:选定某个序列,删除严格大于序列的平均数的元素

请问最多能删去多少个元素

【解题思路】

观察一下样例容易发现,在若干次操作之后,一定是最小的元素留下,所以我们只需要统计最小值元素个数,然后输出 Codeforces Round #722 (这场难,需要注意) - 图4

【AC 代码】

  1. void solve() {
  2. int n;
  3. cin >> n;
  4. int a[n + 1];
  5. for (int i = 1; i <= n; ++i)cin >> a[i];
  6. sort(a + 1, a + 1 + n);
  7. int cnt = 0;
  8. for (int i = 1; i <= n; ++i)if (a[i] == a[1])cnt++;
  9. cout << n - cnt << "\n";
  10. }

1529B. Sifid and Strange Subsequences

【题意描述】

先有一个长度为 Codeforces Round #722 (这场难,需要注意) - 图5 的数组,定义“奇怪数组”:数组中任意两个元素的绝对值差值大于等于数组中的最大值,即 Codeforces Round #722 (这场难,需要注意) - 图6 ,请问由原数组中最大能选出多少个元素构成“奇怪数组”

【解题思路】

很容易证明一个奇怪的子序列不能包含一个以上的正元素。
所以最好选择所有的非正元素,现在我们最多只能选择一个正元素。
假设x是数组中最小的正元素。如果已经选取的集合中没有两个元素(如a和b)以a的方式存在,我们可以选取 Codeforces Round #722 (这场难,需要注意) - 图7
要检查这一点,我们只需对已经拾取的元素进行排序,并查看相邻元素对之间的差异。
复杂性:Codeforces Round #722 (这场难,需要注意) - 图8#card=math&code=%5Cmathcal%7BO%7D%28nlog%5C%20n%29&id=l1c5n)

【AC 代码】

  1. void solve() {
  2. int n;
  3. cin >> n;
  4. vector<int>a(n);
  5. for (int &x : a)cin >> x;
  6. sort(a.begin(), a.end());
  7. int ans = 0, cnt0 = 0, cnt = 0;
  8. for (int i = 0; i < n; ++i) {
  9. if (a[i] < 0)ans++;
  10. else if (a[i] == 0)cnt0++;
  11. }
  12. int res = ans + cnt0, Min = 1e9;
  13. for (int i = 0; i + 1 < n; ++i) {
  14. if (a[i + 1] > 0)break;
  15. Min = min(Min, a[i + 1] - a[i]);
  16. }
  17. for (int i = 0; i < n; ++i)if (a[i] > 0 and a[i] <= Min)cnt++;
  18. res = max(res, ans + (cnt0 > 0) + (cnt > 0));
  19. cout << res << "\n";
  20. }

1529C. Parsa’s Humongous Tree

【题意描述】

给你一棵树,树上的每个节点 都有一个值域 ,我们需要从值域中确定一个值 ,而 边权值则为 。我们的目的就是要让所有的边权值之和最大。求出最大权值之和。

【解题思路】

感觉AtCoder上有一道很像的题

【AC 代码】

  1. using ll = long long;
  2. const int N = 1e5 + 10;
  3. vector<int>g[N];
  4. int a[N][2], n;
  5. ll f[N][2];
  6. void dfs(int v, int p) {
  7. for (int s : g[v])
  8. if (s != p) {
  9. dfs(s, v);
  10. f[v][0] += max(f[s][0] + abs(a[s][0] - a[v][0]), f[s][1] + abs(a[s][1] - a[v][0]));
  11. f[v][1] += max(f[s][0] + abs(a[s][0] - a[v][1]), f[s][1] + abs(a[s][1] - a[v][1]));
  12. }
  13. }
  14. void solve() {
  15. cin >> n;
  16. for (int i = 0; i < n; ++i)cin >> a[i][0] >> a[i][1];
  17. for (int i = 0, u, v; i + 1 < n; ++i) {
  18. cin >> u >> v;
  19. --u, --v;
  20. g[u].push_back(v);
  21. g[v].push_back(u);
  22. }
  23. dfs(0, -1);
  24. cout << max(f[0][0], f[0][1]) << "\n";
  25. for (int i = 0; i < n; ++i) {
  26. g[i].clear();
  27. f[i][0] = f[i][1] = 0;
  28. }
  29. }

1529D. Kavi on Pairing Duty

【题意描述】

【解题思路】

Codeforces Round #722 (这场难,需要注意) - 图9Codeforces Round #722 (这场难,需要注意) - 图10 点的良好配对数。
显然,答案是 Codeforces Round #722 (这场难,需要注意) - 图11
引理:表示x为与点1匹配的点。注意每个点p(Codeforces Round #722 (这场难,需要注意) - 图12 )属于长度等于 Codeforces Round #722 (这场难,需要注意) - 图13 长度的线段。
证明:假设某点p(Codeforces Round #722 (这场难,需要注意) - 图14 )与点q配对(q>p),因为[p,q]不在 Codeforces Round #722 (这场难,需要注意) - 图15 之内,所以它们的大小必须相等,配对才是好的。
为了计算dpn,考虑以下情况:

  • Codeforces Round #722 (这场难,需要注意) - 图16 :类似于上述引理,可以证明每个点p(Codeforces Round #722 (这场难,需要注意) - 图17)与点i+x配对−1,剩余的未配对x−n−1个点形成一个连续的子阵列,该子阵列位于每个当前对内,因此它们可以在dpx中配对−n−1种方式。
  • Codeforces Round #722 (这场难,需要注意) - 图18:在这种情况下,由于上述引理,所有的线段必须具有相同的长度,因此它们的长度必须是n的一个除数,在这种情况下,它们可以以D(n)的方式配对;其中D(n)是n的除数。

所以 Codeforces Round #722 (这场难,需要注意) - 图19%2B%E2%88%91%5E%7Bn%E2%88%921%7D%7Bi%3D0%7Ddp_i#card=math&code=dp_n%3DD%28n%29%2B%E2%88%91%5E%7Bn%E2%88%921%7D%7Bi%3D0%7Ddp_i&id=mYDiD)。
注意 Codeforces Round #722 (这场难,需要注意) - 图20

【AC 代码】

  1. const int N = 1e6 + 10, MOD = 998244353;
  2. int n, dp[N], S;
  3. void solve() {
  4. cin >> n;
  5. for (int i = 1; i <= n; i++) {
  6. for (int j = i + i; j <= n; j += i) {
  7. dp[j]++;
  8. }
  9. }
  10. dp[0] = S = 1;
  11. for (int i = 1; i <= n; i++) {
  12. dp[i] = (dp[i] + S) % MOD;
  13. S = (S + dp[i]) % MOD;
  14. }
  15. cout << dp[n] << endl;
  16. }