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;
}
posted @ 2020-08-14 14:14  Creed-qwq  阅读(112)  评论(0编辑  收藏  举报