分析:第一反应是用莫队来写,这样每次查询的复杂度是
o(n∗n−−√)
,设
M
是
感觉这个可以作为莫队算法在一类问题上的优化,因为每一次都是查询
[l,r]
这个区间所有不同的质数,最终的答案是
看这个式子,前面一块我们可以维护前缀积,每次查询 o(1) 就可以搞定,后面一块要找出区间 [l,r] 中所有的不同的质数的函数的乘积,用莫队平均每次查找的复杂度是 o(n−−√) ,这个地方能不能优化?
当固定左端点 l 的时候,把
现在需要解决的是
l→l+1
这个时候线段树维护的区间变成了
[l+1,n]
,即把
a[l]
的影响去掉,就是把线段是中
l
的位置的乘积变成
复杂度:预处理所有质因数,并且每个数所含有的质数 o(M∗logM) ,扫一遍 [1,n] 中所有能整除的质数的位置 o(n∗logM) ,树状数组查找 o(n∗logn∗logM)
总的复杂度就是 o(M∗logM)+o(n∗logn∗logM)
代码:(自己写的比较挫,各种预处理,一开始还 MLE )
#include <bits/stdc++.h>
#define LL long long
#define FOR(i,x,y) for(int i = x;i < y;++ i)
#define IFOR(i,x,y) for(int i = x;i > y;-- i)
using namespace std;
typedef vector <int> VT;
const int Mod = 1e9+7;
const int maxn = 1000010;
map <int,int> mat;
int prime[maxn];
bool check[maxn];
VT pri[maxn];
void get_prime(){
FOR(i,0,maxn) pri[i].clear();
memset(check,false,sizeof(check));
prime[0] = 0;
FOR(i,2,maxn){
if(!check[i]){
prime[++prime[0]] = i;
pri[i].push_back(i);
mat[i] = prime[0];
}
FOR(j,1,prime[0]+1){
if(i*prime[j] >= maxn) break;
int u = i*prime[j];
check[u] = true;
FOR(k,0,(int)pri[i].size()) pri[u].push_back(pri[i][k]);
if(i%prime[j] == 0) break;
pri[u].push_back(prime[j]);
}
}
}
void gcd(LL a,LL b,LL& d,LL& x,LL& y){
if(!b) {d = a; x = 1; y = 0;}
else {gcd(b,a%b,d,y,x); y -= x*(a/b);}
}
LL inv(LL a,LL n){
LL d,x,y;
gcd(a,n,d,x,y);
return d == 1 ? (x+n)%n : -1;
}
LL mul[80000],imul[80000];
void init(){
get_prime();
FOR(i,1,prime[0]+1){
mul[i] = (prime[i]-1)*inv(prime[i],Mod)%Mod;
imul[i] = prime[i]*inv(prime[i]-1,Mod)%Mod;
}
}
const int maxm = 200020;
struct Commends{
int l,r,id;
bool operator < (const Commends& rhs) const{
return l < rhs.l;
}
}cmd[maxm];
const int __cntpri = 80000;
queue <int> r_mx[__cntpri];
int n,a[maxm],b[maxm],q;
LL c[maxm],res[maxm],sum[maxm],isum[maxm];
int lowbit(int x) {return x&-x;}
void modify(int x,LL val){
while(x <= n){
c[x] *= val;
c[x] %= Mod;
x += lowbit(x);
}
}
LL query(int x){
LL ans = 1;
while(x){
ans *= c[x];
ans %= Mod;
x -= lowbit(x);
}
return ans;
}
void work(){
FOR(i,1,n+1) c[i] = 1;
FOR(i,1,prime[0]+1){
if(!r_mx[i].empty()) modify(r_mx[i].front(),mul[i]);
}
int l = 1;
FOR(i,0,q){
res[cmd[i].id] = sum[cmd[i].r]*isum[cmd[i].l-1]%Mod;
while(l<cmd[i].l){
FOR(j,0,(int)pri[a[l]].size()){
int u = pri[a[l]][j];
modify(r_mx[mat[u]].front(),imul[mat[u]]);
r_mx[mat[u]].pop();
if(!r_mx[mat[u]].empty()){
modify(r_mx[mat[u]].front(),mul[mat[u]]);
}
}
l++;
}
LL tem = query(cmd[i].r);
res[cmd[i].id] = res[cmd[i].id]*tem%Mod;
}
FOR(i,0,q){
printf("%I64d\n",res[i]);
}
}
int main()
{
//freopen("test.in","r",stdin);
init();
while(~scanf("%d",&n)){
sum[0] = isum[0] = 1;
FOR(i,1,n+1) scanf("%d",&a[i]),sum[i] = sum[i-1]*a[i]%Mod,isum[i] = isum[i-1]*inv(a[i],Mod)%Mod;
scanf("%d",&q);
FOR(i,0,q) scanf("%d%d",&cmd[i].l,&cmd[i].r),cmd[i].id = i;
sort(cmd,cmd+q);
FOR(i,1,prime[0]+1) while(!r_mx[i].empty()) r_mx[i].pop();
FOR(i,1,n+1){
FOR(j,0,(int)pri[a[i]].size()) r_mx[mat[pri[a[i]][j]]].push(i);
}
work();
}
return 0;
}