2023杭电多校第二场 1011.SPY finding NPY

54 篇文章 0 订阅
11 篇文章 1 订阅

传送门: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,i1]中的最大值只要 [ 1 , k ] [1,k] [1,k]中此时就是满足题意的,并且不在就是不满足题意的.

因为假设我们的最大值在 [ 1 , k ] [1,k] [1,k]中,那么对于 [ k + 1 , i − 1 ] [k+1,i-1] [k+1,i1]中来说,我们必然找不到一个比最大值还大的数了,所以此时只能找到为于 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,i1]找到他们的区间最大值比他们要大,此时必然是轮不到 i i i的,

然后我们简单算一下此时的概率:
1 / n 1/n 1/n的概率位于 i i i,区间 [ 1 , i − 1 ] [1,i-1] [1,i1]的最大值有 k / ( i − 1 ) k/(i-1) k/(i1)的概率位于 [ 1 , k ] [1,k] [1,k]中,并且只有此时才是满足题意的.此时的概率就是 1 n ∗ k i − 1 \frac{1}{n}*\frac{k}{i-1} n1i1k.然后显然我们的 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}} nki=k+1ni11简单化简一下,也就是 k n ∗ ∑ i = k n − 1 1 i \frac{k}{n}*\sum_{i=k}^{n-1}{\frac{1}{i}} nki=kn1i1
对于这个函数,我们发现这个是关于 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值