Newcoder 40 F.珂朵莉的约数(数论+莫队算法)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/V5ZSQ/article/details/83301735

Description

珂朵莉给你一个长为 n n 的序列,有 m m 次查询

每次查询给两个数 l , r l,r

s s 为区间 [ l , r ] [l,r] 内所有数的乘积

s s 的约数个数 m o d   1000000007 mod\ 1000000007

Input

第一行两个正整数 n , m n,m

第二行一个长为 n n 的序列

之后 m m 行每行两个数 l l r r

( n , m 1 0 5 , a i 1 0 6 ) (n,m\le 10^5,a_i\le 10^6)

Output

对于每个询问,输出一个整数表示答案

Sample Input

5 5
64 2 18 9 100
1 5
2 4
2 3
1 4
3 4

Sample Output

165
15
9
45
10

Solution

对于不超过 1000 1000 的素数直接维护每个素数的幂指数 + 1 +1 的前缀乘积即可(共 168 168 个),而每个数超过 1000 1000 的素因子至多一个,这部分用莫队维护下区间这些素因子的幂指数 + 1 +1 的乘积即可,此处需要线性预处理逆元,时间复杂度 O ( n n + 168 m ) O(n\sqrt{n}+168m)

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=100005;
#define mod 1000000007
int add(int x,int y)
{
	x+=y;
	if(x>=mod)x-=mod;
	return x;
}
int mul(int x,int y)
{
	ll z=1ll*x*y;
	return z-z/mod*mod;
}
struct node
{
    int l,r,id,ans;
}q[maxn];
int n,m,c[maxn],pos[maxn],ans;
int cmp1(node x,node y)
{
    if(pos[x.l]!=pos[y.l])return x.l<y.l;
    return x.r<y.r;
}
int cmp2(node x,node y)
{
    return x.id<y.id;
}
int p[maxn],res,mark[maxn];
void init(int n=1000)
{
	for(int i=2;i<=n;i++)
		if(!mark[i])
		{
			p[res++]=i;
			for(int j=2*i;j<=n;j+=i)mark[j]=1;
		}
}
int num[1000005],inv[1000005],f[170][maxn];
void deal(int x,int id)
{
	for(int i=0;i<res;i++)f[i][id]=f[i][id-1];
	for(int i=0;i<res;i++)
	{	
		if(x<p[i])break; 
		while(x%p[i]==0)x/=p[i],f[i][id]++;
	} 
	c[id]=x;
}
void update(int x,int v)//表示对第x个元素做删除(v=-1)或者添加(v=1) 
{
	if(c[x]==1)return ;
	ans=mul(ans,inv[num[c[x]]+1]);
	num[c[x]]+=v;
	ans=mul(ans,num[c[x]]+1);
}
int main()
{
	init(1000);
	inv[1]=1;
	for(int i=2;i<=1e6+1;i++)inv[i]=mul(mod-mod/i,inv[mod%i]);
    scanf("%d%d",&n,&m);
    int mm=(int)sqrt(n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&c[i]);
        deal(c[i],i);
        pos[i]=(i-1)/mm+1;
    }
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].id=i;
        q[i].ans=1;
        for(int j=0;j<res;j++)q[i].ans=mul(q[i].ans,f[j][q[i].r]-f[j][q[i].l-1]+1);
    }
    sort(q,q+m,cmp1);
    ans=1;
    int l=1,r=0;
    for(int i=0;i<m;i++)
    {
        while(r<q[i].r)update(r+1,1),r++;
        while(r>q[i].r)update(r,-1),r--;
        while(l<q[i].l)update(l,-1),l++;
        while(l>q[i].l)update(l-1,1),l--;
        q[i].ans=mul(q[i].ans,ans); 
    }
    sort(q,q+m,cmp2);
    for(int i=0;i<m;i++)printf("%d\n",q[i].ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/V5ZSQ/article/details/83301735