题意:
给定长度为n的序列a,q次询问
每次询问给定[L,R],问[L,R]内不能整除区间内所有数的数的个数有多少个
数据范围:n,q<=1e5,a(i)<=1e9
解法:
将问题转化为求区间内可以整除其他所有数的数的个数,用区间长度减去就是答案,
那么问题变为求区间gcd在区间内的个数
区间gcd可以用线段树求
求个数:
先预处理,将值等于x的所有下标放在一个容器里,预处理完每种x的位置都在一个容器中,
计算区间内x有多少个的时候,直接在x所在容器二分左右端点在容器中的位置,计算两个位置中有多少个数即可。
这题a(i)的数据范围1e9,但是n只有1e5,多打一个离散化就行了。
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
vector<int>g[maxm];
int a[maxm<<2];
int b[maxm];
int xx[maxm];
int n,q;
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
void pushup(int node){
a[node]=gcd(a[node*2],a[node*2+1]);
}
void build(int l,int r,int node){
if(l==r){
a[node]=b[l];
return ;
}
int mid=(l+r)/2;
build(l,mid,node*2);
build(mid+1,r,node*2+1);
pushup(node);
}
int ask(int st,int ed,int l,int r,int node){
if(st<=l&&ed>=r)return a[node];
int mid=(l+r)/2;
int ans=0;
if(st<=mid)ans=gcd(ans,ask(st,ed,l,mid,node*2));
if(ed>mid)ans=gcd(ans,ask(st,ed,mid+1,r,node*2+1));
return ans;
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>b[i],xx[i]=b[i];
}
build(1,n,1);
sort(xx+1,xx+1+n);
int num=unique(xx+1,xx+1+n)-xx-1;
for(int i=1;i<=n;i++){
int x=lower_bound(xx+1,xx+1+num,b[i])-xx;
g[x].push_back(i);
}
cin>>q;
while(q--){
int l,r;cin>>l>>r;
int temp=ask(l,r,1,n,1);
int pos=lower_bound(xx+1,xx+1+num,temp)-xx;
if(xx[pos]!=temp){
cout<<r-l+1<<endl;
}else{
int ans=upper_bound(g[pos].begin(),g[pos].end(),r)-lower_bound(g[pos].begin(),g[pos].end(),l);
cout<<r-l+1-ans<<endl;
}
}
return 0;
}