题目描述
Description
蚂蚁是勤劳的动物,他们喜欢挑战极限。现在他们迎来了一个难题!蚂蚁居住在图书馆里,图书馆里有大量的书籍。书是形状大小质量都一样的矩形。蚂蚁要把这些书摆在水平桌子的边缘。蚂蚁喜欢整洁的布置,所以蚂蚁规定书本必须水平摆放,宽必须平行于桌缘(如图),而且不允许同一高度摆多本书
蚂蚁想要让书本伸出桌子边缘尽量远,同时不让书因为重力垮下来。它们已经用不知道什么方法测出了书的长度M(如图)。如果总共有N本书,请你帮忙计算如何摆放使得最多水平伸出桌缘多远。你不用考虑蚂蚁用什么方法搭建这堆书。
如果某本书以上的所有书的重心的竖直射影不在这本书上,或者正好落在在这本书的边界上,那么这堆书是不稳定的,会因为重力而垮下来。
()不考虑地球自转,重力系数也不因高度改变;
()书是质量均匀,质地坚硬的理想二维物体;
(*)在不会垮的前提下,每本书的位置坐标可以是任意实数。
Input
输入文件仅含一行,两个正整数N和M,表示书本数和书本长度。
Output
输出仅包含一行,整数L,表示水平延伸最远的整数距离 (不大于答案的最大整数,详见样例)
Sample Input
【输入样例一】
1 100
【输出样例一】
49
【输入样例二】
2 100
【输出样例二】
74
Sample Output
Data Constraint
Hint
【数据范围】
10%的数据中N≤5;
20%的数据中N≤10^3;
40%的数据中N≤10^7;
100%的数据中N≤1018;答案≤106。
20~40%(?)
从上往下设其伸出长度为ai
二分a1,利用重心的约束条件来往下求
最后判断(a1+…+an)/n<m/2
code
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define abs(x) ((x)>0?(x):-(x))
using namespace std;
int l,r,mid;
long long n,m;
long double sum,M;
bool bz;
bool pd(double a)
{
int i,j,k,l;
sum=a;
fo(i,2,n)
{
a=sum/(i-1)-M;
sum+=a;
}
sum/=n;
if (abs(sum-M)<=0.00000001)
return 0;
if (sum<M)
return 1;
else
return 0;
}
int main()
{
// freopen("S8_2_1.in","r",stdin);
scanf("%lld%lld",&n,&m);
M=m/2.0;
if (n<=1000000)
{
l=1;
r=1000000;
}
else
{
l=7*m;
r=9*m;
}
while (l<r)
{
mid=(l+r)/2;
if (pd(mid))
l=mid+1;
else
r=mid;
}
if (!pd(l))
--l;
printf("%d\n",l);
}
40%
假设把书堆反过来,变成从左往右(从上往下)放
第一本书的左边界为x=0,那么最终答案=所有书的重心
设S表示已经放了的i-1本书的重心和,G表示i-1本书的重心
显然G=S/(i-1)
考虑贪心放第i本书
显然i的左边界最多能贴着G,那么i的重心为G+M/2
则S+=G+M/2,S=S+S/(i-1)+M/2(i≥2)
最终答案为G
100%
化一下式子
S
1
=
M
2
S_1=\frac{M}{2}
S1=2M
S
=
S
+
S
i
−
1
+
M
2
S=S+\frac{S}{i-1}+\frac{M}{2}
S=S+i−1S+2M(i≥2)
=
S
∗
i
i
−
1
+
M
2
=S*\frac{i}{i-1}+\frac{M}{2}
=S∗i−1i+2M
可以发现最终的S为
S
=
M
2
∗
∑
i
=
1
n
n
i
S=\frac{M}{2}*\sum_{i=1}^{n}{\frac{n}{i}}
S=2M∗∑i=1nin
G
=
S
n
=
M
2
∗
∑
i
=
1
n
1
i
G=\frac{S}{n}=\frac{M}{2}*\sum_{i=1}^{n}{\frac{1}{i}}
G=nS=2M∗∑i=1ni1
当n很大(>107)时,后面的可以用调和级数公式来算
调和级数公式(n趋近于无穷):
∑
i
=
1
n
1
i
≈
ln
(
n
)
+
γ
\sum_{i=1}^{n}{\frac{1}{i}} \approx \ln(n)+\gamma
∑i=1ni1≈ln(n)+γ,其中
γ
\gamma
γ为欧拉常数,约等于0.5772156649
一些定义:
https://baike.baidu.com/item/欧拉常数/5371177?fr=aladdin
(这个貌似可以手算机算)
https://en.wikipedia.org/wiki/Natural_logarithm
∑
i
=
1
n
1
i
=
∫
1
n
+
1
1
⌊
x
⌋
d
x
\sum_{i=1}^{n}{\frac{1}{i}}=\int_{1}^{n+1}{\frac{1}{\left \lfloor x \right \rfloor}}dx
∑i=1ni1=∫1n+1⌊x⌋1dx
推导
∑
i
=
1
n
1
i
=
∫
1
n
+
1
1
⌊
x
⌋
d
x
\sum_{i=1}^{n}{\frac{1}{i}}=\int_{1}^{n+1}{\frac{1}{\left \lfloor x \right \rfloor}}dx
∑i=1ni1=∫1n+1⌊x⌋1dx
=
∫
1
n
+
1
1
x
d
x
+
∫
1
n
+
1
(
1
⌊
x
⌋
−
1
x
)
d
x
=\int_{1}^{n+1}{\frac{1}{x}}dx+\int_{1}^{n+1}{(\frac{1}{\left \lfloor x \right \rfloor}-\frac{1}{x})}dx
=∫1n+1x1dx+∫1n+1(⌊x⌋1−x1)dx
=
ln
(
n
+
1
)
+
∫
1
n
+
1
(
1
⌊
x
⌋
−
1
x
)
d
x
=\ln(n+1)+\int_{1}^{n+1}{(\frac{1}{\left \lfloor x \right \rfloor}-\frac{1}{x})}dx
=ln(n+1)+∫1n+1(⌊x⌋1−x1)dx
其实当n大时ln(n)和ln(n+1)差不多
≈
ln
(
n
)
+
γ
\approx \ln(n)+\gamma
≈ln(n)+γ(n+1≈∞)
code
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define r 0.577215664901532860606512090082402431042159335
using namespace std;
int i,j,k,l;
long long n;
long double S,m;
int main()
{
// freopen("S8_2_1.in","r",stdin);
scanf("%lld%Lf",&n,&m);
m/=2.0;
// S+=G+M/2 G=S/i
// 40%
// S=m;
// fo(i,2,n)
// S+=S/(i-1)+m;
// S/=n;
// 100%
if (n<=10000000)
{
fo(i,1,n)
S+=1.0/i;
S*=m;
}
else
S=m*(log(n)+r);
printf("%0.0Lf\n",floor(S-0.0000001));
}
附·欧拉常数近似计算
根据积分的定义:[a,b]段曲线与x轴之间的面积,化成若干矩形来计算面积和
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define E 0.0001
using namespace std;
long double euler,i;
int main()
{
i=1;
while (i<=10000)
{
euler+=(1.0/floor(i)-1.0/i);
i+=E;
}
printf("%0.10Lf\n",euler*E);
}
算得γ=0.5771351607,足以通过本题