1. 程式人生 > >912E - Prime Gift

912E - Prime Gift

個數 codeforce define rim clu ios con 集合 cin

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

912E - Prime Gift