题解 P5071 【[Ynoi2015]此时此刻的光辉】

诗乃

2019-10-25 21:54:21

Solution

不难发现,我们要求的是$\prod_{i=1}^{n}(a_i+1)$,其中$a_i$表示第$i$个质因子的出现次数。 考虑莫队。首先一起维护所有质因子的出现次数是肯定T飞的。 考虑根号分治。有一个性质,一个数最多只有一个大于$\sqrt{v}$的质因子。一个直接的思路是把小于$\sqrt{v}$的质数先拿出来做前缀和。佛说不行,小于$\sqrt{n}$的质数太多了。 我说,那就两个。有一个性质,一个数最多只有两个大于$^3\sqrt{v}$的质因子。一个直接的思路是把小于$^3\sqrt{v}$的质数先拿出来做前缀和,剩下的去莫队维护。 佛哭了,说这样可以AC。 具体的说,对于每一个输入的数分解质因数,将小于$^3\sqrt{v}$的质因子出现次数做前缀和,大于$^3\sqrt{v}$的数存起来在莫队时维护。莫队时,对于每一个询问先转移出大质因子的乘积,随后暴力遍历所有小于$^3\sqrt{v}$的质因子统计答案即可。 ```cpp #include <bits/stdc++.h> //#include <unordered_map> using namespace std; const int SV = 32000, MAXN = 100050, siz = 317, P = 19260817, S = 320; void read(int &x) { char ch; while(ch = getchar(), ch < '!'); x = ch - 48; while(ch = getchar(), ch > '!') x = (x << 3) + (x << 1) + ch - 48; } struct Qry {int l, r, id;} q[MAXN]; int cmp(Qry a, Qry b) {return a.l/siz == b.l/siz ? a.r < b.r : a.l < b.l;} struct PV {int p, v;}; bool notp[SV+5]; int p[SV+5], cntp, pre[MAXN][S+5], inv[P+1], ima, n, m, a[MAXN], ans[MAXN], id[SV+5], cnt[MAXN << 1], tot, pos[MAXN]; vector <PV> w[MAXN]; map <int, int> mp; void add(int x) { int l = w[x].size(); for(int i = 0; i < l; ++i) { int pp = w[x][i].p, v = w[x][i].v; ima = 1ll * ima * inv[cnt[pp] % P] % P; cnt[pp] += v; ima = 1ll * ima * (cnt[pp]) % P; } } void del(int x) { int l = w[x].size(); for(int i = 0; i < l; ++i) { int pp = w[x][i].p, v = w[x][i].v; ima = 1ll * ima * inv[cnt[pp] % P] % P; cnt[pp] -= v; ima = 1ll * ima * (cnt[pp] % P) % P; } } void init() { for(int i = 2; i <= SV; ++i) { if(!notp[i]) p[++cntp] = i, id[i] = cntp; for(int j = 1; j <= cntp && 1ll*i*p[j] <= SV; ++j) { notp[i * p[j]] = 1; if(i % p[j] == 0) break; } } inv[1] = 1; for(int i = 2; i <= P-1; ++i) inv[i] = 1ll*(P-P/i)*inv[P%i]%P; } void pus(int i, int x, int k) { if(x < p[S]) pre[i][id[x]] += k; else { if(!mp[x]) mp[x] = ++tot, pos[tot] = x; w[i].push_back((PV) {mp[x], k}); } } void Getpre() { for(int i = 1; i <= n; ++i) { int x = a[i]; for(int j = 1; p[j] * p[j] <= x && j <= cntp; ++j) if(x % p[j] == 0) { int cc = 0; for(; x % p[j] == 0; ++cc, x /= p[j]); pus(i, p[j], cc); } if(x != 1) pus(i, x, 1); for(int j = 1; j <= S; ++j) pre[i][j] += pre[i-1][j]; } } int main() { read(n); read(m); for(int i = 1; i <= n; ++i) read(a[i]); for(int i = 1; i <= m; ++i) read(q[q[i].id = i].l), read(q[i].r); sort(q+1, q+m+1, cmp); init(); Getpre(); ima = 1; for(int i = 1; i <= tot; ++i) cnt[i] = 1; for(int L = 1, R = 0, l, r, i = 1; i <= m; ++i) { l = q[i].l; r = q[i].r; while(R < r) add(++R); while(L > l) add(--L); while(R > r) del(R--); while(L < l) del(L++); ans[q[i].id] = ima; for(int j = 1; j <= S; ++j) ans[q[i].id] = 1ll*ans[q[i].id]*(pre[r][j]-pre[l-1][j]+1)%P; } for(int i = 1; i <= m; ++i) printf("%d\n", ans[i]); } ```