时间限制 |
内存限制 |
1000 ms |
65536 KB |
# 题目描述
小 P 有一个奇怪的秒表。若这个秒表当前时间为 t,则一秒后它的时间 t 将变为 [0,t−1] 中的随机一个整数。小 P 想知道,当秒表的初始时间(即第 0 秒的时间 t)为 t0 时,其时间 t 平均会在第几秒时变为 0。
# 输入格式
第一个数为数据组数 T。
接下来 n 行,每行 1 个整数 t0。
# 输出格式
对于每组数据,输出一个小数,为时间 t 平均会在第几秒时变为 0。
本题采用特判,只要你的程序输出的答案与正解之间的差值不超过 0.01 即算正确,输出的每个数之间用任何空白符间隔均可。
# 输入样例
# 输出样例
# 数据范围
对于 30 的样例,保证 0≤T×t02≤4×106。
对于 60 的样例,保证 0≤t0≤2000。
对于 90 的样例,保证 0≤t0≤2×106。
对于 100 的样例,保证 0≤t0≤1012,0<T≤2×105。
# 提示
设 ai 为 t0=i 时秒表平均变为 0 所用的时间,总有:
an=na0+a1+⋯+an−1+1
# 题解:数学
设 sumn 为 an 前缀和。则:
sumn−sumn−1=nsumn−1+1sumn=nn+1sumn−1+1n+1sumn=nsumn−1+n+11sumn=(n+1)(21+⋯+n+11)=2n+1+⋯+1sumn−1=n(21+⋯+n1)=2n+⋯+1an=sumn−sumn−1=1+21+31+⋯+n1
由于 n 最大可以到 1012,所以我们需要一个结论:
n→∞lim(an−lnn)=γ
其中 γ 是欧拉常数,你可以通过打表前 106 项计算出,这里给出六位小数:0.577216。
因此小范围直接预处理出来,大范围的答案直接利用该结论。
参考代码:
| #include <stdio.h> |
| #include <math.h> |
| |
| #define GAMMA 0.577216 |
| |
| typedef long long ll; |
| |
| double sum[1000010]; |
| |
| int main() |
| { |
| |
| |
| |
| for (int i = 1; i <= 1000000; ++ i) |
| sum[i] = sum[i - 1] + 1.0 / i; |
| |
| int T; |
| scanf("%d", &T); |
| |
| while (T -- ) |
| { |
| ll t; |
| scanf("%lld", &t); |
| |
| if (t <= 1000000) |
| printf("%.4lf\n", sum[t]); |
| else |
| printf("%.4lf\n", log(t) + GAMMA); |
| } |
| |
| return 0; |
| } |