第1行:一个数T,表示后面用作输入测试的数的数量(1 <= T <= 50000)。 第2 - T + 1行:每行2个数,N, M,中间用空格分隔,N为楼的高度,M为棋子的数量(1 <= N <= 10^18, 1 <= M <= 64)。
输出共T行:对应每组数据在最坏情况下,需要进行测试的次数。
2 10 1 5 2
10 3
直接求次数很难,那么我们可以设F[i,j]表示扔i次,有j个棋子,最高能试出多少层楼。
也就是保证1~F[i,]j都可以试出来。
那么我们想一想现在的最优策略。
我们考虑先扔在某一层楼。
如果棋子碎了,那么就表示x在它以下,那么现在和上面这些楼层都是无关的,少了一个棋子,所以往下最多试出F[i-1,j-1]层。
如果棋子没碎,那么就表示x在它以上,同样和下面也是无关的,也就是往上最多试出F[i-1,j]层。
所以F[i,j]=F[i-1,j-1]+F[i-1,j]+1
如果处理出来,然后对于每个询问,二分一下就好了。
显然,这东西是指数级别增长的,真正有用的状态数不多。
但是当m=1和m=2时还是有点多的,可以特判一下。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL ;
typedef vector<LL>vec;
const int N = 2*1e6;
const long long inf = 1e18;
vec p[65];
int main()
{
for(int i=0;i<=N;i++) p[0].push_back(0);
for(int i=1;i<=64;i++)
{
p[i].push_back(0);
for(int j=1;j<=N;j++)
{
p[i].push_back(p[i-1][j-1]+p[i][j-1]+1);
if(p[i][j]>inf) break;
}
}
int t;
scanf("%d", &t);
while(t--)
{
LL n;
int m;
scanf("%lld %d",&n,&m);
if(m==1)
{
printf("%lld\n",n);
continue;
}
else if (m==2)
{
LL x=sqrt(2*n);
if (x*(x+1)<2*n) x++;
printf("%lld\n",x);
continue;
}
int x=upper_bound(p[m].begin(),p[m].end(),n)-p[m].begin();
if(p[m][x-1]==n) x--;
printf("%d\n",x);
}
return 0;
}