CF 359D. Pair of Numbers

D.Pair of Numbers


原题链接

题意简述

西蒙有一个数组 \(a_1, a_2, ..., a_n\) ,由 n 个正整数组成。今天,西蒙要求你找出一对整数 $l, r (1 \leq l \leq r \leq n) $,使得下列条件成立:
有整数 \(j ( l \leq j \leq r )\),使得所有整数 \(a_l, a_{l + 1}, ..., a_r\) 都能被 aj 整除;
值$ r - l $在条件 1 为真的所有数对中取最大值;
帮助西蒙,找出所需的一对数 \((l, r)\) 。如果有多个所需的数对,请找出所有数对

解题思路

满足一个数能被所有数整除,那么这个数一定是这些数的公因数,同时满足 \(\gcd_{i=l}^r a_i= \min_{i=l}^r a_i\),观察发现
1.对于包含某个数的区间连续gcd后等于这个数,这样的区间大小满足单调性
2.如果贪心的枚举每个作为区间左端点,那么 二分复杂度时\(\mathcal{O}(n \times n\times \log n)\)的,所以我们要设法加速某个过程.
3.对于区间连续gcd操作,考虑使用朴素线段树或st表维护,使得查询从 \(\mathcal{O}(n)\) 降为 \(\mathcal{O}(1)\)
总体复杂度 \(\mathcal{O}(n \times \log n)\)

AC code(st 表)

//Stop learning useless algorithms, go and solve some problems, learn how to use binary search.
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
#define dbg(...) cout<<"usedchang"<<endl
struct ST_gcd{
    vector< vector<ll> >a;
    int n,len;
    ST_gcd(int n,vector<ll>&v):n(n),len(__lg(n)){
        a=vector<vector<ll>>(len+1,vector<ll>(n+1));
        build(v);
    }
    void build(vector<ll>&v){
        for(int i=1;i<=n;i++) a[0][i]=v[i];
        for(int i=1;i<=len;i++){
            for(int j=1;j<=n-(1<<i)+1;j++){
                a[i][j]=gcd(a[i-1][j],a[i-1][j+(1<<i-1)]);
            }
        }
    }
    ll qry(int l,int r){
        int len=__lg(r-l+1);
        return gcd(a[len][l],a[len][r-(1<<len)+1]);
    }
};
void solve(){
    int n;cin>>n;
    vector<ll>a(n+1);
    for(int i=1;i<=n;i++) cin>>a[i];
    ST_gcd G(n,a);
    auto isok=[&](int op,int l,int r) ->bool {
        if(op==1) return G.qry(l,r)==a[l];
        return G.qry(l,r)==a[r];
    };
    int maxl=0;
    vector< pair<int,int> >ans;
    for(int i=1;i<=n;i++){
        int l=i,r=n;
        while(l<=r){
            int mid=l+r>>1;
            if(isok(1,i,mid)) l=mid+1;
            else r=mid-1;
        }
        int R=l-1;
        l=1,r=i;
        while(l<=r){
            int mid=l+r>>1;
            if(isok(2,mid,i)) r=mid-1;
            else l=mid+1;
        }
        int L=l;
        if(R-L>=maxl){
            maxl=R-L;
            ans.push_back({L,maxl});
        }
        i=R;
    }
    vector<int>res;
    for(int i=0;i<ans.size();i++){
        if(ans[i].second==maxl) res.push_back(ans[i].first);
    }
    cout<<res.size()<<' '<<maxl<<endl;
    for(auto &p:res) cout<<p<<' ';
    cout<<endl; 
}
int main(){
    cin.tie(0)->ios::sync_with_stdio(false);
    solve();
    return 0;
}

AC code(线段树上二分)

//Stop learning useless algorithms, go and solve some problems, learn how to use binary search.
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define lc (p<<1)
#define rc (p<<1|1)
typedef long long ll;
const int N=3e5+5;
int n;
struct Seg{
    int l,r,val;
}tre[N<<2];
int a[N<<2];
void pushup(int p){
    tre[p].val=gcd(tre[lc].val,tre[rc].val);
}
void build(int l=1,int r=n,int p=1){
    tre[p]={l,r,0};
    if(l==r){
        tre[p].val=a[l];
        return;
    }
    int mid=l+r>>1;
    build(l,mid,lc);
    build(mid+1,r,rc);
    pushup(p);
}
ll qry(int l=1,int r=n,int p=1){
    if(l<=tre[p].l&&tre[p].r<=r){
        return tre[p].val;
    }
    ll ans=0;
    int mid=tre[p].l+tre[p].r>>1;
    if(l<=mid) ans=gcd(ans,qry(l,r,lc));
    if(mid<r) ans=gcd(ans,qry(l,r,rc));
    return ans;
}
ll find_R(int p,int ql,ll G){
    if(tre[p].r<ql) return ql;
    if(tre[p].l>=ql&&gcd(G,tre[p].val)==a[ql]){
        return tre[p].r;
    }
    if(tre[p].l==tre[p].r) return tre[p].l-1;
    int res=find_R(lc,ql,G);
    if(res<tre[lc].r) return res;
    return find_R(rc,ql,G);
}
ll find_L(int p,int qr,ll G){
    if(tre[p].l>qr) return qr;
    if(tre[p].r<=qr&&gcd(G,tre[p].val)==a[qr]){
        return tre[p].l;
    }
    if(tre[p].l==tre[p].r) return tre[p].l+1;
    int res=find_L(rc,qr,G);
    if(res>tre[rc].l) return res;
    return find_L(lc,qr,G);
}
void solve(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    build();
    int maxl=0;
    vector<int>res;
    for(int i=1;i<=n;){
        int R=find_R(1,i,a[i]);
        int L=find_L(1,i,a[i]);
        if(R-L>maxl){
            maxl=R-L;
            res.clear();
            res.push_back(L);
        }
        else if(R-L==maxl&&R-L>=0) res.push_back(L);
        i=R+1;
    }
    sort(res.begin(),res.end());
    cout<<res.size()<<" "<<maxl<<endl;
    for(auto &p:res) cout<<p<<' ';
    cout<<endl;
}
int main(){
    cin.tie(0)->ios::sync_with_stdio(false);
    solve();
    return 0;
}
posted @ 2025-10-18 19:46  usedchang  阅读(8)  评论(0)    收藏  举报