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}
    so
    count[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数学公式…

我明白了,所以我只想减去