【ZSTU4214 2015年12月浙理工校赛 E】【看似区间DP实则线性相加 脑洞 好题】Power Eggs 最少扔鸡蛋次数测出其坚固度 学会状态表示

来源:互联网 发布:淘宝店铺怎么制作头像 编辑:程序博客网 时间:2024/04/29 14:49

4214: Power Eggs

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 130  Solved: 24

Description

Benedict bought K identical power eggs from Dropeggs.com, and now he wants to test them by dropping them from different floors of his building. His building has N floors numbered 1 to N. F is an unknown number in the range from 0 to N, inclusive. Each egg will break if dropped from floor F+1 or above, but will not break if dropped from floor F or below. Benedict can drop each egg as many times as he wants from any floor until it breaks. He wants to know the minimum number of egg drops necessary to ensure that he can determine F.

For example, if there are three floors and Benedict has only one egg, then he has to first throw the egg from the first floor, then from the second floor (if the egg survived), and then from the third floor (if the egg survived). Therefore, three drops are required in the worst case

Input

The first line contains one number T (1 ≤ T ≤ 10000) which is the number of test cases, followed by T lines. Each of the next T lines contains two numbers: N, the number of floors (1 ≤ N ≤ 2000000007) and K, the number of eggs (1 ≤ K ≤ 32).

Output

For each of the T lines, print the minimal number of drops required, or if it's greater than 32, print the word Impossible. After that many drops, Benedict gets too tired and cannot continue.

Sample Input

410 1100 230 302000000000 2

Sample Output

10145Impossible


#include<stdio.h>#include<iostream>#include<string.h>#include<string>#include<ctype.h>#include<math.h>#include<set>#include<map>#include<vector>#include<queue>#include<bitset>#include<algorithm>#include<time.h>using namespace std;void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}#define MS(x,y) memset(x,y,sizeof(x))#define MC(x,y) memcpy(x,y,sizeof(x))#define MP(x,y) make_pair(x,y)#define ls o<<1#define rs o<<1|1typedef long long LL;typedef unsigned long long UL;typedef unsigned int UI;template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}const int N=0,M=0,Z=1e9+7,ms63=0x3f3f3f3f;int casenum,casei;int n,m;LL f[32+2][32+2];void init(){for(int i=1;i<=32;++i)f[i][1]=i+1;//只有一个鸡蛋,能尝试几次可达范围就是几+1for(int i=1;i<=32;++i)f[1][i]=2;//只能尝试一次,有再多鸡蛋也只能测范围2for(int i=2;i<=32;++i){for(int j=2;j<=32;++j)f[i][j]=f[i-1][j-1]+f[i-1][j];}}int main(){init();scanf("%d",&casenum);for(casei=1;casei<=casenum;++casei){scanf("%d%d",&n,&m);++n;int ans=0;for(int i=1;i<=32;++i)if(f[i][m]>=n){ans=i;break;}if(ans==0)puts("Impossible");else printf("%d\n",ans);}return 0;}/*【trick&&吐槽】不要给自己增大心理负担,一些以为很难的题目可能并不难!【题意】有n(2e9)层楼,我们手中有m(1<=m<=32)个鸡蛋,鸡蛋拥有相同的坚固度。我们想要通过最少的测试次数,使得自己确保能够测得鸡蛋的坚固度。(坚固度是[0,n]范围的值,表示鸡蛋最高不会摔碎的楼层)。PS:如果在32步之内,都无法测出这个值,则输出impossible。【类型】DP【分析】比赛时,看到题目和题意之后,我便想到了——《IOI2004 国家集训队论文 朱晨光 ——从《鹰蛋》一题浅析对动态规划算法的优化》这个论文我没有看过,只感觉这题肯定是高深莫测不可做。然而,最后诗诗却做了出来,让我才知道这道题是可以突破的,只是已经没了时间。======================================================================我们让我们的思维逻辑清晰一些,冷静分析下这道题目。首先,楼层数量n很大,我们对其,最多只可取log级别的算法。然而,鸡蛋数和最大步数却并不大,可以作为突破口。于是,想到一个状态表示——用f[i][j],表示我们有现在还可以尝试i次,还有j枚鸡蛋,最多能够测出的楼层范围。这里需要引入的一个思想,是子问题思想。尽管楼层数为n,但答案的取值范围是[0,n],共有n+1个值。不过,答案是确定在范围内的,是封闭的。于是,我们最多的验证次数依然只是n次,而不是n+1次。意思是——比如,只要我们测出,鸡蛋的坚固度不是[1,n],那坚固度必然是确定的0。再具体一点——初始的[0,n]可以考虑为——在n+1扔鸡蛋,碎掉了,在0扔鸡蛋,没碎对于一个区间是[l,r]的子状态,是因为我们在r+1扔鸡蛋,碎掉了;在l扔鸡蛋,没碎。我们如果在mid位置扔鸡蛋。碎掉的话,便到达了f[剩余尝试次数-1][剩余鸡蛋数-1]的状态,对应的区间范围是[l,mid-1]没碎的话,便到达了f[剩余尝试次数-1][剩余鸡蛋数]的状态,对应的区间范围是[mid,r]显然,拓扑序会是(剩余尝试次数升序,剩余鸡蛋数升序)这样一个序列。f[i][j]如何求得呢?哇哦,好像就是f[i-1][j-1]+f[i-1][j]。于是,只需要找到递推的起点。我们可以定义——1,f[剩余尝试次数==1][剩余鸡蛋数>=1]=2,表示我们可以用一次的扔鸡蛋操作,求出坚固度是[x,x+1]中的x,亦或是x+1.2,f[剩余尝试次数>=1][剩余鸡蛋数==1]=剩余尝试次数+1.表示,我们需要保证这个鸡蛋不破,于是一楼楼地扔,测出的坚固度的区间差就是n.最后f[num][初始鸡蛋数]>=(n+1) 的最小的num就是答案喽(或者impossible)。【时间复杂度&&优化】O(n^2)当然这题还有其他各种各样的做法。然而最关键的一步还是想出状态表示,用DP来解决这道题。*/


1 0
原创粉丝点击