【题解】P1654 OSU!(组合数学,概率,期望)
【题解】P1654 OSU!
post on 2022.5.4:
昨天艾教重新很详细的讲了一遍这道题,之前就感觉这道题并没有完全理解。
昨天艾教讲了之后我才茅塞顿开。这里记录一下艾教的推导过程,一是让我再次捋一遍思路,更加清楚;二是希望我以后见到类似的题目之后,能有所进步,而不是像刚开始一样手足无措。
题目链接
思路分析
解法一
用
那么根据期望的定义有:
同理,
考虑递推式。
假设每次的成功概率是
对于第
所以对于二次:
同理,
我们可以发现这玩意其实满足二项式定理。
那么其实可以拓展到
考虑统计答案。
可以发现:
这个式子如何理解呢?
对于一个答案序列,我们最后统计答案时只计算每一段连续的 1 中最后一个位置的答案。
举个例子:当我们最后序列是 0011101101
这个序列时,我们最后答案计算方法是:
也就是说,实际上只有每一段的最后一个位置对答案有贡献。而其它位置,可以看做是对答案无贡献的。
那么在具体的式子里面如何判断一个位置是不是一段连续的 1 的最后一个位置呢?
显然对于一个位置
那么就很显然了。根据期望的定义,用第
解法二
我们首先从一个例子引入。
假设我们最终的答案序列是 1110110
,那么答案显然为
在这里,我们可以换一种思路:将每一段连续的 1 的最后一个位置的贡献分配到这一段包含连续的 1 的所有位置上去。
比如:对于上面这个例子,我们可以看做:第一个位置对答案贡献了 1,第二个位置对答案贡献了 7,第三个位置对答案贡献了 19。
也就是说,对于一段连续的 1 中的第
所以
拓展
根据一次,二次,三次期望,我们可以拓展到
通过解法一中的递推式我们可以发现:
二项式定理解决即可。
代码实现
//luoguP1654
#include<iostream>
#include<cstdio>
#include<iomanip>
using namespace std;
const int maxn=1e5+10;
double p[maxn];
double s1[maxn],s2[maxn],s3[maxn],ans[maxn];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int main()
{
int n;
n=read();
for(int i=1;i<=n;i++)cin>>p[i];
for(int i=1;i<=n;i++)
{
s1[i]=(s1[i-1]+1)*p[i];
s2[i]=(s2[i-1]+2*s1[i-1]+1)*p[i];
s3[i]=(s3[i-1]+3*s2[i-1]+3*s1[i-1]+1)*p[i];
ans[i]=ans[i-1]+(1-p[i+1])*s3[i];//解法一
//ans[i]=ans[i-1]+(3*s2[i-1]+3*s1[i-1]+1)*p[i];//解法二
}
cout<<fixed<<setprecision(1)<<ans[n]<<endl;
return 0;
}
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· .NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想
· Browser-use 详细介绍&使用文档
· 软件产品开发中常见的10个问题及处理方法
· Vite CVE-2025-30208 安全漏洞