习题:Prime Gift(折半搜索)

题目

传送门

思路

这道题和折半搜索有点类似

通过暴力可以算出

如果只有8个质数,在1e18内能表示的数的范围不是很大

也就是指可以考虑将8个质数分成一组,另外8个质数分成一组

如果已知一个数

就可以用\(O(n*log_n)\)的时间去找出小于这个数一共有多少个数,即枚举一个集合,二分一个集合

用一个二分来枚举已知的数即可

总时间复杂度\(O(n*log_n*log_n)\)

代码

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int n,cnt;
int p[20],c[20];
long long k;
long long l=0,r=1e18,mid;
vector<long long> s[2];
void dfs(int _ind,int la,long long now)
{
    s[_ind].push_back(now);
    for(int j=la;j<=cnt;j++)
        if(1e18/c[j]>=now)
            dfs(_ind,j,now*c[j]);
}
long long check(long long mid)
{
    long long ret=0;
    for(int i=0;i<s[0].size()&&s[0][i]<=mid;i++)
    {
        long long t=mid/s[0][i];
        t=upper_bound(s[1].begin(),s[1].end(),t)-s[1].begin();
        ret+=t;
    }
    return ret;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>p[i];
    cin>>k;
    for(int i=1;i<=n;i++)
        if(i%2==0)
            c[++cnt]=p[i];
    dfs(0,1,1);
    cnt=0;
    for(int i=1;i<=n;i++)
        if(i%2==1)
            c[++cnt]=p[i];
    dfs(1,1,1);
    if(s[0].size()>s[1].size())
        swap(s[0],s[1]);
    sort(s[0].begin(),s[0].end());
    sort(s[1].begin(),s[1].end());
	while(l+1<r)
    {
        mid=(l+r)>>1;
        if(check(mid)>=k)
            r=mid;
        else
            l=mid;
    }
    while(check(l+1)<k)
        l++;
    cout<<l+1;
    return 0;
}
posted @ 2020-07-20 10:59  loney_s  阅读(159)  评论(0)    收藏  举报