原来我们都被诈骗了。
由于 u→v 的边满足 u<v,所以 1…n 一定是这张图的一个拓扑序。
而且题目的模拟顺序其实和拓扑序是一样的,因此考虑按照拓扑序来模拟这些操作。
考虑现在前 i−1 个点已经全部被清零,要怎么拓展到 i 的情况。
设当前 i 实际有 ai 个物品,上限存储 ci 个物品,当前答案为 ans。显然操作 ans 次可以使 i 添加 ai 个物品,且前面清零,那么我们操作 ans×cigcd 次就可以清空 1 \dots i。
然后还要实时更新 a 数组,其实暴力更新就行了,每轮内每条边只会被更新一次。
时间复杂度 O(nm)。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 15, M = 3e4 + 15, mod = 998244353;
int n, m;
int h[N], e[M], ne[M], idx = 0;
long long a[N], c[N];
inline void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; }
inline long long gcd(long long a, long long b) { return b ? gcd(b, a % b) : a; }
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%lld", &c[i]), h[i] = -1;
for (int i = 1, u, v; i <= m; i++) scanf("%d%d", &u, &v), add(u, v);
long long ans = 1; a[1] = 1;
for (int i = 1; i <= n; i++) {
long long k = c[i] / gcd(a[i], c[i]);
for (int j = 1; j <= n; j++) a[j] *= k; (ans *= k) %= mod;
for (int u = 1; u <= n; u++) {
for (int j = h[u]; ~j; j = ne[j]) { int v = e[j]; a[v] += a[u] / c[u]; }
a[u] %= c[u];
}
}
printf("%lld\n", ans);
return 0;
}