CF594D REQ 樹狀陣列+質因數分解
阿新 • • 發佈:2020-11-16
題意:
給定序列 \(a_1,a_2,\dots a_n\) ,\(q\) 次詢問 \(l,r\),求 $ \phi(\prod_{i=l}^r a_i)$
範圍&性質 : \(1\le n,q\le 2\times 10^5,1\le a_i\le 10^6\)
分析:
前置芝士:\(\phi(n)=n\times \prod(1-\frac{1}{p})\)
所以我們只需要處理出每一段區間內質因數的並集,然後乘上它的影響,還要維護一個字首積
那麼問題就轉化成了,如何處理出一段區間內質因數的並集,我們發現這個東西等價於求區間內質因數的種類,和 採花 / HH的項鍊 這兩道題很類似,不過每個物品的價值變成了 \(\frac{(p-1)}{p}\)
複雜度\(O(n\log n)\)
程式碼:
#include<bits/stdc++.h> using namespace std; namespace zzc { inline int read() { int x=0,f=1;char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();} while (isdigit(ch)){x=x*10+ch-48;ch=getchar();} return x*f; } const int maxn = 2e5+5; const int maxm = 1e6+5; const long long mod = 1e9+7; long long n,qt,cnt; long long a[maxn],c[maxm],f[maxn],ans[maxn],p[maxn],lst[maxm]; bool vis[maxm]; struct que { long long l,r,id; bool operator <(const que &b)const { return r<b.r; } }q[maxn]; long long qpow(long long x,long long y) { long long res=1; while(y) { if(y&1) res=res*x%mod; x=x*x%mod; y>>=1; } return res; } void init() { for(int i=2;i<=1000000;i++) { if(!vis[i]) { p[++cnt]=i; } for(int j=1;j<=cnt&&i*p[j]<=1000000;j++) { vis[i*p[j]]=true; if(i%p[j]==0)break; } } } inline long long lowbit(int x) { return x&(-x); } long long query(long long x) { long long res=1; for(long long i=x;i;i-=lowbit(i)) res=res*c[i]%mod; return res; } void update(long long x,long long val) { for(int i=x;i<=1000000;i+=lowbit(i)) c[i]=c[i]*val%mod; } void insert(long long x) { long long tmp=a[x]; for(int i=1;p[i]*p[i]<=tmp;i++) { if(tmp%p[i]) continue; update(x,(p[i]-1)*qpow(p[i],mod-2)%mod); if(lst[p[i]]) update(lst[p[i]],p[i]*qpow(p[i]-1,mod-2)%mod); lst[p[i]]=x; while(tmp%p[i]==0) tmp/=p[i]; } if(tmp>1) { update(x,(tmp-1)*qpow(tmp,mod-2)%mod); if(lst[tmp]) update(lst[tmp],tmp*qpow(tmp-1,mod-2)%mod); lst[tmp]=x; } return ; } void work() { init(); memset(vis,false,sizeof(vis)); for(int i=0;i<=1000000;i++) c[i]=1; n=read();f[0]=1; for(int i=1;i<=n;i++) a[i]=read(),f[i]=f[i-1]*a[i]%mod; qt=read(); for(int i=1;i<=qt;i++) q[i].l=read(),q[i].r=read(),q[i].id=i; sort(q+1,q+qt+1); long long now=0; for(int i=1;i<=qt;i++) { while(now<q[i].r) insert(++now); ans[q[i].id]=f[q[i].r]*qpow(f[q[i].l-1],mod-2)%mod*query(q[i].r)%mod*qpow(query(q[i].l-1),mod-2)%mod; } for(int i=1;i<=qt;i++) printf("%lld\n",ans[i]); } } int main() { zzc::work(); return 0; }