• 2023 ICPC 网络赛 第一场 部分题解 (待完善)


    D Transitivity

    题解:

    根据题意可以推出结论: 如果存在连通块,那么这个连通块要满足条件,必然是满连通块.

    一共有两种情况

    1. 存在一个连通块不是满连通块

    cnt表示连通块的节点个数, num表示连通块边的个数

    一个连通块的贡献 = cnt*(cnt-1)/2 - num;

    那么最终答案 =  连通块贡献之和

    2.所有连通块都是满连通块

    因为我们至少需要添加一条边,所以此时等价于我们需要把两个连通块合并.

    假设连通块A有x个节点,连通块B有y个节点,那么我们需要添加 x*y条边 才能满足条件.

    所以即找到 最小和次小的连通块即可,答案 = x*y

    AC代码:

    1. #include <bits/stdc++.h>
    2. typedef long long ll;
    3. typedef unsigned long long ull;
    4. #define int long long
    5. #define endl '\n'
    6. #define bit(x) (1ll << x)
    7. using namespace std;
    8. const int N = 1e6 + 5;
    9. const int inf = 1e16;
    10. vector<int> g[N];
    11. int sz[N];//连通块大小
    12. int cnt[N];//边的数量
    13. int vis[N];
    14. void solve()
    15. {
    16. int n,m;
    17. cin >> n >> m;
    18. for(int i = 1; i<=m; i++)
    19. {
    20. int u,v;
    21. cin >> u >> v;
    22. g[u].push_back(v);
    23. g[v].push_back(u);
    24. }
    25. int Min1 = inf;//最小值
    26. int Min2 = inf;//次小
    27. auto dfs = [&](auto self, int u, int fa,int root)-> void
    28. {
    29. vis[u] = 1;
    30. sz[u] = 1;
    31. cnt[root]+=g[u].size();
    32. for(auto v: g[u])
    33. {
    34. if(vis[v])
    35. {
    36. continue;
    37. }
    38. self(self,v,u,root);
    39. sz[u]+=sz[v];
    40. }
    41. };
    42. auto cal = [&](int now, int sum)//计算贡献
    43. {
    44. return sum*(sum-1)/2 - now;
    45. };
    46. int ans = 0;
    47. int f = 0;
    48. for(int i = 1; i<=n; i++)
    49. {
    50. if(vis[i])
    51. {
    52. continue;
    53. }
    54. dfs(dfs,i,-1,i);
    55. cnt[i]/=2;
    56. int val = cal(cnt[i],sz[i]);//连通块的贡献
    57. if(val != 0)
    58. {
    59. ans+=val;
    60. f = 1;
    61. }
    62. else
    63. {
    64. if(sz[i] < Min1)
    65. {
    66. Min2 = Min1;
    67. Min1 = sz[i];
    68. }
    69. else if(sz[i] <=Min2)
    70. {
    71. Min2 = sz[i];
    72. }
    73. }
    74. }
    75. if(f)
    76. {
    77. cout << ans << endl;
    78. }
    79. else
    80. {
    81. cout << Min1*Min2 << endl;
    82. }
    83. }
    84. signed main()
    85. {
    86. ios_base::sync_with_stdio(0);
    87. cin.tie(0);
    88. cout.tie(0);
    89. int t = 1;
    90. //cin >> t;
    91. while (t--)
    92. {
    93. solve();
    94. }
    95. return 0;
    96. }

    A Qualifiers Ranking Rules

    题解: 

    按照题意模拟即可

    1. #include <bits/stdc++.h>
    2. typedef long long ll;
    3. typedef unsigned long long ull;
    4. #define int long long
    5. #define endl '\n'
    6. #define bit(x) (1ll << x)
    7. using namespace std;
    8. const int N = 1e6 + 5;
    9. const int inf = 1e16;
    10. struct node
    11. {
    12. string s; // 学校名称
    13. int rank; // 比赛名次
    14. int t;
    15. node(string x, int y, int _t)
    16. {
    17. s = x;
    18. rank = y;
    19. t = _t;
    20. }
    21. };
    22. int cmp(node a, node b)
    23. {
    24. if (a.rank == b.rank)
    25. {
    26. return a.t < b.t;
    27. }
    28. return a.rank < b.rank;
    29. }
    30. void solve()
    31. {
    32. int n, t;
    33. cin >> n >> t;
    34. map<string, int> vis;
    35. vector<node> pos1;
    36. int cnt = 1;
    37. for (int i = 1; i <= n; i++)
    38. {
    39. string s;
    40. cin >> s;
    41. if (vis.count(s))
    42. {
    43. continue;
    44. }
    45. pos1.push_back({s, cnt, 1});
    46. vis[s] = 1;
    47. cnt++;
    48. }
    49. cnt = 1;
    50. vis.clear();
    51. for (int i = 1; i <= t; i++)
    52. {
    53. string s;
    54. cin >> s;
    55. if (vis.count(s))
    56. {
    57. continue;
    58. }
    59. pos1.push_back({s, cnt, 2});
    60. cnt++;
    61. vis[s] = 1;
    62. }
    63. vis.clear();
    64. sort(pos1.begin(), pos1.end(), cmp);
    65. for (int i = 0; i < pos1.size(); i++)
    66. {
    67. if (vis.count(pos1[i].s))
    68. {
    69. continue;
    70. }
    71. cout << pos1[i].s << endl;
    72. vis[pos1[i].s] = 1;
    73. }
    74. }
    75. signed main()
    76. {
    77. ios_base::sync_with_stdio(0);
    78. cin.tie(0);
    79. cout.tie(0);
    80. int t = 1;
    81. // cin >> t;
    82. while (t--)
    83. {
    84. solve();
    85. }
    86. return 0;
    87. }

    L KaChang!

    题解: 找到最大的数Max,输出  max(2ll,(int)ceil(1.0*Max/k)) 即可

    1. void solve()
    2. {
    3. int n,k;
    4. cin >> n >> k;
    5. int Max = 0;
    6. for(int i = 1; i<=n; i++)
    7. {
    8. int x;
    9. cin >> x;
    10. Max = max(Max,x);
    11. }
    12. cout << max(2ll,(int)ceil(1.0*Max/k)) << endl;;
    13. }

    I Pa?sWorD

    题解:

    设dp[i][S][ch] 表示只看前i个字母,且当前字符的出现状态为S,且最后一个字母是ch的方案数

    (下面这些事伪代码,看不懂的可以直接看代码,有详细注释)

    1.当前是 大写字母
    dp[i][S| bit(2)][ch1] += dp[i-1][S][ch2];//其中ch2 != ch1  即上一层所有字符的方案数 - 上一层ch1的方案数

    1.当前是 小写字母

    (1)大写字母
    dp[i][S| bit(2)][ch1] += dp[i-1][S][ch2];//其中ch2 != ch1  即上一层所有字符的方案数 - ch1的方案数


    (2)填小写字母
    dp[i][S| bit(1)][ch1] += dp[i-1][S][ch2];//其中ch2 != ch1  即上一层所有字符的方案数 - ch1的方案数

    1.当前是 数字
    dp[i][S| bit(0)][ch1] += dp[i-1][S][ch2];//其中ch2 != ch1  即上一层所有字符的方案数 - ch1的方案数


    1.当前是 问号
    枚举当前字符ch1,  t表示当前字母是谁
    dp[i][S| bit(t)][ch1] += dp[i-1][S][ch1];//其中ch2 != ch1  即上一层所有字符的方案数 - ch1的方案数

    AC代码:  

    1. #include <bits/stdc++.h>
    2. typedef long long ll;
    3. typedef unsigned long long ull;
    4. #define int long long
    5. #define endl '\n'
    6. #define bit(x) (1ll << x)
    7. using namespace std;
    8. const int N = 1e6 + 5;
    9. const int inf = 1e16;
    10. const int MOD = 998244353;
    11. int add(int x, int y)
    12. {
    13. x += y;
    14. while (x >= MOD)
    15. x -= MOD;
    16. while (x < 0)
    17. x += MOD;
    18. return x;
    19. }
    20. int sub(int x, int y)
    21. {
    22. return add(x, MOD - y);
    23. }
    24. int mul(int x, int y)
    25. {
    26. return (x * 1ll * y) % MOD;
    27. }
    28. int binpow(int x, int y)
    29. {
    30. int z = 1;
    31. while (y > 0)
    32. {
    33. if (y % 2 == 1)
    34. z = mul(z, x);
    35. x = mul(x, x);
    36. y /= 2;
    37. }
    38. return z;
    39. }
    40. int inv(int x)
    41. {
    42. return binpow(x, MOD - 2);
    43. }
    44. int divide(int x, int y)
    45. {
    46. return mul(x, inv(y));
    47. }
    48. int my_hash(char ch)//对字符进行哈希
    49. {
    50. if (ch >= 'a' && ch <= 'z')
    51. {
    52. return ch - 'a' + 10;
    53. }
    54. else if (ch >= 'A' && ch <= 'Z')
    55. {
    56. return ch - 'A' + 36;
    57. }
    58. else
    59. {
    60. return ch - '0';
    61. }
    62. }
    63. int pos(int ch)//当前字符在二进制中的位置
    64. {
    65. if (ch >= 10 && ch <= 35) // 小写表示第1
    66. {
    67. return 1;
    68. }
    69. else if (ch >= 36 && ch <= 61) // 大写表示第2
    70. {
    71. return 2;
    72. }
    73. else // 数字表示第0
    74. {
    75. return 0;
    76. }
    77. }
    78. int dp[2][10][70]; // 当前状态为S且最后一个字符是 ch 的方案数
    79. int last[10]; // 状态为S时 所有的字符方案数之和
    80. void solve()
    81. {
    82. int n;
    83. cin >> n;
    84. string s;
    85. cin >> s;
    86. s = " " + s;
    87. //初始化部分
    88. int S = 0;
    89. int now;
    90. int ch; // 当前填入的字符编号
    91. if (s[1] == '?')
    92. {
    93. for (ch = 0; ch <= 61; ch++) // 当前填入ch
    94. {
    95. now = S | bit(pos(ch)); // 填入s[i]后,当前的二进制状态
    96. dp[1][now][ch] = 1;
    97. }
    98. }
    99. else
    100. {
    101. now = S | bit(pos(my_hash(s[1]))); // 填入s[i]后,当前的二进制状态
    102. ch = my_hash(s[1]);
    103. dp[1][now][ch] = 1; // 加上全部的
    104. if (s[1] >= 'a' && s[1] <= 'z')//如果是小写字母,还可以是大写字母
    105. {
    106. now = S | bit(pos(my_hash(s[1]) + 26)); // 填入s[i]后,当前的二进制状态
    107. ch = my_hash(s[1]) + 26; // 填大写字母
    108. dp[1][now][ch] = 1; // 加上全部的
    109. }
    110. }
    111. for (int i = 2; i <= n; i++)
    112. {
    113. for (int S = 0; S < 8; S++)//
    114. {
    115. int sum = 0;
    116. for (int ch = 0; ch <= 61; ch++)
    117. {
    118. dp[0][S][ch] = dp[1][S][ch]; // 滚动数组
    119. dp[1][S][ch] = 0; // 进行初始化
    120. sum = add(sum, dp[0][S][ch]);//表示上一层状态为S的所有字符的方案数
    121. }
    122. last[S] = sum; // 表示上一层状态为S的所有字符的方案数
    123. }
    124. for (int S = 0; S < 8; S++) // 枚举上一层的状态
    125. {
    126. int now;//表示填入字符后的状态
    127. int ch; // 当前填入的字符编号
    128. if (s[i] == '?')
    129. {
    130. for (ch = 0; ch <= 61; ch++) // 当前填入ch
    131. {
    132. now = S | bit(pos(ch)); // 填入s[i]后,当前的二进制状态
    133. dp[1][now][ch] = add(dp[1][now][ch], last[S]); // 加上全部的
    134. dp[1][now][ch] = sub(dp[1][now][ch], dp[0][S][ch]); // 相邻不能相同,减去
    135. }
    136. }
    137. else
    138. {
    139. now = S | bit(pos(my_hash(s[i]))); // 填入s[i]后,当前的二进制状态
    140. ch = my_hash(s[i]);
    141. dp[1][now][ch] = add(dp[1][now][ch], last[S]); // 加上全部的
    142. dp[1][now][ch] = sub(dp[1][now][ch], dp[0][S][ch]); // 相邻不能相同,减去
    143. if (s[i] >= 'a' && s[i] <= 'z') // 填入大写的
    144. {
    145. now = S | bit(pos(my_hash(s[i]) + 26)); // 填入s[i]后,当前的二进制状态
    146. ch = my_hash(s[i]) + 26;
    147. dp[1][now][ch] = add(dp[1][now][ch], last[S]); // 加上全部的
    148. dp[1][now][ch] = sub(dp[1][now][ch], dp[0][S][ch]); // 相邻不能相同,减去
    149. }
    150. }
    151. }
    152. }
    153. int ans = 0;
    154. for (int ch = 0; ch <= 61; ch++)
    155. {
    156. ans = add(ans, dp[1][7][ch]);
    157. }
    158. cout << ans << endl;
    159. }
    160. signed main()
    161. {
    162. ios_base::sync_with_stdio(0);
    163. cin.tie(0);
    164. cout.tie(0);
    165. int t = 1;
    166. // cin >> t;
    167. while (t--)
    168. {
    169. solve();
    170. }
    171. return 0;
    172. }

  • 相关阅读:
    码蹄集 - MT3251 - 多重回文
    BigDecimal常用API
    基于PyTorch的生成对抗网络实战(7)——利用Pytorch搭建SGAN(Semi-Supervised GAN)生成手写数字并分类
    VLAN trunk扩展 MUXVLAN 原理与实验
    深入理解数据库视图
    Spring-Spring之AOP底层源码解析(下)
    client-go gin的简单整合十-Update
    html02-标签继续学习
    <<JavaEE>> 线程安全问题
    CMake+CLion+Qt配置
  • 原文地址:https://blog.csdn.net/cs1414358917/article/details/132977088