您的位置:首页 > 其它

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

2018-01-01 20:20 453 查看
Description

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

Input

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

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: