[Ynoi2015] 此时此刻的光辉
[Ynoi2015] 此时此刻的光辉
买了新的草稿纸,所以来水一下这题。
挺简单的,直接Pollard-Rho
质因数分解之后莫队就行了。
但是为了卡常可以用一个小trick
,把比较小的质因子用处理了,这样子莫队和Pollard-Rho
都会快一些。
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_map>
using namespace std;
template <typename T>
inline void read(T &x) {
x = 0; int f = 0; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48);
if(f) x = ~x + 1;
}
const int B = 1000;
int vis[B + 10], p[B + 10], totB;
void Sieve() {
for(int i = 2; i <= B; ++i) {
if(!vis[i]) p[++totB] = i;
for(int j = 1; j <=totB && i * p[j] <= B; ++j) {
vis[i * p[j]] = 1;
if(i % p[j] == 0) break;
}
}
}
using LL = long long;
using ull = unsigned long long;
using vi = vector<int>;
ull mul(ull x, ull y, ull P) {
LL res = x * y - P * ull(1.L / P * x * y);
return res + P * (res < 0) - P * (res >= (LL)P);
}
ull fpow(ull x, ull pnt, ull P) {
if(x >= P) x %= P;
ull res = 1;
for(; pnt; pnt >>= 1, x = mul(x, x, P))
if(pnt & 1) res = mul(res, x, P);
return res;
}
const ull A[] = {2,325,9375,28178,450775,9780504,1795265022};
bool isPrime(ull n) {
if(n < 3 || !(n & 1)) return n == 2;
ull s = __builtin_ctzll(n - 1), t = n >> s;
for(ull a : A) {
ull p = fpow(a, t, n), i = s;
while(p != 1 && p != n - 1 && a % n && i--)
p = mul(p, p, n);
if(p != n - 1 && i != s) return false;
}
return true;
}
int pollard(ull n) {
auto f = [n](ull x) {return mul(x, x, n) + 1;};
ull x = 0, y = 0, t = 30, prd = 2, i = 1, q;
while(t++ % 40 || __gcd(prd, n) == 1) {
if(x == y) x = ++i, y = f(x);
if((q = mul(prd, max(x, y) - min(x, y), n))) prd = q;
x = f(x), y = f(f(y));
}
return __gcd(prd, n);
}
vi factor(int n) {
if(n == 1) return {};
if(isPrime(n)) return {n};
int x = pollard(n);
auto l = factor(x), r = factor(n / x);
for(auto x : r) l.emplace_back(x);
return l;
}
const int N = 1e5 + 10;
struct Query {
int l, r, id;
}q[N];
const int QB = 384;
bool cmp(Query x, Query y) {
return ((x.l / QB) == (y.l / QB)) ?
(((x.l / QB) & 1) ? (x.r < y.r) : (x.r > y.r)) :
(x.l < y.l);
}
const LL P = 19260817;
LL inv[N * 32], cur = 1;
int tot;
unordered_map<int, int> id;
vector<int> fac[N];
int buc[N << 2];
inline void add(int x) {
for(auto p : fac[x]) {
cur = cur * inv[buc[p] + 1] % P;
++buc[p];
cur = cur * (buc[p] + 1) % P;
}
}
inline void del(int x) {
for(auto p : fac[x]) {
cur = cur * inv[buc[p] + 1] % P;
--buc[p];
cur = cur * (buc[p] + 1) % P;
}
}
int n, m, a[N], cnt[N][200], ans[N];
int main() {
Sieve();
read(n), read(m);
inv[1] = 1;
for(int i = 2; i <= n * 32; ++i) inv[i] = (P - P / i) * inv[P % i] % P;
for(int i = 1; i <= n; ++i) {
read(a[i]);
int tmp = a[i];
for(int j = 1; j <= totB; ++j) {
cnt[i][j] = cnt[i - 1][j];
while(tmp % p[j] == 0) ++cnt[i][j], tmp /= p[j];
}
fac[i] = factor(tmp);
for(auto &x : fac[i]) {
auto &p = id[x];
if(!p) p = ++tot;
x = p;
}
}
for(int i = 1; i <= m; ++i) read(q[i].l), read(q[i].r), q[i].id = i;
sort(q + 1, q + m + 1, cmp);
for(int l = 1, r = 0, i = 1; i <= m; ++i) {
while(r < q[i].r) add(++r);
while(l > q[i].l) add(--l);
while(r > q[i].r) del(r--);
while(l < q[i].l) del(l++);
LL tmp = cur;
for(int j = 1; j <= totB; ++j)
tmp = tmp * (cnt[q[i].r][j] - cnt[q[i].l - 1][j] + 1) % P;
ans[q[i].id] = tmp;
}
for(int i = 1; i <= m; ++i) printf("%d\n",ans[i]);
}