鹰蛋

C:不能更经典的经典DP题
Description:
有一堆共k个鹰蛋,一位教授想研究这些鹰蛋的坚硬度E。他是通过不断从一幢n层的楼上向下扔鹰蛋来确定E的。
当鹰蛋从第E层楼及以下楼层落下时是不会碎的,但从第(E+1)层楼及以上楼层向下落时会摔碎。
如果鹰蛋未摔碎,还可以继续使用;但如果鹰蛋全碎了却仍未确定E,这显然是一个失败的实验。教授希望实验是成功的。
例如:若鹰蛋从第1层楼落下即摔碎,E=0;若鹰蛋从第N层楼落下仍未碎,E=N。
这里假设所有的鹰蛋都具有相同的坚硬度。给定鹰蛋个数k与楼层数n。
要求最坏情况下确定E所需要的最少次数。
Solution:
正常DP,(dp[i][j])i层,j个鹰蛋,最少次数,(dp[i][j]=min(dp[k][j-1],dp[i-k][j])+1),让两边尽量相等,可以二分,但是这个dp空间存不下,时间也是(n^{2}log_n),考虑把存不下的那一维和值调换,也就是(dp[i][j])i次,j个鹰蛋,可到达最大层数,由刚才转移可得,(dp[i][j]=dp[i-1][j]+dp[i-1][j-1]),这样一般的也过了,但是1和2个鹰蛋仍然存不下,如果k=1,ans=n,如果k=2,由dp思想,要使两边相等,就右边一个区间等于左边一个区间长度-1,最后到1结束,ans=t,t*(t+1)>=n的最小值。

#include<bits/stdc++.h>
#define LL long long
#define inf 1e18
using namespace std;
vector<LL> G[65];
int T,k;
LL n;
int main() {
	G[3].push_back(0);
	LL x=1;
	while(1) {
		G[3].push_back(G[3][x-1]+1+(x-1)*x/2);
		if(G[3].back()>=inf) break;
		x++;
	}
	for(int i=4;i<=64;i++) {
		int x=1;
		G[i].push_back(0);
		while(1) {
			G[i].push_back(G[i][x-1]+1+G[i-1][x-1]);
			if(G[i].back()>=inf) break;
			x++;
		}
	}
	scanf("%d",&T);
	while(T--) {
		scanf("%lld%d",&n,&k);
		if(k==1) printf("%lld
",n);
		else if(k==2) {
			n<<=1;
			LL t=sqrt(n);
			while(t*(t+1)<n) t++;
			printf("%lld
",t);
		}
		else {
			int res=lower_bound(G[k].begin(),G[k].end(),n)-G[k].begin();
			printf("%d
",res);
		}
	}
	return 0;
}

小结:
1.打表找规律;
2.dp状态过大考虑与值调换。

原文地址:https://www.cnblogs.com/oierqingmo/p/15092675.html