题目概述
经典的鹰蛋问题,就因为懒所以不写了。
解题报告
不知道大家第一想法是不是二维DP,反正我不是……
2015年,当我还是普及组大菜鸡(现在是提高组大菜鸡)时,我看到了这道题。
然后根本不会,直到教练下发题解……
题解上是……没错……区间DP f[L][R][egg] ……
(黑历史完……)
显然所有区间都是等价的,唯一重要的是区间长度,所以可以定义
f[i][j]
表示区间长度为
i
,目前还有
枚举在哪里扔,要考虑碎掉和不碎掉两种状态的最坏情况,即 max(f[i−1][j−1],f[n−i+1][j])+1 ,然后从所有最坏情况中选出最小值,得到 f[i][j] 。
然而这样效率是
O(n2m)
,显然无法承受。此时会想到明显错误但是最优的答案
p=⌈log2n⌉
,当鸡蛋数超过
p
时,显然答案就是
然后?其实还可以优化,但是我不会:P,可以看dalao的论文。
示例程序
记忆化大法好。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1000,maxm=10,MAXINT=((1<<30)-1)*2+1;
int n,m,f[maxn+5][maxm+5];
inline int Log(int n) {for (int i=0;;i++) if ((1<<i)>=n) return i;}
int Solve(int n,int m)
{
int p=Log(n);if (p<=m) return p;
if (n==1) return 0;if (m==1) return n-1;if (~f[n][m]) return f[n][m];
f[n][m]=MAXINT;
for (int i=2;i<=n;i++)
{
int now=max(Solve(i-1,m-1),Solve(n-i+1,m))+1;
f[n][m]=min(f[n][m],now);
}
return f[n][m];
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
memset(f,255,sizeof(f));
while (~scanf("%d%d",&m,&n)) printf("%d\n",Solve(n+1,m));
return 0;
}