CF474F区间gcd和区间gcd个数
题意
给出一个长度为 $n$ 的序列 $s$,$q$ 组询问。
每次给定区间 $[l,r]$。
如果 i,j∈[l,r], $s[i]|s[j]$ 则 i 得一分。
问有多少个没有得到满分,即 r-l。
解析
这个题的题意就是$s[i]$是$s[j]$的因子这$s[i]$就得1分,求不能得满分得个数,如果能得满分则证明这个数是区间内所有数得gcd
1.这个题可以用线段数求区间gcd和区间gcd个数
2.这个题可以用ST表+二分求的
Code1

#include<iostream> #include<algorithm> #include<vector> #include<map> using namespace std; typedef long long ll; const int maxn=2e5+100; ll a[maxn],b[maxn]; ll Max[maxn][33]; vector<int>v[maxn]; int Log[maxn]; int id[maxn]; int n,m; map<ll,int>mp; int cnt=0; void GetLog(){ Log[1]=0; for(int i=2;i<=n+1;i++){ Log[i]=Log[i/2]+1; } } void RMQ(){ for(int i=1;i<=n;i++){ Max[i][0]=abs(a[i]); } for(int j=1;(1<<j)<=n;j++){ for(int i=1;i+(1<<(j-1))<=n;i++){ Max[i][j]=__gcd(Max[i][j-1],Max[i+(1<<(j-1))][j-1]); } } } ll qgcd(int l,int r){ int k=Log[r-l+1]; return __gcd(Max[l][k],Max[r-(1<<k)+1][k]); } int get(int x){ if(!mp.count(x)){ mp[x]=++cnt; } return mp[x]; } int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; int p=get(a[i]); v[p].push_back(i); } for(int i=1;i<=n;i++){ v[i].push_back(1e9); } GetLog(); RMQ(); scanf("%d",&m); while(m--){ int x,y; scanf("%d%d",&x,&y); ll z=qgcd(x,y); if(!mp.count(z)){ printf("%d\n",y-x+1); } else{ int zz=mp[z]; int l=lower_bound(v[zz].begin(),v[zz].end(),x)-v[zz].begin(); int r=upper_bound(v[zz].begin(),v[zz].end(),y)-v[zz].begin(); int p=r-l; cout<<y-x+1-p<<"\n"; } } }
Code2