Java 在K次试验后,一个数N降低为非正值的概率
假设我们有一个整数Java 在K次试验后,一个数N降低为非正值的概率,java,python,algorithm,permutation,probability,Java,Python,Algorithm,Permutation,Probability,假设我们有一个整数N。在每个K试验中,该数字从均匀间隔[0,M](因此,如果我们有M=5,那么每个试验中的N数字可以减少0,1,2,3,4或5,每个都有一个概率1/6).在K试验后,数字N小于或等于零的概率是多少?例如,对于N=2,M=1和K=3,答案是0.5 我可以编写蛮力解决方案,简单地枚举每个排列,总共(M+1)^K,并在N最终成为时计算案例。下面是一个计算所需概率的程序 N=2 M=1 K=3 计数=[0]*(N+1) 上一个=[0]*(N+1) 计数[0]=1#空集 对于范围(K)内的
N
。在每个K
试验中,该数字从均匀间隔[0,M]
(因此,如果我们有M=5
,那么每个试验中的N
数字可以减少0
,1
,2
,3
,4
或5
,每个都有一个概率1/6
).在K
试验后,数字N
小于或等于零的概率是多少?例如,对于N=2
,M=1
和K=3
,答案是0.5
我可以编写蛮力解决方案,简单地枚举每个排列,总共
(M+1)^K
,并在N
最终成为时计算案例。下面是一个计算所需概率的程序
N=2
M=1
K=3
计数=[0]*(N+1)
上一个=[0]*(N+1)
计数[0]=1#空集
对于范围(K)内的i:
#将计数移到上一个
对于范围(N+1)中的索引:
上一个[索引]=计数[索引]
计数[索引]=0
#计算新计数
对于范围(N+1)内的prevSum:
对于范围(M+1)中的值:
newSum=min(N,prevSum+值)
计数[newSum]+=prev[prevSum]
ans=(计数[N]/pow(M+1,K))
打印(ans)
- 在这里,我们跟踪
count[]
数组中添加到给定总和的集合数的计数
- 任何加起来的值大于
N
的集合都将添加到count[N]
这是怎么回事
- 最初,
count[0]=1
,因为我们只有空集{}
- (K=1):尝试向所有现有集合添加一个元素:
{}+0,{}+1
。我们得到{0},{1}
socount[0]=1
,count[1]=1
- (K=2):现在再次向所有现有集合添加一个元素:
{0}+0,{0}+1,{1}+0,{1}+1
。我们得到{0,0},{0,1},{1,0},{1,1}
所以计数[0]=1
,计数[1]=2
,计数[2]=1
- (K=3):现在再次向所有现有集合添加一个元素,我们将得到
{0,0,0},{0,0,1},{0,1,0},{1,0,0},{0,1,1},{1,0,1},{1,1,0},{1,1,1}
。
因此计数[0]=1
,计数[1]=3
,计数[2]=4
- 在最后一步中,我们还将
{1,1,1}
添加到计数[2]
中,因为我们将其总和为=N
的所有集合添加到计数[N]
- 最后,为了计算概率,我们将
计数[N]
(总和为=N
的所有集合的计数)除以所有可能集合的计数,即(M+1)^K
复杂度是O(N*M*K)
。在最坏的情况下N=M*K
,因此时间复杂度可以重写为:O((M*K)^2)
优化1:
如果您为K
的每次迭代写下count[]
数组,您可以发现一个有趣的观察结果:
M=1
sum: 0 1 2 3 4
K=0: 1 0 0 0 0 (if empty consider value as 0 from now on)
K=1: 1 1
K=2: 1 2 1
K=3: 1 3 3 1
K=4: 1 4 6 4 1
M=2
sum: 0 1 2 3 4 5 6 7 8
K=0: 1
K=1: 1 1 1
K=2: 1 2 3 2 1
K=3: 1 3 6 7 6 3 1
K=4: 1 4 10 16 19 16 10 4 1
这里的观察结果是:
通过保持先前M值的滚动和,我们可以编写代码的优化版本:
N=2
M=1
K=3
最大值=M*K
计数=[0]*(最大值+1)
prev=[0]*(最大值+1)
计数[0]=1#空集
对于范围(K)内的i:
#将计数移到上一个
对于范围内的索引(maxValue+1):
上一个[索引]=计数[索引]
计数[索引]=0
rollingSum=0
#计算新计数
对于范围内的总和(最大值+1):
rollingSum+=上一个[总和]
如果(总和>M):
rollingSum-=prev[总和-(M+1)]
计数[总和]=滚动总和
#添加总和大于等于N的集合的所有计数
ans=总和(计数[N:])/pow(M+1,K)
打印(ans)
这种方法的时间复杂度是
O(M*(K^2))这里我只关注算法级别
该问题相当于计算出概率大于K步后,各值之和大于N
让我们调用p
在给定步骤中选择on元素的概率
p = 1/(M+1)
其思想是以多项式形式表示一次试验的概率集:
A[x] = p * (1 + x^2 + x^3 + ... + x^{M-1})
然后在K
步骤之后,概率集由以下公式给出:
F[x] = p^K * (1 + x^2 + x^3 + ... + x^{M-1})^K = p^K A[x]^K
P = sum_{i >= N} p_i
最后,如果F[x]=sum\u i p\u i x^i
,则概率由下式给出:
F[x] = p^K * (1 + x^2 + x^3 + ... + x^{M-1})^K = p^K A[x]^K
P = sum_{i >= N} p_i
然后问题是计算多项式幂A[x]^k
第一次尝试符合以下条件:
递归计算:然后我们得到了与第一个答案中提供的解等价的东西,同样复杂
第二次尝试在于隐含地考虑K
的二进制表示
伪代码:
F[x] = 1
T[x] = A[x]
Power = K
while (Power != 0)
if (Power mod 2 == 1) F[x] = F[x] * T[x]
T[x] = T[x] * T[x]
Power = Power / 2
end while
步骤数等于log2(K)
在每次迭代中,多项式的次数乘以2:复杂性由最后一步决定, 其中多项式的阶数等于
KM
最后一步的复杂性是O(K^2 M^2) 如果
C=K^2M^2
,则功率计算的全局复杂性为O(C+C/4+C/8+…)=O(C)=O(K^2M^2)
与第一种方法相比,这种方法似乎没有任何优势(我可能在复杂性评估中出错了!)
第三种方法考虑到多项式乘法等价于卷积,并且可以通过FFT过程执行。由于最终大小为O(KM),那么复杂性为O(mk(logm+logk))
在这里详细描述这个方法需要很多时间。你可以找到很多参考资料
例如,在互联网上,关于这个主题
旁注:很遗憾不能在这里插入latex数学公式…我明白了,所以我只想减去