Description
(%%%WerkeyTom_FTD)
Analysis
首先,我们知道,
φ(x)=∏kφ(pakk)
因为ai,x很小,所以可以把他们分解质因数。
600以内的质数只有109个,所以可以开109颗线段树,维护该质数在区间中的指数,乱搞一下。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const ll N=10010,M=110,mo=1e8+7;
ll ind,num,ans,
prime[]={1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599};
ll n,m,a[M],b[M],c[M][N];
struct segment
{
ll n,x,lz;
}tr[M][N*4];
char ch;
void read(ll &n)
{
int t=0,p=1;
for(ch=getchar();ch<'0' || ch>'9';ch=getchar())
if(ch=='-') p=-1;
for(;'0'<=ch && ch<='9';ch=getchar()) t=t*10+ch-'0';
n=t*p;
}
void pri(ll n,int num)
{
fo(i,1,109)
{
while(n%prime[i]==0) n/=prime[i],c[i][num]++;
if(n==1) break;
}
}
void deco(ll n)
{
m=0;
fo(i,1,109)
if(n%prime[i]==0)
{
a[++m]=i,b[m]=0;
while(n%prime[i]==0) n/=prime[i],b[m]++;
}
}
ll qmi(ll x,ll n)
{
ll t=1;
for(;n;n>>=1)
{
if(n&1) t=t*x%mo;
x=x*x%mo;
}
return t;
}
void up(int k,int v)
{
tr[k][v].x=tr[k][v+v].x+tr[k][v+v+1].x;
tr[k][v].n=tr[k][v+v].n+tr[k][v+v+1].n;
}
void build(int k,int v,int l,int r)
{
if(l==r)
{
tr[k][v].x=c[k][l];
tr[k][v].n=(tr[k][v].x>0);
return;
}
int mid=(l+r)>>1;
build(k,v+v,l,mid);
build(k,v+v+1,mid+1,r);
up(k,v);
}
void update(segment &a,ll len,ll z)
{
a.x+=len*z;
a.lz+=z;
a.n=len;
}
void down(int k,int v,int l,int r)
{
if(!tr[k][v].lz) return;
int mid=(l+r)>>1;
update(tr[k][v+v],mid-l+1,tr[k][v].lz);
update(tr[k][v+v+1],r-mid,tr[k][v].lz);
tr[k][v].lz=0;
}
void change(int k,int v,int l,int r,int x,int y,ll z)
{
if(l==x && r==y)
{
update(tr[k][v],r-l+1,z);
return;
}
down(k,v,l,r);
int mid=(l+r)>>1;
if(y<=mid) change(k,v+v,l,mid,x,y,z);
else
if(x>mid) change(k,v+v+1,mid+1,r,x,y,z);
else change(k,v+v,l,mid,x,mid,z),change(k,v+v+1,mid+1,r,mid+1,y,z);
up(k,v);
}
void query(int k,int v,int l,int r,int x,int y)
{
if(l==x && r==y)
{
ind+=tr[k][v].x;
num+=tr[k][v].n;
return;
}
down(k,v,l,r);
int mid=(l+r)>>1;
if(y<=mid) query(k,v+v,l,mid,x,y);
else
if(x>mid) query(k,v+v+1,mid+1,r,x,y);
else
query(k,v+v,l,mid,x,mid),query(k,v+v+1,mid+1,r,mid+1,y);
}
int main()
{
ll _,tp,l,r,x;
read(n);
fo(i,1,n)
{
read(x);
pri(x,i);
}
fo(i,1,109) build(i,1,1,n);
read(_);
while(_--)
{
read(tp),read(l),read(r);
if(!tp)
{
read(x);
deco(x);
fo(i,1,m) change(a[i],1,1,n,l,r,b[i]);
}
else
{
ans=1;
fo(i,1,109)
{
ind=num=0;
query(i,1,1,n,l,r);
ans=ans*qmi(prime[i],ind-num)%mo*qmi(prime[i]-1,num)%mo;
}
printf("%lld\n",ans);
}
}
return 0;
}