题目链接:传送门
在太阳西斜的这个世界里,置身天上之森。等这场战争结束之后,不归之人与望眼欲穿的众人, 人人本着正义之名,长存不灭的过去、逐渐消逝的未来。我回来了,纵使日薄西山,即便看不到未来,此时此刻的光辉,盼君勿忘。
珂朵莉最可爱了,珂朵莉的题最毒瘤了qwq
然而这道题……
首先这道题显然是莫队qwq。
把质数筛出来,把每个数大莉分解质因数。
若
n
n
n分解质因数为
p
1
a
1
∗
p
2
a
2
∗
.
.
.
p
k
a
k
p_1^{a_1}*p_2^{a_2}*...p_k^{a_k}
p1a1∗p2a2∗...pkak,则
n
n
n的因数个数为
Π
i
=
1
k
(
a
i
+
1
)
\Large\Pi\large_{i=1}^{k}(a_i+1)
Πi=1k(ai+1)(简单,不解释)。
把每个数的质因数和它的指数存在一个
v
e
c
t
o
r
vector
vector里面。
每次统计的时候珂以大莉遍历每一个质因数,然后暴莉统计答案。
然后……稳稳的TLE……QAQ
发现珂以把逆元线性筛出来,于是复杂度降一个
O
(
l
o
g
n
)
O(logn)
O(logn)……
然后……还是稳稳的TLE……QAQ
用上所有优化常数的办法,发现一直卡在82分qwq
于是我们可以考虑上网搜题解。
搜出一个玄学优化:
之前的暴莉莫队是把所有指数的出现次数大莉统计出来。
发现比较小的质数的指数较大,所以能不能预处理出这一部分质数的指数呢?
发现是珂以的qwq
用
s
u
m
[
i
]
[
j
]
sum[i][j]
sum[i][j]表示前
i
i
i个数的乘积,第
j
j
j个质数的指数是多少。
发现
s
u
m
[
i
]
[
j
]
sum[i][j]
sum[i][j]就是一个指数的前缀和qwq。
所以每次用前缀和算出
<
=
160
<=160
<=160的质数的指数之积,然后其他指数用莫队来求即可。
(别问我为什么是
160
160
160,题解大法好qwq)
时间复杂度……大概
O
(
n
n
)
O(n\sqrt n)
O(nn)?
代码
//LXL毒瘤~
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<vector>
#include<map>
#define re register int
#define rl register ll
#define mod 19260817
using namespace std;
typedef long long ll;
int read() {
re x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') {
x=10*x+ch-'0';
ch=getchar();
}
return x*f;
}
inline void write(int x) {
if(x>9) write(x/10);
putchar(x%10+'0');
}
namespace I_Love {
const int Size=100005;
const int L=160;
int n,m,siz,a[Size],belong[Size],inv[2000005];
struct Query {
int l,r,id;
} Q[Size];
inline bool comp(Query x,Query y) {
if(belong[x.l]!=belong[y.l]) return x.l<y.l;
return x.r<y.r;
}
int tot,prime[1000005];
int sum[Size][161];
bool vis[Size*10];
map<int,int> pos;
void GetPrime(int maxn) {
//筛质数
vis[1]=true;
//卡常,除2以外的偶数不是质数,先处理出来
for(re i=4; i<=maxn; i+=2) vis[i]=true;
prime[++tot]=2; pos[2]=1;
for(re i=3; i<=maxn; i+=2) {
if(!vis[i]) {
prime[++tot]=i;
pos[i]=tot;
for(re j=i*i; j<=maxn; j+=i) {
vis[j]=true;
}
}
}
}
struct Prime {
int id,t;
};
vector<Prime> div[Size];
void Divide(int x) {
//对a[x]分解质因数
int num=a[x];
//注意这里要写成prime[i]*prime[i]<=num
for(re i=1; i<=tot && prime[i]*prime[i]<=num; i++) {
int now=0;
while(!(num%prime[i])) {
num/=prime[i];
now++;
}
if(now) {
// div[x].push_back(tmp);
if(i<=L) {
sum[x][i]+=now;
} else {
Prime tmp; tmp.id=i; tmp.t=now;
div[x].push_back(tmp);
}
}
}
if(num!=1) {
int id=pos[num];
if(!id) {
id=pos[num]=++tot;
prime[tot]=num;
}
if(id<=L) {
sum[x][id]++;
} else {
Prime tmp; tmp.id=id; tmp.t=1;
div[x].push_back(tmp);
}
}
}
ll ans,c[Size<<1];
int out[Size<<1];
inline void add(int x) {
int len=div[x].size();
for(re i=0; i<len; i++) {
Prime now=div[x][i];
ans=ans*(ll)inv[c[now.id]]%mod;
c[now.id]+=now.t;
ans=ans*c[now.id]%mod;
}
}
inline void del(int x) {
int len=div[x].size();
for(re i=0; i<len; i++) {
Prime now=div[x][i];
ans=ans*(ll)inv[c[now.id]]%mod;
c[now.id]-=now.t;
ans=ans*c[now.id]%mod;
}
}
void Fujibayashi_Ryou() {
n=read();
m=read();
siz=n/sqrt(m*2.0/3.0);
int maxa=0;
for(re i=1; i<=n; i++) {
a[i]=read();
belong[i]=i/siz+1;
if(a[i]>maxa) {
maxa=a[i];
}
}
GetPrime(sqrt(maxa));
for(re i=1; i<=n; i++) {
//预处理前缀和
for(re j=0; j<=L; j++) sum[i][j]=sum[i-1][j];
Divide(i);
int len=div[i].size();
for(re j=0; j<len; j++) {
Prime now=div[i][j];
c[now.id]+=now.t;
}
}
int maxn=0;
for(re i=1; i<=tot; i++) {
if(c[i]>maxn) {
maxn=c[i];
}
}
maxn++;
inv[0]=inv[1]=1;
//线性求逆元
for(re i=2; i<=maxn; i++)
inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
for(re i=1; i<=tot; i++) c[i]=1;
for(re i=1; i<=m; i++) {
Q[i].l=read();
Q[i].r=read();
Q[i].id=i;
}
sort(Q+1,Q+1+m,comp);
int l=1,r=0;
ans=1;
for(re i=1; i<=m; i++) {
while(r<Q[i].r) add(++r);
while(r>Q[i].r) del(r--);
while(l<Q[i].l) del(l++);
while(l>Q[i].l) add(--l);
out[Q[i].id]=ans;
for(re j=1; j<=L; j++) {
out[Q[i].id]=(ll)out[Q[i].id]*(sum[Q[i].r][j]-sum[Q[i].l-1][j]+1)%mod;
}
}
for(re i=1; i<=m; i++) {
printf("%d\n",out[i]);
}
}
}
int main() {
I_Love::Fujibayashi_Ryou();
return 0;
}