1 条题解
-
0
自动搬运
来自洛谷,原作者为

Pengzt
自己选择的路,跪着也要走完。搬运于
2025-08-24 23:08:06,当前版本为作者最后更新于2025-01-08 17:10:23,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
waht 先生的法阵
Problem
给定数列 。需要支持 次操作,分为以下两种。
- 区间乘 ()。
- 给出 ,按以下方法得到答案:记答案为 ,初始时为 。从 开始,每次 后 。当 大于 时结束。求出 对 取模的值。
数据范围:$1 \le n, Q \le 2.5\times 10^5, a_i \in [1, 998244353) \cap \mathbb{Z}$。
Sol
这个东西和 CF1491H Yuezheng Ling and Dynamic Tree 这道题很像啊。不难发现,对于 , 的变化次数是非常有限的,可以直接均摊出来。直接考虑分块。
不妨记 和 分别表示 跳出当前块的右端点时的位置和经过的权值和。对于散块可以暴力更新。对于整块:
- 如果块内所有 。跳过该块。
- 否则找到所有会被更改的点,暴力更新。
如果块长取 ,则一个点更改一次的时间复杂度是 的。判断整块是否需要更新可以枚举 的所有质因数,然后看这块中有没有数乘上这个质因数后 会变化(这个可以对每个数记录还有那些质因数以及次数,然后就是查询区间是否有值)。
对于枚举质数的部分,时间复杂度为:。
查询的复杂度:。
现在考虑一个数会修改多少次,显然当 都是 的时候变化次数最多。考虑质数 会产生多少的贡献,这个显然为 $\sum\limits_{i=1}^{+\infty} \lfloor \frac{n}{p^i} \rfloor \le \sum\limits_{i=1}^{+\infty} \frac{n}{p^i} = \frac{n}{p - 1}$,即所有数分解质因数后 的出现次数和。所以最后所有数的变化次数为 。
clx 表示这是欧依的。根据埃氏筛的时间复杂度分析,这个是 的。所以修改的时间是 。
当 时,即 时有最小值。时间复杂度为:。题解有不对的地方欢迎大家指正!
Code
代码没有卡过常,跑得很慢。
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> pii; #define fi first #define se second mt19937_64 eng(time(0) ^ clock()); template<typename T> T rnd(T l, T r) { return eng() % (r - l + 1) + l; } int pC, pri[250005]; bool vis[250005]; vector<int> d[250005]; void Init(int n) { for (int i = 2; i <= n; i++) { if (!vis[i]) pri[++pC] = i; for (int j = 1; j <= pC && i * pri[j] <= n; ++j) { vis[i * pri[j]] = 1; if (i % pri[j] == 0) break; } } for (int i = 1; i <= pC && pri[i] <= n; i++) for (int j = pri[i]; j <= n; j += pri[i]) d[j].emplace_back(i); memset(vis, 0, sizeof(vis)); } const int B = 200, P = 998244353; int n, m; int bel[250005], L[250005], R[250005], g[250005], re[250005], to[250005]; ll a[250005], sum[250005], laz[250005]; set<int> s[250005]; int tpt, stkt[250005]; int tp, stk[250005]; void Calc(int i) { int x = i; sum[i] = 0; while (x <= R[bel[i]]) { (sum[i] += a[x]) %= P; x += g[x]; } to[i] = x; } bool arv[250005]; void Update(int x) { for (int i = R[x]; i >= L[x]; i--) { sum[i] = a[i] % P; if (i + g[i] <= R[x]) { (sum[i] += sum[i + g[i]]) %= P, to[i] = to[i + g[i]]; } else { to[i] = i + g[i]; } } } void Modify(int l, int r, ll c) { int x = bel[l], y = bel[r]; int now = c; for (int i : d[c]) { if ((int) s[i].size() == 0) continue; int cnt = 0; while (now % pri[i] == 0) now /= pri[i], cnt++; auto pl = s[i].lower_bound(l); auto pr = s[i].lower_bound(r + 1); for (auto it = pl; it != pr; it++) { int p = *it, tmp = cnt; while (re[p] % pri[i] == 0 && tmp > 0) re[p] /= pri[i], g[p] *= pri[i], tmp--; if (re[p] % pri[i]) stkt[++tpt] = p; if (!vis[p]) stk[++tp] = p, vis[p] = 1; } while (tpt) s[i].erase(stkt[tpt--]); } for (int i = 1; i <= tp; i++) { Calc(stk[i]); Update(bel[stk[i]]); } for (int i = 1; i <= tp; i++) vis[stk[i]] = 0; tp = 0; if (x == y) { for (int i = l; i <= r; i++) a[i] = a[i] * c % P; Update(x); } else { for (int i = l; i <= R[x]; i++) a[i] = a[i] * c % P; for (int i = L[y]; i <= r; i++) a[i] = a[i] * c % P; Update(x), Update(y); for (int i = x + 1; i < y; i++) laz[i] = laz[i] * c % P; } } int main() { scanf("%d%d", &n, &m); Init(250000); for (int i = 1; i <= n; i++) scanf("%lld", a + i); for (int i = 1; i <= n; i++) bel[i] = (i - 1) / B + 1; for (int i = 1; i <= bel[n]; i++) L[i] = (i - 1) * B + 1, R[i] = min(n, i * B); for (int i = 1; i <= bel[n]; i++) laz[i] = 1; for (int i = 1; i <= n; i++) { g[i] = __gcd((ll) i, a[i]); re[i] = i / g[i]; for (int j : d[re[i]]) s[j].emplace(i); } for (int i = 1; i <= n; i++) Calc(i); for (int _ = 1, op, x, y, z; _ <= m; _++) { scanf("%d%d", &op, &x); if (op == 1) { scanf("%d%d", &y, &z); Modify(x, y, z); } else { ll ans = 0; for (int i = x; i <= n; i = to[i]) (ans += sum[i] * laz[bel[i]] % P) %= P; printf("%lld\n", ans); } } return 0; }
- 1
信息
- ID
- 11320
- 时间
- 5000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者