hdu:Ice Cream Tower(构造二分)

发布时间 2023-05-26 17:21:17作者: ruoye123456

一座高度为k的塔\(b1,b_2,\dots,b_k\)满足\(2b_1\leq b_2,2b_2\leq b_3,2b_3\leq b_4,\dots,2b{k-1}\leq b_k\)

你要从中选择一些数来叠很多座高度为\(k\)的塔,问最多能叠多少座塔。

Input
第一行包含一个正整数T(1≤T≤10),表示测试数据的组数。

每组数据第一行包含两个正整数n,k(2≤n≤100000,2≤k≤30)。

第二行包含\(n\)个正整数\(a_1,a_2,\dots,a_n(1\leq a_i\leq 10^9)\)

Output
对于每组数据输出一行一个整数,即能叠出的塔的数量。

输入样例
3
4 2
1 2 3 4
6 3
1 1 2 2 4 4
6 3
1 1 2 2 3 4
输出样例
2
2
1

数学--构造二分

因为若能够搭出x座塔,必然可以搭出x-1座塔,直接二分查找最大的x即可,关键在判断能否搭成x座k层高的塔,贪心枚举即可
注意无解的特判,让二分范围在[1,n]

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int n,k;
int a[N];

bool f(int x)//返回能否叠出x座k层塔
{
	//利用贪心分析:如能够搭出x座塔,用最小的x个ai座塔底一定是一个解
	vector<int> v[x+1];
	int cnt=0;
	for(int i=1;i<=n;++i)
	{
		cnt%=x;
		if(v[cnt].empty()||a[i]>=2*v[cnt].back())
		{
			v[cnt].push_back(a[i]);
			cnt++;
		}
		//cout<<v[0].size()<<' '<<v[1].size()<<'\n';
	}
	for(int i=0;i<x;++i) if(v[i].size()<k) return false;
	return true;
}

int bina(int mi,int ma)//二分的目的:找到最大的x使得f(x)=true
{
	int l=mi,r=ma,ans=r;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		bool tmp=f(mid);
		if(tmp) ans=mid,l=mid+1;
		else r=mid-1;
	}
	return ans;
}

void solve()
{
    cin>>n>>k;
    for(int i=1;i<=n;++i) cin>>a[i];
    sort(a+1,a+1+n);
    if(!f(1)) cout<<'0'<<'\n';//特判一下无解的情况因为x不能做被模数
    else
    cout<<bina(1,n/k)<<'\n';
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int T;
    cin>>T;
    while(T--)
    {
        solve();
    }
    return 0;
}