Contest Info


[Practice Link](https://cn.vjudge.net/contest/313014)

Solved A B C D E F G H I J K
9/11 O - Ø O - O O O O O O
  • O 在比赛中通过
  • Ø 赛后通过
  • ! 尝试了但是失败了
  • - 没有尝试

Solutions


A. Cotree

题意:

有两棵树,一共有\(n\)个点,现在要求在两棵树中连一条边,使得他们变成一棵树,如何连边使下式最小:

\[\begin{eqnarray*}
\sum\limits_{i = 1}^n \sum\limits_{j = i + 1}^n dis(i, j)
\end{eqnarray*}
\]

思路:

我们可以单独考虑边的贡献,一条边的贡献是这条边两边的点数乘积。

那么新加的边的贡献是固定的。

我们考虑怎么减少已存在的边的贡献,其实我们可以感性的理解一下,我们最后选出的两个点相连,我们强制让它们成为他们各自树中的根,那么这么考虑:

  • 令\(f[i]\)表示以\(i\)为根的子树中的边的贡献

    那么转移有:

\[\begin{eqnarray*}
f[u] = \sum\limits_{v \in son[u]} f[v] + sze[v] * (n - sze[v])
\end{eqnarray*}
\]

  • 令\(g[i]\)表示以\(i\)为根的非子树中的边的贡献

    那么转移有:

\[\begin{eqnarray*}
g[u] = g[fa[u]] + f[fa[u]] - f[u] - (sze[u]) * (n - sze[u]) + (sze[u] + S) * (n - sze[u] - S)
\end{eqnarray*}
\]

其中\(S\)代表另外一棵树的大小,最后那两部分主要是\(u \rightarrow fa[u]\)那条边的贡献变了

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. #define N 100010
  5. int n, S, T;
  6. vector <vector<int>> G;
  7. int fa[N], sze[N];
  8. ll f[N], g[N];
  9. void DFS(int u) {
  10. sze[u] = 1;
  11. f[u] = 0;
  12. for (auto v : G[u]) if (v != fa[u]) {
  13. fa[v] = u;
  14. DFS(v);
  15. sze[u] += sze[v];
  16. f[u] += f[v];
  17. f[u] += 1ll * sze[v] * (n - sze[v]);
  18. }
  19. }
  20. ll DFS2(int u, int rt, int S) {
  21. if (u != rt) {
  22. g[u] = g[fa[u]] + f[fa[u]] - f[u] + 1ll * (n - sze[u] - S) * (sze[u] + S) - 1ll * sze[u] * (n - sze[u]);
  23. } else {
  24. g[u] = 0;
  25. }
  26. ll res = f[u] + g[u];
  27. for (auto v : G[u]) if (v != fa[u]) {
  28. res = min(res, DFS2(v, rt, S));
  29. }
  30. return res;
  31. }
  32. int main() {
  33. while (scanf("%d", &n) != EOF) {
  34. G.clear(); G.resize(n + 1);
  35. for (int i = 1; i <= n; ++i) fa[i] = -1;
  36. for (int i = 1, u, v; i < n - 1; ++i) {
  37. scanf("%d%d", &u, &v);
  38. G[u].push_back(v);
  39. G[v].push_back(u);
  40. }
  41. int rt[2]; rt[0] = 1;
  42. fa[1] = 1;
  43. DFS(1); S = sze[1]; T = n - S;
  44. for (int i = 1; i <= n; ++i) {
  45. if (fa[i] == -1) {
  46. rt[1] = i;
  47. fa[i] = i;
  48. DFS(i);
  49. break;
  50. }
  51. }
  52. ll res = DFS2(1, 1, T) + DFS2(rt[1], rt[1], S) + 1ll * S * T;
  53. printf("%lld\n", res);
  54. }
  55. return 0;
  56. }

C.Trap

题意:

有\(n\)根长度为\(a_i\)的棍子,询问有多少种方案选出四条边,使得它们的\(gcd = 1\),并且能够组成一个等腰梯形。

思路:

考虑\(f(d)\)为长度为\(d\)的倍数的棍子组成的方案数,那么可以容斥原理有:

\[\begin{eqnarray*}
ans = \sum\limits_{i = 1}^{maxlen} f(i)\mu(i)
\end{eqnarray*}
\]

其中\(\mu(i)\)为莫比乌斯函数,它的定义如下:

\[\begin{eqnarray*}
\mu(n) =
\left\{
\begin{array}{cccc}
1 && n = 1 \\
(-1)^k && n = p_1p_2, \cdots p_k \text{n中无平方因数} \\
0 && \text{n中有>1的平方因数}
\end{array}
\right.
\end{eqnarray*}
\]

根据\(\mu(n)\)的定义,我们发现当\(n\)中奇数个质因子的时候\(\mu(n) = -1\),当\(n\)中有偶数个质因子的时候\(\mu(n) = 1\),恰好是我们需要的容斥系数。

考虑怎么求解\(f(d)\),可以两个循环枚举上底和腰:

  • 下底的范围是(上底, 上底 + 腰 * 2)
  • 注意特判下底等于腰的情况和上底等于腰的情况,棍子是否足够

为什么下底的下界是上底 + 腰 * 2 ?

考虑等腰的那个等角越小的时候,下底越长,那么极限情况,就是角度为\(0\)的时候,这时候长度就是上底 + 腰 * 2, 但是这个长度不合法,所以是开区间。

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. #define M 10010
  5. int n, a[M], cnt[M];
  6. vector <vector<int>> vec, fac;
  7. int prime[M], check[M], mu[M], tot;
  8. void init() {
  9. tot = 0;
  10. memset(check, 0, sizeof check);
  11. mu[1] = 1;
  12. fac.clear();
  13. fac.resize(M);
  14. for (int i = 2; i < M; ++i) {
  15. if (!check[i]) {
  16. prime[++tot] = i;
  17. mu[i] = -1;
  18. }
  19. for (int j = 1; j <= tot; ++j) {
  20. if (1ll * i * prime[j] >= M) break;
  21. check[i * prime[j]] = 1;
  22. if (i % prime[j] == 0) {
  23. mu[i * prime[j]] = 0;
  24. break;
  25. } else {
  26. mu[i * prime[j]] = -mu[i];
  27. }
  28. }
  29. }
  30. for (int i = 1; i < M; ++i) {
  31. for (int j = i; j < M; j += i) {
  32. fac[j].push_back(i);
  33. }
  34. }
  35. }
  36. int main() {
  37. init();
  38. while (scanf("%d", &n) != EOF) {
  39. vec.clear(); vec.resize(M);
  40. memset(cnt, 0, sizeof cnt);
  41. for (int i = 1; i <= n; ++i) {
  42. scanf("%d", a + i);
  43. ++cnt[a[i]];
  44. for (auto it : fac[a[i]]) {
  45. vec[it].push_back(a[i]);
  46. }
  47. }
  48. ll res = 0;
  49. for (int i = 1; i < M; ++i) {
  50. if (vec[i].empty() || mu[i] == 0) continue;
  51. ll tmp = 0;
  52. sort(vec[i].begin(), vec[i].end());
  53. vec[i].erase(unique(vec[i].begin(), vec[i].end()), vec[i].end());
  54. int sze = vec[i].size();
  55. for (auto it : vec[i]) { //枚举上边
  56. int l = 0, r = 0;
  57. while (l < sze && vec[i][l] < it + 1) ++l;
  58. for (auto it2 : vec[i]) { //枚举腰
  59. if (it != it2 && cnt[it2] >= 2) {
  60. while (r < sze - 1 && vec[i][r + 1] < it + 2 * it2) ++r;
  61. if (l < sze && r < sze && l <= r) {
  62. tmp += r - l + 1;
  63. if (vec[i][l] <= it2 && it2 <= vec[i][r]) {
  64. if (cnt[it2] < 3) --tmp;
  65. }
  66. }
  67. } else if (it == it2 && cnt[it] >= 3) {
  68. while (r < sze - 1 && vec[i][r + 1] < it + 2 * it2) ++r;
  69. if (l < sze && r < sze && l <= r) {
  70. tmp += r - l + 1;
  71. }
  72. }
  73. }
  74. }
  75. res += tmp * mu[i];
  76. }
  77. printf("%lld\n", res);
  78. }
  79. return 0;
  80. }

D.Wave

题意:

找一个最长的'wave',要求满足以下限制:

  • 序列长度大于等于\(2\)
  • 所有奇数位置上的数相同
  • 所有偶数位置上的数相同
  • 奇数位置和偶数位置的数不同

思路:

因为值域只有\([1, 100]\),那么暴力枚举奇数位置上的数和偶数位置上的数即可。

时间复杂度\(\mathcal{O}(nc)\)

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define N 100010
  4. int n, c, a[N];
  5. int f[N][110], nx[110];
  6. int main() {
  7. scanf("%d%d", &n, &c);
  8. for (int i = 1; i <= n; ++i) scanf("%d", a + i);
  9. for (int i = 1; i <= c; ++i) nx[i] = n + 1, f[n + 1][i] = n + 1;
  10. for (int i = n; i >= 0; --i) {
  11. for (int j = 1; j <= c; ++j) {
  12. f[i][j] = nx[j];
  13. }
  14. if (i) nx[a[i]] = i;
  15. }
  16. int res = 0;
  17. for (int i = 1; i <= c; ++i) {
  18. for (int j = 1; j <= c; ++j) if (i != j) {
  19. int tmp = 0;
  20. int it = 0;
  21. while (it <= n) {
  22. it = f[it][i];
  23. if (it <= n) {
  24. tmp += 1;
  25. } else break;
  26. it = f[it][j];
  27. if (it <= n) {
  28. tmp += 1;
  29. } else break;
  30. }
  31. if (tmp > 1) {
  32. res = max(res, tmp);
  33. }
  34. }
  35. }
  36. printf("%d\n", res);
  37. return 0;
  38. }

F.String

题意:

给出一个字符串,只包含'a', 'v', 'i', 'n', 要求从中等概率可重复的取出四个字符,问恰好是'avin'的概率是多少。

思路:

根据乘法原理计算即可。

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. #define N 110
  5. int n;
  6. char s[N];
  7. int cnt[220];
  8. int main() {
  9. while (scanf("%d", &n) != EOF) {
  10. scanf("%s", s + 1);
  11. memset(cnt, 0, sizeof cnt);
  12. for (int i = 1; i <= n; ++i) ++cnt[s[i]];
  13. if (!cnt['a'] || !cnt['v'] || !cnt['i'] || !cnt['n']) {
  14. puts("0/1");
  15. } else {
  16. ll a = 1ll * cnt['a'] * cnt['v'] * cnt['i'] * cnt['n'];
  17. ll b = 1ll * n * n * n * n;
  18. ll G = __gcd(a, b);
  19. a /= G;
  20. b /= G;
  21. printf("%lld/%lld\n", a, b);
  22. }
  23. }
  24. return 0;
  25. }

G. Traffic

题意:

在一个十字路口,有\(n\)辆东西走向的车,他们会在\(a_i\)时刻到达,有\(m\)辆南北走向的车,他们会在\(b_i\)时刻到达。问需要让\(m\)辆南北走向的车整体等待多少秒,使得他们的开始行动之后不会和东西走向的车相撞?

思路:

考虑\(a_i\)和\(b_i\)只有\(1000\),那么等待时间不会超过\(1000\),暴力枚举即可。

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define N 5100
  4. int n, m, a[N], b[N];
  5. bool ok(int x) {
  6. for (int i = 1; i <= m; ++i) {
  7. if (a[b[i] + x]) {
  8. return 0;
  9. }
  10. }
  11. return 1;
  12. }
  13. int main() {
  14. while (scanf("%d%d", &n, &m) != EOF) {
  15. memset(a, 0, sizeof a);
  16. for (int i = 1, x; i <= n; ++i) {
  17. scanf("%d", &x);
  18. a[x] = 1;
  19. }
  20. for (int i = 1; i <= m; ++i) scanf("%d", b + i);
  21. for (int i = 0; i <= 2000; ++i) {
  22. if (ok(i)) {
  23. printf("%d\n", i);
  24. break;
  25. }
  26. }
  27. }
  28. return 0;
  29. }

H.Rng

题意:

考虑随机选择一个区间的过程:

  • 先从\([1, n]\)等概率选择\(r\)
  • 再在\([1, r]\)中等概率选择出\(l\)

    问随机选择两个区间,它们相交的概率?

思路:

考虑枚举\(r\):

  • 考虑\(R\)落在\([r + 1, n]\)的概率,即为:

\[\begin{eqnarray*}
\frac{1}{n^2} \sum\limits_{i = r + 1}^n \frac{r}{i}
\end{eqnarray*}
\]

  • 考虑\(R\)落在\([l, r]\)之间的概率,即为:

\[\begin{eqnarray*}
\frac{1}{n}(\frac{1}{r} \sum\limits_{i = 1}^r \frac{r - i +1}{n})
\end{eqnarray*}
\]

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. #define N 1000010
  5. const ll p = 1e9 + 7;
  6. ll qmod(ll base, ll n) {
  7. ll res = 1;
  8. while (n) {
  9. if (n & 1) {
  10. res = res * base % p;
  11. }
  12. base = base * base % p;
  13. n >>= 1;
  14. }
  15. return res;
  16. }
  17. int n;
  18. ll f[N], g[N], inv[N];
  19. ll Sf(int l, int r) {
  20. if (l > r) return 0;
  21. return (f[r] - f[l - 1] + p) % p;
  22. }
  23. ll Sg(int l, int r) {
  24. if (l > r) return 0;
  25. return (g[r] - g[l - 1] + p) % p;
  26. }
  27. void add(ll &x, ll y) {
  28. x += y;
  29. if (x >= p) x -= p;
  30. }
  31. int main() {
  32. inv[1] = 1;
  33. for (int i = 2; i < N; ++i) inv[i] = inv[p % i] * (p - p / i) % p;
  34. for (int i = 1; i < N; ++i) {
  35. f[i] = (f[i - 1] + i) % p;
  36. g[i] = (g[i - 1] + inv[i]) % p;
  37. }
  38. while (scanf("%d", &n) != EOF) {
  39. ll res = 0;
  40. for (int i = 1; i <= n; ++i) {
  41. add(res, 1ll * i * inv[n] % p * inv[n] % p * Sg(i + 1, n) % p);
  42. add(res, 1ll * inv[i] * inv[n] % p * inv[n] % p * (1ll * i * (i + 1) % p - Sf(1, i) + p) % p);
  43. }
  44. printf("%lld\n", res);
  45. }
  46. return 0;
  47. }

I. Budget

签到题。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. #define N 1100
  5. int n;
  6. char s[N];
  7. ll get() {
  8. scanf("%s", s + 1);
  9. int len = strlen(s + 1);
  10. int pos = -1;
  11. for (int i = 1; i <= len; ++i) {
  12. if (s[i] == '.') {
  13. pos = i;
  14. break;
  15. }
  16. }
  17. if (pos == -1 || len - pos < 3) return 0;
  18. int num = s[pos + 3] - '0';
  19. if (num <= 4) return -num;
  20. else return 10 - num;
  21. }
  22. int main() {
  23. while (scanf("%d", &n) != EOF) {
  24. ll res = 0;
  25. for (int i = 1; i <= n; ++i) {
  26. res += get();
  27. }
  28. printf("%.3f\n", res * 0.001);
  29. }
  30. return 0;
  31. }

J. Worker

题意:

有\(n\)个销售点,有\(m\)个销售员,每个销售员在第\(i\)个销售点会产生\(a_i\)的订单,问如何分配销售员使得每个销售点产生的订单相同。

思路:

首先单个销售点的订单量肯定是所有销售点\(a_i\)的最小公倍数的倍数。

那么判断\(m\)能否整除其最小公倍数即可,然后按比例分配。

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define N 1100
  4. #define ll long long
  5. int n, a[N];
  6. ll m, lcm;
  7. void solve() {
  8. ll one = 0;
  9. for (int i = 1; i <= n; ++i) {
  10. one += lcm / a[i];
  11. }
  12. if (m % one) {
  13. puts("No");
  14. return;
  15. }
  16. ll cur = m / one;
  17. puts("Yes");
  18. for (int i = 1; i <= n; ++i) printf("%lld%c", cur * (lcm / a[i]), " \n"[i == n]);
  19. }
  20. int main() {
  21. while (scanf("%d%lld", &n, &m) != EOF) {
  22. for (int i = 1; i <= n; ++i) scanf("%d", a + i);
  23. lcm = a[1];
  24. for (int i = 2; i <= n; ++i) {
  25. lcm = lcm * a[i] / __gcd(lcm, 1ll * a[i]);
  26. }
  27. solve();
  28. }
  29. return 0;
  30. }

K. Class

题意:

给出:

\[\begin{cases}
x &=& a + b \\
y &=& a - b
\end{cases}
\]

计算\(a \cdot b\)。

思路:

签到题。

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int main() {
  4. int x, y;
  5. while (cin >> x >> y) {
  6. int a = (x + y) / 2;
  7. int b = (x - y) / 2;
  8. cout << a * b << "\n";
  9. }
  10. return 0;
  11. }

2019CCPC-江西省赛的更多相关文章

  1. 2021江西省赛线下赛赛后总结(Crypto)

    2021江西省赛线下赛 crypto1 题目: from random import randint from gmpy2 import * from Crypto.Util.number impor ...

  2. 2021 ICPC 江西省赛总结

      比赛链接:https://ac.nowcoder.com/acm/contest/21592   大三的第一场正式赛,之前的几次网络赛和选拔赛都有雄哥坐镇,所以并没有觉得很慌毕竟校排只取每个学校成 ...

  3. 2019-CCPC广东省赛总结

    2018年11月第一次参加ICPC区域赛青岛赛区,打铁了! 2019年5月第一次参加CCPC广东省赛,4题滚粗,C题莫队TLE13发,只拿了个铜牌! 教训总结: 比赛时千万不能犹豫,不能犹豫,不能犹豫 ...

  4. [2019CCPC网络赛][hdu6704]K-th occurrence(后缀数组&&主席树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6704 题意为查询子串s[l...r]第k次出现的位置. 写完博客后5分钟的更新 写完博客才发现这份代码 ...

  5. I - Union 2019ccpc女生赛

    I - Union 这是2019女生赛最难的一个题目,但是现在去写,我觉得没有想象之中的那么难. 把这个题目分成几个部分来考虑. 假设给你k个数,让你分成三个集合,满足这四个条件,且不需要考虑时间和空 ...

  6. CCPC2019江西省赛-Problem G.Traffic

    题目描述: /*纯手打题面*/ Avin is observing the cars at a crossroads.He finds that there are n cars running in ...

  7. 2019CCPC网络赛 C - K-th occurrence HDU - 6704(后缀数组+ST表+二分+主席树)

    题意 求区间l,r的子串在原串中第k次出现的位置. 链接:https://vjudge.net/contest/322094#problem/C 思路 比赛的时候用后缀自动机写的,TLE到比赛结束. ...

  8. 2019CCPC网络赛

    ^&^ (HDU 6702) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Other ...

  9. 2019CCPC网络赛 HD6707——杜教筛

    题意 求 $f(n,a,b)=\sum_{i=1}^n \sum_{j=1}^i gcd(i^a-j^a,i^b-j^b)[gcd(i,j)=1]\%(10^9+7)$,$1 \le n,a,b \l ...

  10. 2019CCPC网络赛 HDU 6702——找规律

    题意 给定 $A,B$(都是正整数),求使得 $(A\  xor\  C) \& (B \ xor \  C)$ 最小的正整数 $C$,如果有多个满足条件的 $C$,输出最小的 $C$. 分析 ...

随机推荐

  1. 游记-pkupc&cts2019

    Day0 和boshi.Rayment组的队,昨天听学长说这次比赛可以加学分,他们信科的大部分人都会参加,估摸有两百多支队伍--然而奖品只有不到一百份 我要奖品呐! 上午十一点半到的北京,拉着行李提着 ...

  2. (十七)Hibnernate 和 Spring 整合

    一.Hibnernate 和 Spring结合方案: 方案一:  框架各自使用自己的配置文件,Spring中加载Hibernate的配置文件. 方案二:   统一由Spring的配置来管理.(推荐使用 ...

  3. (七)Action之ActionContext(OGNL表达式的使用)

    一.ActionContext的重要性 struts中的数据都存放在ActionContext里,所以这部分是Action中的核心. ActionContext又称广义值栈,既然有广义值栈就有侠义值栈 ...

  4. MySQL 的COUNT(x)性能怎么样?

    做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! x 可以代表: 主键id.字段.1.* 0 说明 对于count(主键id)来说 innodb引擎会遍历整张表,把每一行的 ...

  5. 在CentOS部署AspNetCore网站

    前段时间某云服务器大促,就买了一台打算折腾一下,买了几个月,却啥也没做,就改了个初始密码.最近快到双十一了,另一家厂商相同配置的服务器价格又便宜了一大截,看来又得剁手了.从今年开始,搜索一下云服务器, ...

  6. Vue绑定的table页面在Chrome浏览器左右抖动

    现象: 今天Chrome浏览器升级到最新版本(75.0.3770.100),突然发现之前vue页面只要绑定了el-table标签的,都在左右抖动,抖动得眼睛都花了,百度上找半天也没有遇到相同问题的人, ...

  7. opencv-02--图像的邻域操作

    图像的邻域操作 很多时候,我们对图像处理时,要考虑它的邻域,比如3*3是我们常用的,这在图像滤波.去噪中最为常见,下面我们介绍如果在一次图像遍历过程中进行邻域的运算. 下面我们进行一个简单的滤波操作, ...

  8. Map集合中key不存在时使用toString()方法、valueOf()方法和强制转换((String))之间的区别

    1.toString()方法 底层代码 public String toString() { return this; } 其返回值为String类型的字符串本身 Map<String, Obj ...

  9. CentOS linux7 设置开机启动服务

    常用命令 描述                                 旧命令  新命令 使服务自动启动          chkconfig --level 3 http on  syste ...

  10. Sliverlight/WPF 样式使用方法

    1,UserControl 页面级样式: UserControl.Resources style setter Property value. TargetType为应用的类型 <UserCon ...