画一下柿子就知道是求区间乘积乘区间内所有质因数的(p-1)/p(就是求欧拉的公式嘛)
看上去莫队就很靠谱然而时间O(nsqrt(n)logn)并不资瓷
还是离线,确定右端点,对于1~i的区间内的质因数我们在树状数组把他们插入到最后一次出现的位置,然后扫一次求逆元+找质因数O(nlog^2n)
注意算质因子的时候不能用试除法啊
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const LL mod=1e9+7; int quick_pow(int A,int p) { int ret=1; while(p!=0) { if(p%2==1)ret=(LL)ret*A%mod; A=(LL)A*A%mod;p/=2; } return ret; } int inv(int A){return quick_pow(A,mod-2);} int pr,prime[1100000],pm[1100000]; bool v[1100000]; void get_prime() { pr=0; for(int i=2;i<=1001000;i++) { if(v[i]==false)prime[++pr]=i,pm[i]=i; for(int j=1;j<=pr&&i*prime[j]<=1001000;j++) { v[i*prime[j]]=true; pm[i*prime[j]]=min(pm[i],prime[j]); if(i%prime[j]==0)break; } } } int n;LL s[210000]; int lowbit(int x){return x&-x;} void change(int x,LL k) { while(x<=n) { s[x]=s[x]*k%mod; x+=lowbit(x); } } LL getsum(int x) { LL ret=1; while(x>0) { ret=ret*s[x]%mod; x-=lowbit(x); } return ret; } int a[210000];LL sm[210000]; struct query{int l,r,id;}q[210000];int as[210000]; bool cmp(query q1,query q2){return q1.r<q2.r;} int last[1100000]; int main() { get_prime(); scanf("%d",&n); sm[0]=1; for(int i=1;i<=n;i++) scanf("%d",&a[i]), sm[i]=sm[i-1]*a[i]%mod; int Q; scanf("%d",&Q); for(int i=1;i<=Q;i++) scanf("%d%d",&q[i].l,&q[i].r), q[i].id=i; sort(q+1,q+Q+1,cmp); int j=1; memset(last,0,sizeof(last)); for(int i=1;i<=n;i++)s[i]=1; for(int i=1;i<=n;i++) { int d=a[i]; while(d>1) { int p=pm[d];LL c=(LL)(p-1)*inv(p)%mod; if(last[p]>0)change(last[p],inv(c)); last[p]=i; change(last[p],c); while(d%p==0)d/=p; } while(j<=Q&&q[j].r==i) { as[q[j].id]=sm[q[j].r]*inv(sm[q[j].l-1])%mod*getsum(q[j].r)%mod*inv(getsum(q[j].l-1))%mod; j++; } } for(int i=1;i<=Q;i++)printf("%d ",as[i]); return 0; }