• Codeforces 912E


    912E - Prime Gift

    思路:

    折半枚举+二分check

    将素数分成两个集合(最好按奇偶位置来,保证两集合个数相近),这样每个集合枚举出来的小于1e18的积个数小于1e6。

    然后二分答案,check时枚举其中一个集合,然后找到另外一个集合小于mid/该元素的元素有多少个,这里用到一个双指针的技巧将复杂度降到O(n):一个集合从大到小枚举,那么mid/该元素就会逐渐变大,那么直接从上次找到的位置往后找就可以了,因为答案肯定在后面。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define pb push_back
    #define mem(a,b) memset(a,b,sizeof(a))
    
    const ll INF=1e18;
    vector<ll>s[2];
    int p[20],a[20];
    ll k;
    void dfs(int l,int r,ll v,int id){
        s[id].pb(v);
        for(int i=l;i<=r;i++){
            if(INF/v>=p[i])dfs(i,r,v*p[i],id);
        }
    }
    bool check(ll a){
        ll cnt=0;
        int j=0;
        for(int i=s[0].size()-1;i>=0;i--){
            while(j<s[1].size()&&a/s[0][i]>=s[1][j])j++;
            cnt+=j;
        }
        return cnt<k;
    }
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        for(int i=1;i<=n/2;i++)p[i]=a[i*2];
        for(int i=n/2+1;i<=n;i++)p[i]=a[(i-n/2)*2-1];
        cin>>k;
        int hf=n/2;
        int _hf=n-hf;
        dfs(1,hf,1,0);
        dfs(hf+1,n,1,1);
        sort(s[0].begin(),s[0].end());
        sort(s[1].begin(),s[1].end());
        ll l=1,r=1e18,mid=(l+r)>>1;
        while(l<r){
            if(check(mid))l=mid+1;
            else r=mid;
            mid=(l+r)>>1;
            //cout<<l<<' '<<r<<endl;
        }
        cout<<mid<<endl;
        return 0;
    }
  • 相关阅读:
    洛谷 P1119 灾后重建
    [NOIP 2011] 观光公交
    AtCoder Beginner Contest 071 D
    UOJ #228. 基础数据结构练习题
    bzoj 3673&3674: 可持久化并查集 by zky
    bzoj 2427: [HAOI2010]软件安装
    都市环游
    poj2299——Ultra-QuickSort
    poj1958——Strange Towers of Hanoi
    洛谷 P4139 上帝与集合的正确用法
  • 原文地址:https://www.cnblogs.com/widsom/p/8352859.html
Copyright © 2020-2023  润新知