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"; 
        }
    }
}
ST表+二分

Code2

 

posted @ 2021-08-22 15:44  lipu123  阅读(70)  评论(0)    收藏  举报