UVa 10934 Dropping water balloons
题目
◇题目传送门◆(由于UVa较慢,这里提供一份vjudge的链接)
◇题目传送门(vjudge)◆
题目大意
有KK个一模一样的水球,在一个有 层楼高的高楼进行测试。但是你很懒,所以你想使用最少的实验次数来知道一个水球的硬度到底是多少(若从某层楼扔下来刚好破,则水球的硬度为这层楼的标号),或得出结论:在最高层也摔不破。注意一个水球不会被实验所损坏(即若这个球没破,这个球的还是原来的硬度)。
求出最少需要的实验次数。注意若63次实验仍然不能得出结果,则输出:More than 63 trials needed.
。
思路
二分?暴力?似乎有了KK的限制,一切都变了。。。
我们换一下思路:给定水球个数及实验次数,求出最高实验楼层。这道题就转化为了DP。
定义状态 为使用ii个球,做 次实验所能测试的楼的最高层数。接下来考虑决策:
设当前测试楼层为kk。
若水球在第 层破了,则说明之前的k?1k?1层必须使用i?1i?1个球实验j?1j?1次测出。则当k=f[i?1][j?1]+1k=f[i?1][j?1]+1时,该决策最优。
若水球没有破,则我们可以将第k+1k+1层看做第11层以后继续实验 层楼。
综上所述,我们可列出状态转移方程:
实现细节
注意f[i][j]f[i][j]的值可能超过int
,请使用long long
。
为了保证在规定内时间出解,请使用打表法预处理出所有的f[i][j]f[i][j]。时间复杂度为O(216)O(216),能够过。
正解代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;int K;
long long N;
long long f[65][65];void Init() {memset(f,0,sizeof f);for(int i=1;i<64;i++)for(int j=1;j<64;j++)f[i][j]=f[i-1][j-1]+1+f[i][j-1];
}int main() {#ifdef LOACLfreopen("in.txt","r",stdin);freopen("out.txt","w",stdout);#endifInit();//直接打表,预处理f[i][j]while(scanf("%d %lld",&K,&N)!=EOF&&K&&N) {K=min(K,63);//K与63取min!!!//因为N<2^64,根据二分法,最多只需63个球就可以得到解bool ok=false;for(int i=0;i<64;i++)if(f[K][i]>=N) {printf("%d\n",i);ok=true;break;}//注意应枚举实验次数找到f[K][i]大于等于N的状态if(!ok)puts("More than 63 trials needed.");//没有找到,即63次实验也测不出}return 0;
}