SP25338 NPC2015E - Eefun Plays LOL 题解
题意
可曾听闻过——大楼扔鸡蛋?
某个品种的鸡蛋,有一个硬度值
出题人:“给你
没错,这道题就是一个大楼扔鸡蛋,但是前往 Spoj 上之后,你就会发现...
这是什么数据啊?
别急,让我们慢慢地...从最朴素开始。
分析
我们先从最简单的地方,也就是 spoj 上的 subtask 1 分析。
当
哎呀,现在
没关系,我们慢慢来。
- 动态规划
假设我们最终的答案为
我们的
对于
好的,因为要求的是最坏情况,所以应该是这两者的最大值,于是转移方程便显而易见了。
时间复杂度
有了这个式子,我们再想想,对于
一个
但是这个算法还可以再次优化,我们尝试魔改这个
我们只需要枚举
时间复杂度
无论怎样,直至现在,我们还是没能通过最大的数据,于是我们开启头脑风暴,将这个过程深入分析一下。
我们换一种方式表示
一个值,由上边和左上得到,你想到了什么?
杨辉三角!
因此,我们用
所以:
我们感性理解这个式子:
每次扔鸡蛋,只有碎与不碎两种情况,因此,最终我们会得到一个
于是,我们的最终目的便成为了:找到一个最小的
对于这种算法,时间复杂度为
代码
#include<iostream>
#include<cmath>
#include<cstring>
#include<vector>
#include<cstdio>
using namespace std;
long long read()
{
char c=getchar();
long long x=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9')
{
x=x*10+c-'0';
c=getchar();
}
return x;
}
long long f(long long x,long long k,long long n) {
long double ans=0,r=1;
long double p=n;
for (long long i = 1; i <= k; i++) {
r = r*(long double)(x-i+1);
r = r / i;
ans += r;
// printf("%lf %lf %lf\n",ans,r,p);
if (ans >=p) return 1;
}
return 0;
}
long long solve(long long k,long long n) {
long long l = 1, r = n;
while (l < r) {
long long m = (l + r)/2;
if (!f(m, k, n)) l = m + 1;
else r = m;
}
return l;
}
int main()
{
// freopen("1.txt","r",stdin);
// freopen("2.txt","w",stdout);
long long T=read();
while(T--)
{
bool flag=0;
long long n,k,c=0;
long long ss=1;
n=read(),k=read();
// cout<<n.size()<<" "<<c.size()<<endl;
// cout<<(n==c)<<endl;
if(n==0)
{
cout<<0<<endl;
continue;
}
// cout<<poww(2,60)<<endl;
for(long long i=1;i<=k;i+=1)
{
ss*=2;
// cout<<i<<" "<<ss<<endl;
if(ss>n)
{
flag=1;
cout<<i<<endl;
break;
}
}
if(flag) continue;
cout<<solve(k,n)<<endl;
}
}
时间紧迫,如有错误,敬请指出!