洛谷 P4820 [国家集训队]书堆

题目描述

让N本密度均匀的相同的书摆在桌上。最下面的摆在桌子边缘,其他的书依次堆叠在一本书上。每本书都只能水平放置,宽必须垂直于桌子边缘。如(洛谷的)图:

img

求书本最右能到多远(这个距离是指最右边的书的右端点-桌子的右边缘),同时不让书因为重力垮下来。每本书的长度为M,最大化L。

当然是在“理想状态”下。即不考虑地球自转,重力系数改变,书的形变。

但是如果某本书以上的所有书的重心的竖直射影不在这本书上,或者正好落在在这本书的边界上,那么这堆书是不稳定的,会因为重力而垮下来。

输出延伸最远的距离向下取整。

\(N\le 10^{18}\),保证答案\(<10^6\)

题意分析

这道题前不久我的物理老师\(\times5\)大人给我们讲过!

首先确定递推的方向应该是从上往下,否则上面的会影响下面的书的重心。

(以下默认长度为1)

n=1,\(\frac12\),下面的书的右端点对齐上面的书的重心。

n=2,\(\frac12+\frac14=\frac34\),第三本书对齐前两本书的重心。

n=3,\(\frac12+\frac14+\frac16=\frac{11}{12}\),第四本书对齐前三本书的重心距离。

\(\dots\)

然后就发现答案是

\[\frac12+\frac14+\frac16+\frac18+\dots+\frac1{2i}\\ =\sum_{i=1}^n\frac1{2i} \]

注意以上考虑的是重心正好落在了下一本书的边缘上。而题目中说了,正好落在边界上是不稳定的!所以要减去一个极小的数,当作是那个\(\varepsilon\)就好。

但是这不可能通过\(N\le10^{18}\)的数据的。

如果您在这个地方发现有的点是WA的话,请检查您有没有开\(\texttt{long long}\)哦~

for(LL i=1;i<=n;i++) ans+=0.5/i;
cout<<(LL)(ans*m-(1e-6));

这样大概可以做到\(10^9\),您就可以获得\(36pts\)的好成绩!

考虑在数学方面搞点文章。

可以发现这个东西就是调和级数\(H(x)\div2\)而来的

8cb1cb134954092327c3cbe69858d109b2de4984

又因为\(H(x)\)\(\ln(x)\)特别特别的相近(\(\lim_{x\to\infty}\))

第n个调和数与n的自然对数自然对数的差值收敛于欧拉常数。

\[\sum_{i=1}^n\frac1k-\ln n=\gamma \]

\[\gamma=\int_1^n\left(\frac1{\lfloor x \rfloor}-\frac1x\right)dx\thickapprox 0.57721 56649 01532 86060 65120 90082 40243 10421 59335 \]

所以对于很大的\(n\)我们只要计算\(\ln(n)+0.5772156649\dots\)即可。

Code

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#define IL inline
#define re register
#define LL long long
#define ULL unsigned long long
#define debug printf("Now is %d\n",__LINE__);
using namespace std;

inline LL read()
{
	LL x=0,fu=1;
    char ch=getchar();
    while(!isdigit(ch)&&ch!='-') ch=getchar();
    if(ch=='-') fu=-1,ch=getchar();
    x=ch-'0';ch=getchar();
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return x*fu;
}

double ans; 
LL n,m;
int main()
{
	n=read();
	m=read();
	if(n>100000000) cout<<(LL)(m*(log(n)+0.5772156649)/2-(1e-6))<<endl;
	else
	{
		for(LL i=1;i<=n;i++) ans+=0.5/i;
		cout<<(LL)(ans*m-(1e-6))<<endl;
	}
	return 0;
}
posted @ 2020-11-18 21:18  Vanilla_chan  阅读(185)  评论(0编辑  收藏  举报