zoukankan      html  css  js  c++  java
  • Everything Is Generated In Equal Probability(概率与期望)

    题目地址

    Problem Description

    一天,Y_UME得到一个整数N和一个有趣的程序,如下图所示:

    img

    大致意思:

    这是一个递归程序。

    1.答案加上数组中逆序对的个数。

    2.对数组等概率地取一个子序列(可以为空序列)

    3.递归计算子序列, 并把结果加到答案中

    4.返回答案

    Y_UME想玩这个程序。首先,随机生成一个等概率的整数n∈[1,n]。然后他随机生成一个长度为n的排列,概率相等。然后,他运行有趣的程序(function calculate()),将这个排列作为参数,然后获得一个返回值。请输出此值的期望值998244353。

    长度n的置换是长度n的数组,其中只包含一对不同的整数∈[1,n]。

    置换p中的反转对是一对索引(i,j),使得i>j和<pj。例如,一个置换[4,1,3,2]包含4个逆序:(2,1),(3,1),(4,1),(4,1),(4,3)。

    在数学中,子序列是一个序列,它可以从另一个序列中派生出来,方法是删除一些或不删除元素,而不改变其余元素的顺序。注意,空子序列也是原始序列的子序列。

    为了更好地理解,请参考https://en.wikipedia.org/wiki/ence

    Input

    有多个测试用例。

    每种情况都以包含一个整数N(1≤N≤3000)的行开始。

    保证所有测试用例的N之和不大于5×104。

    Output

    对于每个测试用例,输出一行包含一个表示答案的整数。

    Sample Input

    1
    2
    3
    

    Sample Output

    0
    332748118
    554580197
    

    Solution

    首先考虑一个长度为n的全排列期望产生多少逆序对

    n长序列则最多有(frac{n(n-1)}{2})组逆序对, 其中每对出现的概率为(frac12), 所以期望为(frac{n(n-1)}{4})

    然后考虑在n长序列中取m长子序列的长度的概率是多少

    因为有(2^n)种取法, 在n中取m个有(C^m_n)种取法, 所以(P=frac{C^m_n}{2^n})

    考虑f(n)表示n长序列的贡献

    边界(f(0)=f(1)=0)

    那么先加上其全排列的贡献: (f(n)+=frac{n(n-1)}{4})

    再加上其子序列对其贡献: (f(n)+=sumlimits_{m=0}^{n}frac{C^m_n}{2^n}f(m))

    所以得出柿子:

    [f(n)=frac{n(n-1)}{4}+sumlimits_{m=0}^{n}frac{C^m_n}{2^n}f(m) ]

    移项得:

    [f(n)=frac{sumlimits_{m=0}^{n-1}frac{C^m_n}{2^n}f(m)+frac{n(n-1)}{4}}{1-frac{1}{2^n}} ]

    最后答案就是:

    [ans=frac{sumlimits_{i=0}^{N}f(i)}{N} ]

    Code

    #include<iostream>
    #define int unsigned long long
    using namespace std;
    const int N=4e3+28,p=998244353;
    int Pow(int x,int y=p-2){
        int re=1;
        while(y){
    	if(y&1)re=re*x%p;
    	x=x*x%p;
    	y>>=1;
        }
        return re;
    }
    int mul[N],inv[N],two[N];
    int inv4;
    int pre(){
        mul[0]=inv[1]=two[0]=1;
        for(int i=1;i<=4000;i++)mul[i]=mul[i-1]*i%p;
        for(int i=0;i<=4000;i++)inv[i]=Pow(mul[i]);
        int inv2=Pow(2);
        inv4=inv2*inv2%p;
        for(int i=1;i<=4000;i++)two[i]=two[i-1]*inv2%p;
    }
    int C(int n,int m){
        int re=mul[n];
        re=re*inv[m]%p;
        re=re*inv[n-m]%p;
        return re;
    }
    int g(int x){
        if(x==0)return 0;
        int re=x*(x+p-1)%p;
        re=re*inv4%p;
        return re;
    }
    int f[N];
    signed main(){
        pre();
        for(int i=2;i<=4000;i++){
    	f[i]=g(i);
    	for(int j=2;j<i;j++){
    	    int tmp=f[j];
    	    tmp=tmp*C(i,j)%p;
    	    tmp=tmp*two[i]%p;
    	    f[i]=(f[i]+tmp)%p;
    	}
    	f[i]=f[i]*Pow(1+p-two[i])%p;
        }
        int n;
        while(scanf("%lld",&n)!=EOF){
    	int ans=0;
    	for(int i=2;i<=n;i++)ans=(ans+f[i])%p;
    	ans=ans*Pow(n)%p;
    	printf("%lld
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    05.迪米特原则 (LOD)
    04.接口隔离原则 (ISP)
    03.依赖倒置原则 (DIP)
    02.里氏替换原则 (LSP)
    01.单一职责原则 (SRP)
    Flutter点击事件的穿透,父元素点击事件覆盖了子元素点击的问题
    flutter dart语法判断 0/0==Nan 1/0==Infinity的问题
    vue项目引入三方字体
    vue echart图表打包后 图片不显示
    vue设置页面的高度100%
  • 原文地址:https://www.cnblogs.com/nlKOG/p/11243080.html
Copyright © 2011-2022 走看看