912E - Prime Gift
阿新 • • 發佈:2018-01-25
個數 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 #definepb 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