912E - Prime Gift

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;
}

原文地址:https://www.cnblogs.com/widsom/p/8352859.html

时间: 2024-10-08 21:05:25

912E - Prime Gift的相关文章

Codeforces 912E Prime Gift(预处理 + 双指针 + 二分答案)

题目链接 Prime Gift 题意  给定一个素数集合,求第k小的数,满足这个数的所有质因子集合为给定的集合的子集. 保证答案不超过$10^{18}$ 考虑二分答案. 根据折半的思想,首先我们把这个集合的数分成两组. 然后分别生成这两组质数所能表示出的正整数的集合. 然后把这个集合sort一下,我们得到了两个有序的数列. 在计算小于等于某个数$x$的符合题目条件的数的时候,我们枚举第一个集合中的数, 用双指针定位和当前枚举到的数乘积恰好小于等于$x$的位置. 然后累加. 这里有一个细节,我们要

Codeforces 912 E.Prime Gift (折半枚举、二分)

题目链接:Prime Gift 题意: 给出了n(1<=n<=16)个互不相同的质数pi(2<=pi<=100),现在要求第k大个约数全在所给质数集的数.(保证这个数不超过1e18) 题解: 如果暴力dfs的话肯定超时间,其实给的n数据范围最大是16是一个很奇妙的数(一般折半枚举基本上是这样的数据范围@.@-).所以想到折半枚举,把所有的质数分成两份求出每份中所有小于1e18的满足条件的数.然后二分答案,写cheak函数时遍历第一个集合,对第二个集合二分(折半枚举基本上这个套路).

Prime Gift CodeForces - 912E (中途相遇)

链接 大意:求素因子只含给定素数的第k大数 先二分答案转为判定x是第几大, 然后分两块合并即可, 按奇偶分块可以优化一下常数 #include <iostream> #include <algorithm> #include <cstdio> #include <vector> #define PER(i,a,n) for(int i=n;i>=a;--i) #define REP(i,a,n) for(int i=a;i<=n;++i) #de

CF912E Prime Gift 数学

Opposite to Grisha's nice behavior, Oleg, though he has an entire year at his disposal, didn't manage to learn how to solve number theory problems in the past year. That's why instead of Ded Moroz he was visited by his teammate Andrew, who solemnly p

CF912E Prime Gift(Meeting In The Middle+Two pointers)

原题 挂个链接CodeForces 题目大意:给定k个质数,求出约数中只有由这几个数组合一下(可以多次用一个数)的第k个值 Solution 分析: 我们看到n是16,然后如果爆搜n/2是可以过的.所以考虑Meeting In The Middle 他让我们求第k个数,理所应当地想到二分答案. 然后我们先把所有的组合求出来,然后二分答案判断就好了. #include<stdio.h> #include<stdlib.h> #include<string.h> #incl

Codeforces Round #456 (Div. 2)

C. Perun, Ult! 分析 首先对于每个敌人单独预处理时间线(即在什么时候可以杀死这个敌人,什么时候杀不死了),然后通过一个总时间线去更新答案. code #include<bits/stdc++.h> using namespace std; const int N = 1e5 + 10; map<long long, int> add, erase; set<long long> timeline; vector<pair<long long,

Ch’s gift

Ch’s gift Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description Mr. Cui is working off-campus and he misses his girl friend very much. After a whole night tossing and turning, he decides to get to his

Sicily 1444: Prime Path(BFS)

题意为给出两个四位素数A.B,每次只能对A的某一位数字进行修改,使它成为另一个四位的素数,问最少经过多少操作,能使A变到B.可以直接进行BFS搜索 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 bool isPrime(int n){//素数判断 5 if(n == 2 || n == 3) return true; 6 else{ 7 int k = sqrt(n) + 1; 8 for(int i = 2; i < k; i

HDU 1389 继续畅通工程【最小生成树,Prime算法+Kruskal算法】

继续畅通工程 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 21871    Accepted Submission(s): 9356 Problem Description 省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).现得到城镇道路统计表,表中列