一开始还想怎么快速合并两个区间的最大公因数,其实直接辗转相除法就可以,毕竟O(nlog^2n)过1e5也是可以的。
对于查询区间中有几个数的值==最大公约数,直接把每个值存入vector中upper_bound()二分即可。
本次使用了大不同于寻常的代码风格。(我保证这是最后一次了QwQ)
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
typedef long long LL;
using std::cin;
using std::cout;
using std::endl;
const int MAXN=100005;
int n;LL a[MAXN],b[MAXN],c[MAXN];
std::vector<int> v[MAXN];
std::map<LL,int> f;
LL gcd(LL x,LL y){
while(y!=0){
std::swap(x,y);
y%=x;
}
return x;
}
#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc ((o<<1)|1)
namespace seg{
LL num[MAXN<<2];int ql,qr;
void build(int o,int l,int r){
if(l==r){
num[o]=a[l];
return;
}
build(lc,l,mid);
build(rc,mid+1,r);
num[o]=gcd(num[lc],num[rc]);
}
LL query(int o,int l,int r){
if(ql<=l&&r<=qr){
return num[o];
}
LL ans=0;
if(mid>=ql) ans=gcd(ans,query(lc,l,mid));
if(mid<qr) ans=gcd(ans,query(rc,mid+1,r));
return ans;
}
}
int getans(LL d){
if(!f.count(d)) return 0;
d=f[d];
return std::upper_bound(v[d].begin(),v[d].end(),seg::qr)
-std::upper_bound(v[d].begin(),v[d].end(),seg::ql-1);
}
int main(){
std::ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i];
}
std::sort(b+1,b+n+1);
int siz=std::unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++){
c[i]=std::lower_bound(b+1,b+n+1,a[i])-b;
f[a[i]]=c[i];
v[c[i]].push_back(i);
}
seg::build(1,1,n);
int m;
cin>>m;
while(m--){
cin>>seg::ql>>seg::qr;
LL d=seg::query(1,1,n);
cout<<seg::qr-seg::ql+1-getans(d)<<endl;
}
return 0;
}