【51nod1642】区间欧拉函数

Description

求区间\([l,r]\)权值积的欧拉函数值。
详细题面

Solution

直接考虑一个数的欧拉函数如何计算,有:\(φ(x)=x\prod \dfrac{p-1}{p}\)\(p\)\(x\)的质因子)
要求一段区间权值积欧拉函数值其实就是要求这个区间包含不同质数的\(\dfrac{p-1}{p}\)的积乘以区间的积。

考虑离线,把询问按照\(r\)排序,区间不同质数乘积可以用树状数组维护。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;++i)
#define fd(i,j,k) for(int i=j;i>=k;--i)
using namespace std;
typedef long long ll;
const int N=2e5+10,mo=1e9+7;
struct node{
	int l,r,p;
}b[N];
int a[N],n;
ll s[N],tr[N];
int pos[N*5],an[N];
int pr[N],mp[N*5];
bool bz[N*5];
int mx=0;
void mul(int x,int t){
	for(;x<=n;x+=x&-x) tr[x]=tr[x]*t%mo;
}
ll calc(ll x){
	ll tmp=1;
	for(;x;x-=x&-x) tmp=tmp*tr[x]%mo;
	return tmp;
}
ll pow(ll x,int y){
	ll t=1;
	while(y){
		if(y&1) t=t*x%mo;
		y>>=1,x=x*x%mo;
	}
	return t;
}
bool cmp(node x,node y){
	return x.r<y.r;
}
void pre(){
	fo(i,2,mx){
		if(!bz[i]) pr[++pr[0]]=i,bz[i]=1,mp[i]=i;
		fo(j,1,pr[0]){
			int t=i*pr[j];
			if(t>mx) break;
			bz[t]=1,mp[t]=min(mp[i],pr[j]);
			if(i%pr[j]==0) break;
		}
	}
}
void add(int p){
	int x=a[p];
	/*for(int i=2;i*i<=x;i++)
	if(x%i==0){
		while(x%i==0) x/=i;
		ll t=(ll)(i-1)*pow(i,mo-2)%mo;
		if(pos[i]) mul(pos[i],pow(t,mo-2));
		pos[i]=p,mul(p,t);
	}
	if(x>1){
		ll t=(ll)(x-1)*pow(x,mo-2)%mo;
		if(pos[x]) mul(pos[x],pow(t,mo-2));
		pos[x]=p,mul(p,t);
	}*/
	while(x>1){
		int i=mp[x];
		while(x%i==0) x/=i;
		ll t=(ll)(i-1)*pow(i,mo-2)%mo;
		if(pos[i]) mul(pos[i],pow(t,mo-2));
		pos[i]=p,mul(p,t);
	}
}
int main()
{
	scanf("%d",&n);
	s[0]=1;
	fo(i,1,n){
		scanf("%d",&a[i]),s[i]=s[i-1]*a[i]%mo;
		mx=max(mx,a[i]),tr[i]=1;
	}
	pre();
	int q;
	scanf("%d",&q);
	fo(i,1,q) scanf("%d %d",&b[i].l,&b[i].r),b[i].p=i;
	sort(b+1,b+q+1,cmp);
	int p=0;
	fo(i,1,n){
		add(i);
		while(p<q && b[p+1].r==i){
			p++;
			int wz=b[p].p;
			an[wz]=calc(b[p].r)*pow(calc(b[p].l-1),mo-2)%mo;
			an[wz]=an[wz]*s[b[p].r]%mo*pow(s[b[p].l-1],mo-2)%mo;
		}
	}
	fo(i,1,q) printf("%lld\n",an[i]);
}

posted @ 2018-05-16 22:46  sadstone  阅读(224)  评论(0编辑  收藏  举报