传送门:https://vjudge.net/problem/Gym-101194D
题意:在一堆数中,找到对多的组合,使得每个组合的个数为K,且满足在排序后,后一个是前一个的两倍;
思路:二分,贪心;自己想不到贪心check是真的忧伤。这里,只要再开一个pre数组记录每组最新的数字,然后一个个(这组找到了一个,调到下一组找一个)去找是否存在满足条件的后一个数字。
代码:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> using namespace std; typedef long long ll; const int maxn = 3e5+8; int k,n; ll a[maxn]; ll pre[maxn]; bool check(int x) { for(int i=1; i<=x; i++) pre[i] = a[i]; int id = x + 1; for(int g = 1; g<=k - 1; g++) { for(int i=1; i<=x; i++) { if(id>n)return false; while(a[id] < 2 * pre[i]) { id++; if(id>n)return false; } pre[i] = a[id]; id++; } } return true; } int main(){ int T; scanf("%d", &T); for(int t=1; t<=T; t++) { scanf("%d%d", &n, &k); for(int i = 1; i<=n;i++) { scanf("%lld" ,&a[i]); } sort(a+1, a+n+1); int le = 0,ri = n / k +1; while(le + 1 < ri) { int mid = le + (ri - le)/2; if(check(mid)) { le = mid; } else ri = mid; } if(k==1)le = n; printf("Case #%d: %d ",t,le); } return 0; }