Codeforces Round #411 (Div. 1)(A~D)题解

£神魔★判官ぃ 2022-06-16 04:55 231阅读 0赞

题目链接:

#411 (Div. 1)

差点翻船。

题解:

A. 这个推导一下,找一下规律就可以了。答案是:ans=(n+1)2−1。

B. 容易发现,无论我们要对字符串操作几遍,我们最后都是要把字符串变成bbbb…aaaa这种形式的。发现每个a能把它后边的b变成2个b,而a要变的次数一定是后面b的个数,所以从后面开始遍历,统计b的数量就可以了。

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. ll mod=1e9+7;
  5. int main()
  6. {
  7. string s;
  8. cin>>s;
  9. reverse(s.begin(),s.end());
  10. ll ans =0;
  11. int b=0;
  12. for(int i=0;i<s.length();i++)
  13. {
  14. if (s[i] == 'b')
  15. {
  16. b++;
  17. }
  18. else
  19. {
  20. ans = (ans + b) % mod;
  21. b = b * 2 % mod;
  22. }
  23. }
  24. cout<<ans<<endl;
  25. return 0;
  26. }

C. 这题花了我挺久时间的…还不如先做D题啊…

这题题意: 给你n个节点,这n个节点构成一棵树。每个节点有si个类型的ice−cream,同一个节点的ice−cream互相连边构成完全图。对于有相同ice−cream的节点u,v,在树上一定相邻。求将ice−cream构成的图染色,相邻点不能同色的最小颜色数以及方案。

题解:首先dfs一遍,将首个节点对应的ice−cream赋给不同的数字,同时记录一下ice−cream对应的颜色,再dfs到下一个树节点,将已经染过色的ice−cream保存一下,然后再遍历一遍没被染过色的ice−cream,并赋给它一个符合条件的最小值。

我这个跑了1980ms,如果卡了,请加ios::sync_with_stdio(false);

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. ll mod=1e9+7;
  5. const int N=345678;
  6. vector<int>g[N];
  7. vector<int>a[N];
  8. int ans[N];
  9. int dfs(int u,int fa,set<int>&s)
  10. {
  11. set<int>s1;
  12. set<int>s2;
  13. vector<int>vv;
  14. for(auto x:a[u])
  15. {
  16. s1.insert(x);
  17. if(s.count(x))
  18. {
  19. s2.insert(ans[x]);
  20. }
  21. else
  22. {
  23. vv.push_back(x);
  24. }
  25. }
  26. int now=1;
  27. for(auto x:vv)
  28. {
  29. s1.insert(x);
  30. while(s2.count(now))
  31. {
  32. now++;
  33. }
  34. ans[x]=now++;
  35. }
  36. for(auto v:g[u])
  37. {
  38. if(v!=fa)
  39. {
  40. dfs(v,u,s1);
  41. }
  42. }
  43. }
  44. int main()
  45. {
  46. int n,m;
  47. cin>>n>>m;
  48. for(int i=1;i<=n;i++){
  49. int k;
  50. cin>>k;
  51. while(k--)
  52. {
  53. int t;
  54. cin>>t;
  55. a[i].push_back(t);
  56. }
  57. }
  58. for(int i=1;i<n;i++)
  59. {
  60. int u,v;
  61. cin>>u>>v;
  62. g[u].push_back(v);
  63. g[v].push_back(u);
  64. }
  65. set<int>s;
  66. dfs(1,-1,s);
  67. for(int i=1;i<=m;i++)
  68. {
  69. if(ans[i]==0){
  70. ans[i]=1;
  71. }
  72. }
  73. int res=0;
  74. for(int i=1;i<=m;i++)
  75. {
  76. res=max(res,ans[i]);
  77. }
  78. cout<<res<<endl;
  79. for(int i=1;i<=m;i++){
  80. cout<<ans[i]<<" ";
  81. }
  82. return 0;
  83. }

D. :

题意:

给你一个森林,每次询问给出u,v,问你从u所在连通块中随机选出一个点与v所在连通块中随机选出一个点相连,问你此时相连出的树的直径期望是多少?(不是树就输出-1)。

题解:首先,先预处理出各连通块的直径和各点到连通块内一点的最远距离d[x],通过树形dp+换根可以解决,询问时若在同一连通块内输出-1(并查集),否则若随机选出两点x,y,直径为max(d[x]+d[y]+1,x所在连通块的直径,y所在连通块的直径),我们把同一连通块内的d从小到大排序一下,枚举小的连通块中的d,到大的连通块中(lower_bound)二分d[x]+d[y]+1<=max(x所在连通块的直径,y所在连通块的直径),通过map,double>ans记忆一下相同询问的答案,这样我们枚举小的次数最大就只有O(n1.5)。(因为这题复杂度只跟小的有关,那么最差的情况是两个连通块是相同的时候,假设所有联通块大小均为k,那么复杂度为O(k∗min(q,(nk)2)),所以复杂度为O(n1.5)),(具体看代码~)

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int N=123456;
  5. int fa[N], sz[N];
  6. vector<int> g[N];
  7. int n, m, q;
  8. int find(int x)
  9. {
  10. return fa[x]=x?fa[x]:fa[x]=find(fa[x]);
  11. }
  12. int dp[N][3], G[N], mx[N];
  13. vector<int> d[N];
  14. vector<ll> sum[N];
  15. bool cmp(int i, int j)
  16. {
  17. return i > j;
  18. }
  19. void dfs(int u, int p)
  20. {
  21. for(auto v: g[u])
  22. {
  23. if(v == p) continue;
  24. dfs(v, u);
  25. dp[u][2] = dp[v][0] + 1;
  26. sort(dp[u], dp[u] + 3, cmp);
  27. }
  28. }
  29. void dfs2(int u, int p)
  30. {
  31. for(auto v: g[u])
  32. {
  33. if(v == p) continue;
  34. int t;
  35. if(dp[u][0] == dp[v][0] + 1) t = dp[u][1];
  36. else t = dp[u][0];
  37. G[v] = max(G[u] + 1, t + 1);
  38. dfs2(v, u);
  39. }
  40. }
  41. int main()
  42. {
  43. cin>>n>>m>>q;
  44. for(int i = 1; i <= n; i++)
  45. {
  46. fa[i] = i;
  47. sz[i] = 1;
  48. }
  49. for(int i = 1; i <= m; i++)
  50. {
  51. int u, v;
  52. cin>>u>>v;
  53. g[u].push_back(v);
  54. g[v].push_back(u);
  55. sz[find(v)] += sz[find(u)];
  56. fa[find(u)] = find(v);
  57. }
  58. for(int i = 1; i <= n; i++)
  59. {
  60. if(fa[i] == i)
  61. {
  62. dfs(i, 0);
  63. }
  64. }
  65. for(int i = 1; i <= n; i++)
  66. {
  67. if(fa[i] == i){
  68. dfs2(i, 0);
  69. }
  70. }
  71. for(int i = 1; i <= n; i++)
  72. {
  73. d[i].push_back(0);
  74. sum[i].push_back(0);
  75. }
  76. for(int i = 1; i <= n; i++)
  77. {
  78. int x = find(i);
  79. mx[x] = max(mx[x], max(dp[i][0], G[i]));
  80. int t = max(dp[i][0], G[i]);
  81. d[x].push_back(t);
  82. sum[x].push_back(0);
  83. }
  84. for(int i = 1; i <= n; i++)
  85. {
  86. sort(d[i].begin(), d[i].end());
  87. if(fa[i] == i)
  88. {
  89. for(int j = 1; j < sum[i].size(); j++)
  90. {
  91. sum[i][j] = sum[i][j - 1] + d[i][j];
  92. }
  93. }
  94. }
  95. map<pair<int,int>, double> ans;
  96. while(q--)
  97. {
  98. int x, y;
  99. cin>>x>>y;
  100. x = find(x);
  101. y = find(y);
  102. if(x == y) //同一连通块
  103. {
  104. puts("-1");
  105. continue;
  106. }
  107. if(sz[x] > sz[y]) swap(x, y);
  108. if(ans.count(make_pair(x, y)))
  109. {
  110. printf("%.10lf\n", ans[make_pair(x, y)]);
  111. continue;
  112. }
  113. ll res = 0;
  114. int k = max(mx[x], mx[y]);
  115. bool fst = 1;
  116. for(auto v: d[x])
  117. {
  118. if(fst)
  119. {
  120. fst = 0;
  121. continue;
  122. }
  123. int p = lower_bound(d[y].begin(), d[y].end(), k - 1 - v) - d[y].begin();
  124. p = max(p, 1);
  125. res += sum[y][sum[y].size() - 1] - sum[y][p - 1] + 1LL * (v + 1) * (sum[y].size() - p);
  126. res += 1LL * (p - 1) * k;
  127. }
  128. double res2 = res * 1.0 / sz[x] / sz[y];
  129. ans[make_pair(x, y)] = res2;
  130. printf("%.12lf\n", res2);
  131. }
  132. return 0;
  133. }

发表评论

表情:
评论列表 (有 0 条评论,231人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Codeforces Round #564 (Div. 1)

    A 太难了,一半时间刚这题还没做出来,简直自闭了。实际上分两种情况,一种很简单直接放,另一种就是要0,0,…,0,1,2,…,n,然后直接贪心,显然我是把情况判断错误一直没调