1
0

AtCoder-agc050_e.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. using int64 = long long;
  4. using i128 = __int128_t;
  5. constexpr int64 MOD = 998'244'353LL;
  6. int64 lcm_bounded(int64 a, int64 b) {
  7. return static_cast<int64>(static_cast<i128>(a / gcd(a, b)) * b);
  8. }
  9. int64 prefix_short_part(int64 time, int64 period, int64 remainder) {
  10. // Count integers t in [0,time) with t mod period < remainder.
  11. i128 result = static_cast<i128>(time / period) * remainder
  12. + min(time % period, remainder);
  13. return static_cast<int64>(result % MOD);
  14. }
  15. int64 sum_weight(int64 left, int64 right, int64 green, int64 period) {
  16. int64 base = green / period;
  17. int64 remainder = green % period;
  18. int64 length = (right - left) % MOD;
  19. int64 extra = (prefix_short_part(right, period, remainder)
  20. - prefix_short_part(left, period, remainder) + MOD) % MOD;
  21. return (base % MOD * length + extra) % MOD;
  22. }
  23. int64 weight_at(int64 time, int64 green, int64 period) {
  24. return green / period + (time % period < green % period ? 1 : 0);
  25. }
  26. int64 next_change(int64 time, int64 period, int64 remainder, int64 limit) {
  27. int64 next = (time / period + 1) * period;
  28. if (remainder != 0) {
  29. int64 block = time / period;
  30. int64 shifted = block * period + remainder;
  31. if (shifted <= time) ++block;
  32. if (block < limit / period) shifted = block * period + remainder;
  33. else shifted = limit;
  34. next = min(next, shifted);
  35. }
  36. return min(next, limit);
  37. }
  38. int main() {
  39. ios::sync_with_stdio(false);
  40. cin.tie(nullptr);
  41. array<int64, 3> green{}, red{}, period{};
  42. for (int i = 0; i < 3; ++i) {
  43. cin >> green[i] >> red[i];
  44. period[i] = green[i] + red[i];
  45. }
  46. array<int64, 3> reduced{};
  47. for (int i = 0; i < 3; ++i) {
  48. int j = (i + 1) % 3;
  49. int k = (i + 2) % 3;
  50. reduced[i] = lcm_bounded(gcd(period[i], period[j]),
  51. gcd(period[i], period[k]));
  52. }
  53. i128 reduced_lcm = reduced[0];
  54. for (int i = 1; i < 3; ++i) {
  55. reduced_lcm = reduced_lcm / gcd(static_cast<int64>(reduced_lcm % reduced[i]),
  56. reduced[i]) * reduced[i];
  57. }
  58. int64 horizon = static_cast<int64>(reduced_lcm);
  59. int integrated = 0;
  60. for (int i = 1; i < 3; ++i) {
  61. if (reduced[i] < reduced[integrated]) integrated = i;
  62. }
  63. if (integrated != 0) {
  64. swap(green[0], green[integrated]);
  65. swap(period[0], period[integrated]);
  66. swap(reduced[0], reduced[integrated]);
  67. }
  68. int64 compatible_green = 0;
  69. int64 current = 0;
  70. while (current < horizon) {
  71. int64 next = horizon;
  72. for (int i = 1; i < 3; ++i) {
  73. next = min(next, next_change(current, reduced[i],
  74. green[i] % reduced[i], horizon));
  75. }
  76. int64 other_weights = weight_at(current, green[1], reduced[1]) % MOD;
  77. other_weights = other_weights * (weight_at(current, green[2], reduced[2]) % MOD) % MOD;
  78. compatible_green = (compatible_green
  79. + other_weights * sum_weight(current, next, green[0], reduced[0])) % MOD;
  80. current = next;
  81. }
  82. int64 common12 = gcd(period[0], period[1]);
  83. i128 lcm12 = static_cast<i128>(period[0] / common12) * period[1];
  84. int64 common_with_third = gcd(static_cast<int64>(lcm12 % period[2]), period[2]);
  85. int64 repetitions = common12 % MOD * (common_with_third % MOD) % MOD;
  86. cout << compatible_green * repetitions % MOD << '\n';
  87. return 0;
  88. }