ABC393E/F简要题解

ABC393E

给定数组AAA,求包含元素AiA_iAi的大小为kkk的子集中最大的最大公约数。

题解:

首先思考对于整个数组所有包含kkk个元素的子集中最大的GCD是多少,可以怎么求。

我们发现,如果一个数xxx,数组中如果存在至少kkk个数是它的倍数,那么我们一定可以找到一个大小为kkk的子集,使得xxx是这个集合的公约数。

因为总的值域比较小,所以我们可以使用一个桶统计所有数字的出现次数,然后使用调和级数枚举的方式求出对于每个数iii,数组当中有多少数是它的倍数。

如果一个数iii,满足它的倍数个数在数组AAA中的出现次数大于kkk,那么对于所有iii的倍数,我们一定都能找到一个大小为kkk的集合使得公约数是iii。所以我们可以维护一个ans数组,ansians_iansi表示如果选择了一个值为iii的数,最大的答案是多少。对于所有的AiA_iAi,直接输出对应的ans即可。

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
int n,k;
int a[2000005];
int cnt[1000005];
int sum[1000005];
int ans[2000005];
void solve(){
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        cnt[a[i]]++;
    }
    for(int i=1;i<=1e6;i++){
        for(int j=i;j<=1e6;j+=i){
            sum[i]+=cnt[j];
        }
    }
    for(int i=1;i<=1e6;i++){
        if(sum[i]>=k)
            for(int j=i;j<=1e6;j+=i){
                ans[j]=max(ans[j],i);
                //ans[j]=i;
            }
    }
    for(int i=1;i<=n;i++){
        cout<<ans[a[i]]<<endl;
    }
}
signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    solve();
}

ABC393F

给定数组AAA,qqq次询问前缀rir_iri中所有小于xix_ixi的数组成的最长上升子序列是多少。

考虑二分栈求最长上升子序列做法,栈中元素表示对应LCS为iii时最后一个数字的最小值,所以我们可以直接将所有询问离线之后在对应的栈上二分找到答案即可。

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define pii pair<int,int>
using namespace std;
int n,q;
int a[200005];
vector<pii>ask[200005];
void solve(){
    cin>>n>>q;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=q;i++){
        int x,y;cin>>x>>y;
        ask[x].push_back({y,i});
    }
    vector<int>st(1,0);
    vector<int>ans(q+1,0);
    for(int i=1;i<=n;i++){
        int l=0,r=st.size()-1;
        while(l<=r){
            int mid=l+r>>1;
            if(st[mid]<a[i])l=mid+1;
            else r=mid-1;
        }
        if(l==st.size())st.push_back(a[i]);
        else st[l]=a[i];
        // cout<<i<<" "<<l<<"??\n";
        for(auto [y,id]:ask[i]){
            l=0,r=st.size()-1;
            while(l<=r){
                int mid=l+r>>1;
                if(st[mid]<=y)l=mid+1;
                else r=mid-1;
            }
            ans[id]=r;
        }
    }
    for(int i=1;i<=q;i++)cout<<ans[i]<<endl;
}
signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    solve();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值