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

Alex_Wei
**搬运于
2025-08-24 22:36:48,当前版本为作者最后更新于2022-03-07 15:16:17,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
提供一个不需要 Pollard - rho 的做法。
记 的前缀和数组为 ,容易发现若 则无解,否则答案为 $\left(\dfrac {s_n} q - 1\right) + (n - 1) - 2\sum\limits_{i = 1} ^ {n - 1} [q\mid s_i]$。这是因为我们考虑将所有数全部合并再分裂,能够整除 的前缀和对应的切割点处不用分裂再合并,可以减少两步。
考虑这样一个朴素的暴力:对每个 的因数均求一遍答案。时间复杂度 。由于 可达 ,且 内最大的约数个数级别为 ,所以无法接受。
注意到实际上只需求 。考虑每个 对 的每个因数 的贡献。显然, 对所有 的因数有贡献。设 ,则任意 均需要加上 。这是高维前缀和的形式,因此这一部分容易做到 ,后面带一个 是因为要把所有因子用 map 映射到一个较小的范围内,否则无法存储结果。哈希表如 gp_hash_table 应该可以去掉这个 。
问题只剩下分解质因数了。不想写 Pollard - rho 怎么办?考虑只分解到 ,即用 以内的质因子试除 。如果最终结果 ,说明剩下的 是一个质数(否则就被试除掉了),否则说明 有两个大于 的质因子(不一定不同)。对于前者,我们已经成功分解质因数。对于后者,注意到此时 的因子个数不超过 ,于是直接暴力即可。
时间复杂度 $n\max\limits_{i \leq 10 ^ 6} d(i) + n\log (s_n) + d(s_n)\omega(s_n)\log d(s_n)$。代码并不是很可读。
#include <bits/stdc++.h> using namespace std; #define ll long long const int N = 2e5 + 5; ll n, q, a[N], pr[N]; int pw[N], cnt, ppw[N]; map <ll, ll> mp; int f[N]; int calc(int *pw) { int res = 0; for(int i = 1; i <= cnt; i++) res += pw[i] * ppw[i]; return res; } ll rev(int x) { ll res = 1; for(int i = 1; i <= cnt; i++) { int d = x / ppw[i] % (pw[i] + 1); for(int j = 1; j <= d; j++) res *= pr[i]; } return res; } int fix, cpw[N]; void dfs(int id) { if(id > cnt) { int cur = calc(cpw); f[cur - ppw[fix]] += f[cur]; return; } for(int i = pw[id]; i >= (id == fix); i--) cpw[id] = i, dfs(id + 1); } void check() { ll tmp = a[n]; for(int i = 2; i <= 1e6; i++) if(tmp % i == 0) { pr[++cnt] = i; while(tmp % i == 0) pw[cnt]++, tmp /= i; } if(tmp > 1e12) return; if(tmp > 1) pr[++cnt] = tmp, pw[cnt] = 1; ppw[cnt] = 1; for(int i = cnt - 1; ~i; i--) ppw[i] = ppw[i + 1] * (pw[i + 1] + 1); for(int i = 1; i < n; i++) { ll tmp = a[i]; for(int j = 1; j <= cnt; j++) { int cur = 0; while(tmp % pr[j] == 0) cur++, tmp /= pr[j]; cpw[j] = min(pw[j], cur); } f[calc(cpw)]++; } for(int i = 1; i <= cnt; i++) fix = i, dfs(1); for(int i = 0; i < ppw[0]; i++) mp[rev(i)] = n - 1 + a[n] / rev(i) - 1 - f[i] * 2; } int main() { cin >> n; for(int i = 1; i <= n; i++) cin >> a[i], a[i] += a[i - 1]; check(), cin >> q; for(int i = 1; i <= q; i++) { ll x; cin >> x; if(a[n] % x) {puts("-1"); continue;} if(!mp[x]) { ll ans = 0; for(int j = 1; j < n; j++) ans += a[j] % x == 0; mp[x] = n - 1 + a[n] / x - 1 - ans * 2; } cout << mp[x] << "\n"; } return 0; } /* stupid mistakes: 进制转换写错了 rev : res *= pr[i] -> *= pr[j] */
- 1
信息
- ID
- 7527
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者