[CF474F] Ant colony

Description

给定一个长度为 (n) 的序列,有 (q) 组询问,每次询问给定一个下标区间 ([l,r]),问这个区间中,有多少数可以整除区间中的所有数。

Solution

对于区间 ([l,r])(a_i) 整除所有数即 (a_i | extrm{gcd}(a_l,a_{l+1},...,a_r))

(g= extrm{gcd}(a_l,a_{l+1},...,a_r)),可以用线段树在 (O(log n)) 时间内求出

(a_i | g and a_i le g Rightarrow a_i = g),于是只需要统计区间中等于 (g) 的个数即可

对所有数字离散化后,对每种数用 vector 存储其出现位置,查询时在 vector 上二分即可

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 1000005;
const int dbg = 0;

int n,q,t1,t2,t3,l,r;
int a[N];

int gcd(int x,int y)
{
    return __gcd(x,y);
}

namespace seg
{
int a[N];

void build(int p,int l,int r,int *src)
{
    if(l==r)
    {
        a[p]=src[l];
    }
    else
    {
        build(p*2,l,(l+r)/2,src);
        build(p*2+1,(l+r)/2+1,r,src);
        a[p]=gcd(a[p*2],a[p*2+1]);
    }
}

int query(int p,int l,int r,int ql,int qr)
{
    if(l>qr || r<ql) return 0;
    if(l>=ql && r<=qr) return a[p];
    return gcd(query(p*2,l,(l+r)/2,ql,qr), query(p*2+1,(l+r)/2+1,r,ql,qr));
}
}

namespace cnter
{
map <int,int> mp;
int imp[N];
int ind=0;
vector <int> vec[N];

void init()
{
    for(int i=1;i<=n;i++) mp[a[i]]++;
    for(auto &i:mp) i.second=++ind, imp[ind]=i.first;
    for(int i=1;i<=n;i++) vec[mp[a[i]]].push_back(i);
}

int query(int l,int r,int key)
{
    int pos=mp[key];
    if(pos)
    {
        vector <int> &v = vec[pos];
        auto it1=lower_bound(v.begin(),v.end(),l);
        auto it2=lower_bound(v.begin(),v.end(),r+1);
        return it2-it1;
    }
    else return 0;
}
}

signed main()
{
    ios::sync_with_stdio(false);

    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    seg::build(1,1,n,a);
    cnter::init();
    cin>>q;
    for(int i=1;i<=q;i++)
    {
        cin>>l>>r;
        int g=seg::query(1,1,n,l,r);
        if(dbg) cout<<" g = "<<g<<endl;
        int ans=cnter::query(l,r,g);
        cout<<r-l+1-ans<<endl;
    }
}

原文地址:https://www.cnblogs.com/mollnn/p/13584666.html