纪念我场上速通还爆标但死于模数没改的模拟赛。(CF594D)
传送门
这里是跑满的单
首先考虑双
那么考虑 离线询问 + 扫描线 + 线段树(这里可以树状数组,常数更小),将询问挂在右端点上再从左往右扫,维护每个质因子将其贡献(就是
其实优化掉
综上,我们通过压位直接将树状数组修改次数压缩到了
code
#include <bits/stdc++.h>
//#include <windows.h>
//taskkill /f /im 未命名1.exe
#define ED cerr<<endl;
#define TS cerr<<"I AK IOI"<<endl;
#define cr(x) cerr<<x<<endl;
#define cr2(x,y) cerr<<x<<" "<<y<<endl;
#define cr3(x,y,z) cerr<<x<<" "<<y<<" "<<z<<endl;
#define cr4(x,y,z,w) cerr<<x<<" "<<y<<" "<<z<<" "<<w<<endl;
#define pr(a,l,r) for(int i=l;i<=r;++i) cerr<<a[i]<<' ';ED
#define popcnt __builtin_popcount
#define all(s) s.begin(),s.end()
#define bstring basic_string
//#define add(x,y) (x+=y)%=mod
#define pii pair<int,int>
#define epb emplace_back
#define pb push_back
#define mk make_pair
#define ins insert
#define fi first
#define se second
#define ll long long
//#define ull unsigned long long
using namespace std;
const int N=2e5+5,M=1e6+5,INF=2e9,mod=1e9+7;
int t,n,m;
ll inv[M],a[N],b[N],ans[N];
int st[20][N];vector<int> big[N];
int primes[M],id[M],vis[M],pre[M],len=0;
ll qpow(ll x,int y=mod-2) {
ll res=1;
while(y) {
if(y&1) res=res*x%mod;
x=x*x%mod,y>>=1;
}
return res;
}
struct que {
int l,r,id;
bool operator<(const que &W) const {
return r<W.r;
}
}q[N];
void init(ll n) {
for(int i=2;i<=n;++i) {
if(!vis[i]) {
id[i]=len,primes[len++]=i;
pre[i]=i;
}
for(int j=0;j<len&&primes[j]<=n/i;++j) {
vis[i*primes[j]]=1;
pre[i*primes[j]]=primes[j];
if(i%primes[j]==0) break;
}
}
inv[1]=1;
for(int i=2;i<=n;++i) {
inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
}
}
ll tr[N];int ps[M];
void add(int u,ll x) {
for(int i=u;i<=n;i+=i&(-i)) tr[i]=tr[i]*x%mod;
}
ll query(int u) {
ll res=1;
for(int i=u;i!=0;i-=i&(-i)) res=res*tr[i]%mod;
return res;
}
int query2(int l,int r) {
int k=__lg(r-l+1);
return st[k][l]|st[k][r-(1<<k)+1];
}
int main()
{
scanf("%d",&n);ll mx=0;b[0]=1;
for(int i=1;i<=n;++i) {
scanf("%lld",&a[i]);
mx=max(mx,a[i]),b[i]=b[i-1]*a[i]%mod;
tr[i]=1;
}
init(mx);
for(int i=1;i<=n;++i) {
int x=a[i];
while(x>1) {
if(id[pre[x]]<31) st[0][i]|=(1<<id[pre[x]]);
else big[i].epb(pre[x]);
x/=pre[x];
}
}
for(int i=1;i<20;++i) {
for(int j=1;j<=n-(1<<i)+1;++j) {
st[i][j]=st[i-1][j]|st[i-1][j+(1<<i-1)];
}
}
scanf("%d",&m);
for(int i=1;i<=m;++i) {
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q+1,q+1+m);
for(int i=1,j=1;i<=n;++i) {
for(auto it:big[i]) {
if(ps[it]) add(ps[it],it*inv[it-1]%mod);
ps[it]=i,add(i,(it-1)*inv[it]%mod);
}
while(j<=m&&q[j].r==i) {
int l=q[j].l,r=q[j].r,s=query2(l,r);
ll res=b[r]*qpow(b[l-1])%mod;
for(int k=0;k<31;++k) {
if((s>>k)&1) {
res=res*(primes[k]-1)%mod*inv[primes[k]]%mod;
}
}
res=res*query(r)%mod*qpow(query(l-1))%mod;
ans[q[j].id]=res,++j;
}
}
for(int i=1;i<=m;++i) {
printf("%lld\n",ans[i]);
}
return 0;
}