AT2249 ニワンゴくんの約数
链接:https://www.luogu.com.cn/problem/AT2249
题意:给定一个序列,每次查询一个区间乘积的约数个数
AtCoder的题还是比较nb的啊
显然考虑分解质因数
然后又很自然地想到根号分治一下
小于\(\sqrt{n}\)的素数可以用前缀和解决
大于\(\sqrt{n}\)的素数可以用莫队解决
就完了。。
#include<bits/stdc++.h>
#define M 80
#define N 120000
#define eps 1e-7
#define inf 1e9+7
#define db double
#define ll long long
#define ldb long double
#define ull unsigned long long
using namespace std;
inline int read()
{
char ch=0;
int x=0,flag=1;
while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();}
return x*flag;
}
const int mo=1e9+7;
struct query{int x,l,r;}p[N];
bool is_prime[N];
int a[N],f[N],u[N],d[N],cnt[N],bel[N],Ans[N],prime[N],s[M][N];
bool cmp(query a,query b)
{
if(bel[a.l]!=bel[b.l])return bel[a.l]<bel[b.l];
else return a.r<b.r;
}
int ksm(int x,int k)
{
int ans=1;
while(k)
{
if(k&1)ans=1ll*ans*x%mo;
k>>=1;x=1ll*x*x%mo;
}
return ans;
}
int inv(int x){return ksm((x%mo+mo)%mo,mo-2);}
int main()
{
int n=read(),q=read(),sz=max(sqrt(n),1.0),m=0,num=0;
for(int i=1;i<=n;i++)a[i]=read(),m=max(m,a[i]),bel[i]=(i-1)/sz+1;
for(int i=1;i<=q;i++)p[i].x=i,p[i].l=read(),p[i].r=read();
sort(p+1,p+q+1,cmp);
memset(is_prime,true,sizeof(is_prime));
is_prime[0]=is_prime[1]=false;
for(int i=2;i<=m;i++)
{
if(is_prime[i])prime[++num]=i;
for(int j=1;j<=num;j++)
{
int x=i*prime[j];
if(x>m)break;
is_prime[x]=false;
if(i%prime[j]==0)break;
}
}
m=max(sqrt(m),1.0);
int len=1;
while(prime[len+1]<=m)len++;
for(int i=1;i<=n;i++)
{
int x=a[i];
for(int k=1;k<=len;k++)
{
while(x%prime[k]==0)x/=prime[k],s[k][i]++;
s[k][i]+=s[k][i-1];
}
f[i]=x;
}
for(int i=1;i<=n+1;i++)u[i]=1ll*(i+1)*inv(i)%mo,d[i]=1ll*(i-1)*inv(i)%mo;
int L=1,R=1,ans;
if(f[1]!=1)ans=2;else ans=1;
cnt[f[1]]++;
for(int i=1;i<=q;i++)
{
int id=p[i].x,l=p[i].l,r=p[i].r;
while(L>l)
{
L--;
int x=f[L];
if(x!=1)ans=1ll*ans*u[cnt[x]+1]%mo;
cnt[x]++;
}
while(R<r)
{
R++;
int x=f[R];
if(x!=1)ans=1ll*ans*u[cnt[x]+1]%mo;
cnt[x]++;
}
while(L<l)
{
int x=f[L];
if(x!=1)ans=1ll*ans*d[cnt[x]+1]%mo;
cnt[x]--;
L++;
}
while(R>r)
{
int x=f[R];
if(x!=1)ans=1ll*ans*d[cnt[x]+1]%mo;
cnt[x]--;
R--;
}
Ans[id]=ans;
for(int k=1;k<=len;k++)Ans[id]=1ll*Ans[id]*(s[k][r]-s[k][l-1]+1)%mo;
}
for(int i=1;i<=q;i++)printf("%d\n",(Ans[i]%mo+mo)%mo);
return 0;
}