牛客编程巅峰赛S1第11场 - 黄金&钻石 C.牛牛找子集 (二分)

-
题意:有一\(n\)个数,从中找数构成相同的子集,要求子集元素个数为\(k\),求构成子集个数最多的情况,输出子集(字典序最小).
-
题解:我们可以对子集的个数二分答案,首先用桶记录每个元素的个数,然后二分找最大值,check函数中直接枚举\([1,100000]\)的个数,然后用\(mid\)去除,得到的\(t\)就是它可以贡献给子集的元素个数,枚举完之后,比较一下总贡献和\(k\)即可.然后\(l\)就是我们得到的最大答案,再次枚举\([1,100000]\),求每个数的贡献\(t\),然后塞\(t\)个自己进去给\(ans\),当\(cnt=k\)时,直接return \(ans\)即可.
-
代码:
class Solution { public: /** * 返回找到能够满足游戏胜利条件的子集,如果有多个子集满足条件,返回字典序最小的即可。 * @param n int整型 代表数字的数量 * @param k int整型 代表子集的大小 * @param s int整型vector 代表数字数组 * @return int整型vector */ int mp[1000010]; int l,r; vector<int> res; bool check(int x,int k){ int sum=0; for(int i=1;i<=100000;++i){ int t=mp[i]/x; if(t>=1) sum+=t; } if(sum>=k) return true; else return false; } vector<int> solve(int n, int k, vector<int>& s) { // write code here for(int i=0;i<n;++i){ mp[s[i]]++; } l=1,r=1; for(int i=1;i<=100000;++i){ r=max(r,mp[i]); } while(l<r){ int mid=(l+r+1)>>1; if(check(mid,k)){ l=mid; } else r=mid-1; } int cnt=0; for(int i=1;i<=100000;++i){ int t=mp[i]/l; if(t>=1){ for(int j=0;j<t;++j){ res.push_back(i); cnt++; if(cnt==k) return res; } } } return res; } };
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮

浙公网安备 33010602011771号