当前位置:   article > 正文

Codeforces Round 903 (Div. 3)A~F

codeforces round 903

A - Don't Try to Count

题意:字符串s每次操作后变成s+s,问能否操作若干次是t是s的字串。

思路:数据范围很小,len(s)和len(t)最大25,要么如果枚举到len(s)长度大于等于len(t)的二倍,还没有出现答案,之后就不会出现答案。故需要枚举log2(50)上取整次,即六次。

  1. #include<bits/stdc++.h>
  2. #define double long double
  3. #define int long long
  4. using namespace std;
  5. const int N = 2e5 + 10, mod = 998244353;
  6. void solve()
  7. {
  8. int n, m; cin >> n >> m;
  9. string s1, s2; cin >> s1 >> s2;
  10. int ans = 0;
  11. for(int i = 1; i <= 6; i ++)
  12. {
  13. if(s1.find(s2) < s1.size())
  14. {
  15. cout << ans << '\n';
  16. return;
  17. }
  18. s1 += s1;
  19. ans ++;
  20. }
  21. cout << -1 << '\n';
  22. }
  23. signed main()
  24. {
  25. ios::sync_with_stdio(0);
  26. cin.tie(0); cout.tie(0);
  27. int t = 1; cin >> t;
  28. while(t --) solve();
  29. }

 B - Three Threadlets

题意:给n个数,问三次操作能否把数分成相等的值。

要切的操作最少,那么切成min值最优。因为如果要切成更小的值,必须得先经历切成min的操作数

比如8要切成2,因8 = 2 + 2 + 2 + 2,至少要切 8 / 2 - 1次。

故将所有次数累加即可。

  1. #include<bits/stdc++.h>
  2. #define double long double
  3. #define int long long
  4. using namespace std;
  5. const int N = 2e5 + 10, mod = 998244353;
  6. void solve()
  7. {
  8. int a, b, c; cin >> a >> b >> c;
  9. int minn = min({a, b, c});
  10. if((a % minn == 0) && (b % minn == 0) && (c % minn == 0))
  11. {
  12. int ans = 0;
  13. ans += (a / minn) - 1, ans += (b / minn) - 1, ans += (c / minn) - 1;
  14. if(ans <= 3)
  15. {
  16. cout << "YES" << '\n';
  17. return;
  18. }
  19. }
  20. cout << "NO" << '\n';
  21. }
  22. signed main()
  23. {
  24. ios::sync_with_stdio(0);
  25. cin.tie(0); cout.tie(0);
  26. int t = 1; cin >> t;
  27. while(t --) solve();
  28. }

C. Perfect Square(几何)

题意:给一个n x n的字母正方形,n为偶数,要使向右旋转九十度后的字母重合,需要多少次操作。每次操作可以使当前字母变成字母表下一个字母。

思路:根据绕中心旋转的性质,我们只需要(n / 2)x (n / 2)的正方形,就能得到其他应该相同的位置。

找字母应该相同的点时,我们可以发现,把大的正方形分成四个(n / 2)x (n / 2)的小正方形后,这四个小正方形有四个参照点,顺时针依次为(0,0) (0,n-1) (n-1,n-1) (n-1,0),无论怎么旋转在小正方形里它们与参照点的相对位置是不变的。

  1. #include<bits/stdc++.h>
  2. #define double long double
  3. #define int long long
  4. using namespace std;
  5. using i64 = long long;
  6. void solve()
  7. {
  8. int n; cin >> n;
  9. vector<string>s(n);
  10. for(auto &ss : s) cin >> ss;
  11. int ans = 0;
  12. for(int i = 0; i < n / 2; i ++)
  13. {
  14. for(int j = 0; j < n / 2; j ++)
  15. {
  16. int sum = s[i][j] + s[j][n - 1 - i] + s[n - 1 - i][n - 1 - j] + s[n - 1 - j][i];
  17. int maxx = max({s[i][j], s[j][n - 1 - i], s[n - 1 - i][n - 1 - j], s[n - 1 - j][i]});
  18. ans += maxx * 4 - sum;
  19. }
  20. }
  21. cout << ans << '\n';
  22. }
  23. signed main()
  24. {
  25. ios::sync_with_stdio(false);
  26. cin.tie(nullptr);
  27. int t;
  28. cin >> t;
  29. while (t--) solve();
  30. }

D. Divide and Equalize(筛质数,数论)

注意这题卡常,尽量用数组。

题目:给一个长度为n的数组,你可以进行若干次操作:选出两个数ai和aj,以及任意的满足x|ai的x,使得ai = ai / x, aj = aj * x。问是否能让数组中所有数相等。

思路:

对所有数分解质因数并求出质因数的次数,每次操作可以使一个位置的数的质因数次数+1,另一个位置的数的质因数次数-1,那么进行若干次操作,我们可以尽量将质因数的次数匀给每个数。

显然,如果每个出现的质因数的次数是n的整数倍,操作后可以均分,使得每个数相等。

  1. #include<bits/stdc++.h>
  2. #define double long double
  3. #define int long long
  4. using namespace std;
  5. const int N = 1e6;
  6. vector<int>minp, primes;
  7. void sieve(int n)
  8. {
  9. minp.assign(n + 1, 0);
  10. primes.clear();
  11. for(int i = 2; i <= n; i ++)
  12. {
  13. if(minp[i] == 0) minp[i] = i, primes.push_back(i);
  14. for(auto p : primes)
  15. {
  16. if(i * p > n) break;
  17. minp[i * p] = p;
  18. if(p == minp[i]) break;
  19. }
  20. }
  21. }
  22. int cnt[N + 1];
  23. void solve()
  24. {
  25. int n; cin >> n;
  26. vector<int>a(n), stk;
  27. for(auto x : a)
  28. {
  29. cin >> x;
  30. while(x > 1)
  31. {
  32. int p = minp[x];
  33. x /= p;
  34. stk.push_back(p);
  35. cnt[p] ++;
  36. }
  37. }
  38. bool ok = 1;
  39. for (auto x : stk)
  40. {
  41. if (cnt[x] % n) ok = 0;
  42. cnt[x] = 0;
  43. }
  44. cout << (ok ? "YES" : "NO") << '\n';
  45. }
  46. signed main()
  47. {
  48. ios::sync_with_stdio(false);
  49. cin.tie(nullptr);
  50. sieve(N);
  51. int t; cin >> t;
  52. while (t--) solve();
  53. }

E. Block Sequence(dp)

很激动第一次十几分钟一发命中dp,感觉比D好写一些。

题目:对于每个块,满足第一个数是长度len,后面紧跟着len个数,如4 x x x x是一个块。需要执行若干次删除操作使数组由多个块组成。

思路:

定义dp[i]为使得数组i~n变成连续块的最小操作数。

状态转移:

1.每个数都可以选择删除自己dp[i] = dp[i + 1] + 1

2.如果之后的个数没有a[i]个,那么只能由右边的数转移来dp[i] = dp[i + 1] + 1

如果之后的个数恰好等于a[i]个,那么形成一个块dp[i]=0

如果之后的个数小于a[i]个,那么在形成了长度为len的块之后,需要接上后面的块的最小操作数

dp[i] = dp[i + a[i] + 1]

  1. #include<bits/stdc++.h>
  2. #define double long double
  3. #define int long long
  4. using namespace std;
  5. const int N = 1e6;
  6. void solve()
  7. {
  8. int n; cin >> n;
  9. vector<int>a(n + 1), dp(n + 2);
  10. for(int i = 1; i <= n; i ++) cin >> a[i];
  11. dp[n + 1] = 0;
  12. for(int i = n; i >= 0; i --)
  13. {
  14. if(a[i] + i > n) dp[i] = dp[i + 1] + 1;
  15. else if(a[i] + i == n) dp[i] = 0;
  16. else dp[i] = dp[i + a[i] + 1];
  17. dp[i] = min(dp[i], dp[i + 1] + 1);
  18. }
  19. cout << dp[0] << '\n';
  20. }
  21. signed main()
  22. {
  23. ios::sync_with_stdio(false);
  24. cin.tie(nullptr);
  25. int t; cin >> t;
  26. while (t--) solve();
  27. }

F - Minimum Maximum Distance(树形结构,bfs)

题目:给一棵n个点的树,其中k个点有标记。定义f(i)为点i到所有标记点的距离中的最大值。要求输出min(f(1)~f(n))。

思路:先求出所有f(i),再算最小值。

要求出f(i):

首先,我们使点1为根,求出深度最大的标记点a。我们可以发现,除a点所在的子树外所有子树上面的所有点的 f(i) 等于它们各自到 a 的距离,同时f(1)也等于到a的距离,如下图红色部分已经解决。

然后我们找出离a距离最大的标记点b。

如果b在上边已经解决的位置,那么剩下的所有点都不跟b在同一子树,剩下的点的距离f(i)要么等于到a的距离要么等于到b的距离。

如果b不在上边已经解决的位置,又因为最大距离不超过maxdeep(a)。故剩下的点的距离f(i)要么等于到a的距离要么等于到b的距离。所有点得到解决。

综上所述,f(i)要么等于distance(i,a)要么等于distance(i,b),两者取最大值。最后在所有f(i)里取最小值。

  1. #include<bits/stdc++.h>
  2. #define double long double
  3. #define int long long
  4. using namespace std;
  5. const int N = 1e6;
  6. void solve()
  7. {
  8. int n, k; cin >> n >> k;
  9. vector<int>mark(n);
  10. for(int i = 0; i < k; i ++)
  11. {
  12. int x; cin >> x;
  13. x --;
  14. mark[x] = 1;
  15. }
  16. vector<vector<int>>adj(n);
  17. for(int i = 0; i < n - 1; i ++)
  18. {
  19. int a, b; cin >> a >> b;
  20. a --, b --;
  21. adj[a].push_back(b);
  22. adj[b].push_back(a);
  23. }
  24. vector<int>dis(n);
  25. auto bfs = [&](int x)
  26. {
  27. dis.assign(n, - 1);
  28. queue<int>q;
  29. q.push(x);
  30. dis[x] = 0;
  31. while(q.size())
  32. {
  33. int u = q.front();
  34. q.pop();
  35. for(auto v : adj[u])
  36. {
  37. if(dis[v] != -1) continue;
  38. dis[v] = dis[u] + 1;
  39. q.push(v);
  40. }
  41. }
  42. int t = -1;
  43. for(int i = 0; i < n; i ++)
  44. {
  45. if(mark[i] && (t == -1 || dis[i] > dis[t])) t = i;
  46. }
  47. return t;
  48. };
  49. int a = bfs(0), b = bfs(a);
  50. auto f = dis;
  51. bfs(b);
  52. int ans = 1e9;
  53. for(int i = 0; i < n; i ++)
  54. {
  55. ans = min(ans, max(f[i], dis[i]));
  56. }
  57. cout << ans << '\n';
  58. }
  59. signed main()
  60. {
  61. ios::sync_with_stdio(false);
  62. cin.tie(nullptr);
  63. int t; cin >> t;
  64. while (t--) solve();
  65. }

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号