QOJ #5573. Holiday Regifting 题解

Description

有一个 nn 个点的图,有 mm 条有向边 uvu \to v,保证 u<vu<v,每个点有一个 cic_i

一开始每个点有一个点权 aia_i。每次操作可以给 11 号点的点权加上 11。如果一个点的 ai=cia_i = c_i,那么 ai0a_i \gets 0,并且所有 ii 指向的点 jj,都会 ajaj+1a_j \gets a_j + 1。求多少次之后所有 aia_i 会再一次全变成 00。答案模 998244353998244353

1n104,1m3×1041 \le n \le 10^4,1 \le m \le 3\times 10^4

Solution

由于每条边满足 u<vu<v,所以每个点 ii 的点权只和小于 ii 的点有关,考虑从小到大确定答案。

假设枚举到了 ii,如果 ai0a_i\neq 0,则需要让 <i<i 的点继续操作,直到 ai=0a_i=0

由于前面的已经确定了最优方案,所以一定是整体乘一个倍数,然后让 aia_i 变成 00

容易发现这个倍数是 cigcd(ai,ci)\displaystyle\frac{c_i}{\gcd(a_i,c_i)},乘上它并更新更新后面的数即可。

时间复杂度:O(n2+nm)O(n^2+nm)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 1e4 + 5, kMod = 998244353;

int n, m;
int c[kMaxN];
int64_t a[kMaxN];
std::vector<int> G[kMaxN];

void dickdreamer() {
std::cin >> n >> m;
for (int i = 1; i <= n; ++i) std::cin >> c[i];
for (int i = 1; i <= m; ++i) {
int u, v;
std::cin >> u >> v;
G[u].emplace_back(v);
}
int ans = 1;
a[1] = 1;
for (int i = 1; i <= n; ++i) {
int coef = c[i] / std::__gcd((int)a[i], c[i]);
ans = 1ll * ans * coef % kMod;
for (int j = i; j <= n; ++j) a[j] *= coef;
for (int j = i; j <= n; ++j) {
for (auto k : G[j]) {
a[k] += a[j] / c[j];
}
a[j] %= c[j];
}
}
std::cout << ans << '\n';
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
// std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

QOJ #5573. Holiday Regifting 题解
https://sobaliuziao.github.io/2025/04/09/post/1843e060.html
作者
Egg_laying_master
发布于
2025年4月9日
许可协议