传送门:Vjudge
前题提要:一道被榜带偏的简单概率题.赛时过的人不是很多,题面巨长,还以为是什么奇奇怪怪的期望概率,没想到被诈骗了…
发现我们最终要挑选一个最优的
k
k
k,考虑观察一下我们最终的概率和
k
k
k的关系.
那么假设我们已经固定了
k
k
k,最终的概率会是什么呢?
设
[
1
,
n
]
[1,n]
[1,n]的最大值为
m
m
m,根据题意,我们要选
m
m
m,那么显然当我们的
m
m
m在
[
1
,
k
]
[1,k]
[1,k]里是不符合我们的题意的.所以我们的
m
m
m只能在
[
k
+
1
,
n
]
[k+1,n]
[k+1,n]中
假设我们的
m
m
m选在
i
i
i的位置,此时概率为
1
/
n
1/n
1/n(也就是m有1/n的概率在i位置)
此时我们手玩一下此时的情况,就会发现
[
1
,
i
−
1
]
[1,i-1]
[1,i−1]中的最大值只要在
[
1
,
k
]
[1,k]
[1,k]中此时就是满足题意的,并且不在就是不满足题意的.
因为假设我们的最大值在
[
1
,
k
]
[1,k]
[1,k]中,那么对于
[
k
+
1
,
i
−
1
]
[k+1,i-1]
[k+1,i−1]中来说,我们必然找不到一个比最大值还大的数了,所以此时只能找到为于
i
i
i的真最大值
反之若我们的最大值不在
[
1
,
k
]
[1,k]
[1,k]中,那么对于区间
[
1
,
k
]
[1,k]
[1,k]中的所有数字来说,他们必可以在
[
k
+
1
,
i
−
1
]
[k+1,i-1]
[k+1,i−1]找到他们的区间最大值比他们要大,此时必然是轮不到
i
i
i的,
然后我们简单算一下此时的概率:
有
1
/
n
1/n
1/n的概率位于
i
i
i,区间
[
1
,
i
−
1
]
[1,i-1]
[1,i−1]的最大值有
k
/
(
i
−
1
)
k/(i-1)
k/(i−1)的概率位于
[
1
,
k
]
[1,k]
[1,k]中,并且只有此时才是满足题意的.此时的概率就是
1
n
∗
k
i
−
1
\frac{1}{n}*\frac{k}{i-1}
n1∗i−1k.然后显然我们的
i
i
i可以是
[
k
+
1
,
n
]
[k+1,n]
[k+1,n]中的所有位置(注意此时我们是固定k的).此时就有
k
n
∗
∑
i
=
k
+
1
n
1
i
−
1
\frac{k}{n}*\sum_{i=k+1}^n{\frac{1}{i-1}}
nk∗i=k+1∑ni−11简单化简一下,也就是
k
n
∗
∑
i
=
k
n
−
1
1
i
\frac{k}{n}*\sum_{i=k}^{n-1}{\frac{1}{i}}
nk∗i=k∑n−1i1
对于这个函数,我们发现这个是关于
k
k
k的峰值函数.所以找最大值是可以进行三分的.(当然也可以直接求导).但是据出题人解释,怕n太大丢double精度,所以测试数据n取了一个较小的值.所以此时我们直接暴力枚举
k
k
k即可.考虑预处理出
1
/
i
1/i
1/i的前缀和然后暴力.
下面是具体的代码部分;
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
inline void print(__int128 x){
if(x<0) {putchar('-');x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
#define maxn 1000000
const double eps=1e-8;
#define int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
double sum[maxn];
int main() {
int T=read();
for(int i=1;i<=10010;i++) {
sum[i]=sum[i-1]+1/(double)i;
}
while(T--) {
int n;cin>>n;
double Sum=1/(double)n;int ans=0;
for(int i=1;i<=n;i++) {
double this_sum=(double)i/(double)n*(sum[n-1]-sum[i-1]);
if(this_sum>Sum) {
ans=i;Sum=this_sum;
}
}
cout<<ans<<endl;
}
return 0;
}