[51nod 1306]高楼和棋子

17 篇文章 0 订阅
15 篇文章 0 订阅

Description

一栋高度为n层的楼,你有m个棋子,在第x层以上扔棋子会碎。
问对于x=0~n,最坏情况下需要试多少次才可以试出这个x。
T<=50000,1 <= N <= 10^18, 1 <= M <= 64

Solution

是不是长得有点眼熟?
相信大家都在小学奥数书上见过这种题。
不过搬到OI上来似乎就没有那么好做了。
最优策略很难想啊。。。
那我们不妨换个角度。
直接求次数很难,那么我们可以设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时还是有点多的,可以特判一下。
懒得特判写vector,跑的好慢啊!!!

Code

#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define pb push_back
using namespace std;
typedef long long ll;
typedef vector<ll> vec;
const ll Mx=1e18;
const int N=2*1e6;
ll m;
vec f[65];
int n,ty;
int main() {
    fo(i,1,N) f[0].pb(0);
    fo(j,1,64) {
        f[j].pb(0);
        fo(i,1,N) {
            f[j].pb(f[j][i-1]+f[j-1][i-1]+1);
            if (f[j][i]>Mx) break;
        }
    }
    for(scanf("%d",&ty);ty;ty--) {
        scanf("%lld%d",&m,&n);
        if (n==1) printf("%lld\n",m);
        else if (n==2) {
            ll x=sqrt(2*m);
            if (x*(x+1)<2*m) x++;
            printf("%lld\n",x);
        } else {
            int x=upper_bound(f[n].begin(),f[n].end(),m)-f[n].begin();
            if (f[n][x-1]==m) x--;
            printf("%d\n",x);
        }
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值