【DP】RQNOJ107[Ural的鹰蛋实验]题解

题目概述

经典的鹰蛋问题,就因为懒所以不写了。

解题报告

不知道大家第一想法是不是二维DP,反正我不是……

2015年,当我还是普及组大菜鸡(现在是提高组大菜鸡)时,我看到了这道题。

然后根本不会,直到教练下发题解……

题解上是……没错……区间DP f[L][R][egg] ……

(黑历史完……)


显然所有区间都是等价的,唯一重要的是区间长度,所以可以定义 f[i][j] 表示区间长度为 i ,目前还有 j 个鹰蛋的最优解。

枚举在哪里扔,要考虑碎掉和不碎掉两种状态的最坏情况,即 max(f[i1][j1],f[ni+1][j])+1 ,然后从所有最坏情况中选出最小值,得到 f[i][j]

然而这样效率是 O(n2m) ,显然无法承受。此时会想到明显错误但是最优的答案 p=log2n ,当鸡蛋数超过 p 时,显然答案就是 p ,那么复杂度缩减为 O(n2log2n)

然后?其实还可以优化,但是我不会:P,可以看dalao的论文。

示例程序

记忆化大法好。

#include
#include
#include
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<=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;
}

你可能感兴趣的:(一般DP,杂题)