CodeForces 201 E.Thoroughly Bureaucratic Organization(贪心+二分+鸽巢原理)

190 篇文章 1 订阅
142 篇文章 0 订阅

Description

有一个 1 ~n的排列,每次询问至多可以询问 m 个位置的数字,但是只会给出乱序后的这些数字,问最坏情况下最少多少次可以还原整个序列

Input

第一行一整数T表示用例组数,每组用例输入两个整数 n,m(1T1000,1n,m109)

Output

对于每组用例,输出最坏情况下还原整个序列所需的最少询问次数

Sample Input

5
4 1
4 2
7 3
1 1
42 7

Sample Output

3
2
3
0
11

Solution

如果对于任意 k ,可以知道k次询问,每次询问至多问 m 个数字可以还原的最长排列长度为n,那么就可以二分得到答案,把每个数字在这 k 次询问是否被问到看作一个长度为k 01 串,第 i 次询问了这个数字则第i位是 1 ,否则是0,那么我们要找的是尽可能多的这种串,且串之间两两可区分,且对于所有串的某一位,其 1 的个数不能超过m,因为一次询问至多询问 m 个数字,首先不考虑这个限制,那么就是至多用km 1 去构造尽可能多的可两两区分的长度为k 01 串,那么我们可以贪心的先构造 C1k 个只含一个 1 且位置不同的串,然后构造C2k个只含两个 1 且这两个1位置不完全相同的串,….,以此类推可以得到尽可能多的串,下面证明加入这个限制和不加是一样的,假设 i 位的1的数量大于,那么由于总数不超过 km ,所以必然存在一个 j 位其1的数量小于 m ,记x为第 i 位是1且第 j 位是0的串的个数, y 为第i位是 0 且第j位是 1 的串的个数,显然x>y,从 x 中选一个串,交换其在第i位和第 j 位的值,结果是要么该串变成一个和其他串都可区分的串,要么其和这y个串中某一个相同,由于 x>y ,由鸽巢原理,必然存在一个串,交换其两位后和这 y 个串均不相同,那么这个串和其他所有串都可区分,x的数量减一,经过有限次这样的操作,必然可以使得那些使用超过 m 1的位消失,故该限制没用

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
int T,n,m;
bool check(int k)
{
    if(n==1)return 1;
    ll num=(ll)m*k,res=1,C=1;
    for(int i=1;i<=k;i++)
    {
        if(num<i)return 0;
        if((ll)(k-i+1)*C>=(ll)n*i)C=n;
        else C=C*(k-i+1)/i;
        ll temp=min(num/i,C);
        res+=temp;
        if(res>=n)return 1;
        num-=temp*i;
    }
    return 0;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        int l=0,r=n,mid,ans;
        while(l<=r)
        {
            mid=(l+r)/2;
            if(check(mid))ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值