1. 程式人生 > 實用技巧 >習題:Prime Gift(折半搜尋)

習題: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;
}