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状态过大考虑与值调换。