HDU 6595 Everything Is Generated In Equal Probability(递推求期望|找规律)

HDU 6595 Everything Is Generated In Equal Probability(递推求期望|找规律)_第1张图片
Y_UME wants to play with this program. Firstly, he randomly generates an integer n∈[1,N] in equal probability. And then he randomly generates a permutation of length n in equal probability. Afterwards, he runs the interesting program(function calculate()) with this permutation as a parameter and then gets a returning value. Please output the expectation of this value modulo 998244353.

A permutation of length n is an array of length n consisting of integers only ∈[1,n] which are pairwise different.

An inversion pair in a permutation p is a pair of indices (i,j) such that i>j and pi

In mathematics, a subsequence is a sequence that can be derived from another sequence by deleting some or no elements without changing the order of the remaining elements. Note that empty subsequence is also a subsequence of original sequence.

Refer to https://en.wikipedia.org/wiki/Subsequence for better understanding.

题意

给你一个 N N N,然后在 [ 1 , N ] [1,N] [1,N]中随机生成一个 n n n,概率为 1 N \frac{1}{N} N1 n n n表示一个长度为 n n n的排列, n n n中元素为 [ 1 , n ] [1,n] [1,n],然后 n n n的排列是等概率( 1 n ! \frac{1}{n!} n!1)产生的,对于生成的排列让其进行一个程序,程序先求当前排列的逆序对对数,然后再生成一个子序列,用子序列进行递归,直到子序列长度为0则退出,程序返回逆序对数的总数,现在输入一个 N N N,求程序产生的答案的期望

思路

我们先不考虑 N N N的期望,我们先考虑长度为 n n n的排列他能产生逆序对数量的期望,根据逆序对的定义,相当于从长度为 n n n的数中挑出两个数字,那么总数就是 C n 2 C_{n}^2 Cn2,因为挑出的是两个数,所以是逆序对的可能是 1 2 \frac{1}{2} 21,故对于长度为 n n n的排列所能产生的逆序对的期望为 C n 2 2 \frac{C_{n}^2}{2} 2Cn2。那么我们再考虑将长度为 n n n的排列放入程序中所能产生的逆序对的数量的期望。
我们考虑长度为 n n n的排列在程序中所能产生的期望,由于程序是递归一直调用的,所以长度为 n n n的排列也会包含长度为{ n − 1 n-1 n1, n − 2 n-2 n2, ⋯ \cdots , 2 2 2}的排列在程序中所能产生的期望,而这些期望只会和产生这些子序列的概率有关,例如长度为 n n n的序列他产生长度为 k k k的子序列的概率为 C n k 2 n \frac{C_{n}^k}{2^n} 2nCnk。那么我们令机器对于长度为 n n n的排列所能产生的期望为 a n a_n an,那么就可以得到公式
a n = C n 2 2 + C n n − 1 2 n a n − 1 + C n n − 2 2 n a n − 2 + ⋯ + C n 2 2 n a 2 + C n n 2 n ( C n 2 2 + C n n − 1 2 n a n − 1 + C n n − 2 2 n a n − 2 + ⋯ + C n 2 2 n a 2 + C n n 2 n ( ⋯   ) ) a_n=\frac{C_{n}^2}{2}+\frac{C_{n}^{n-1}}{2^{n}}a_{n-1}+\frac{C_{n}^{n-2}}{2^{n}}a_{n-2}+\cdots+\frac{C_{n}^{2}}{2^{n}}a_{2}+\frac{C_n^n}{2^{n}}(\frac{C_{n}^2}{2}+\frac{C_{n}^{n-1}}{2^{n}}a_{n-1}+\frac{C_{n}^{n-2}}{2^{n}}a_{n-2}+\cdots+\frac{C_{n}^{2}}{2^{n}}a_{2}+\frac{C_n^n}{2^{n}}(\cdots)) an=2Cn2+2nCnn1an1+2nCnn2an2++2nCn2a2+2nCnn(2Cn2+2nCnn1an1+2nCnn2an2++2nCn2a2+2nCnn())

x = C n 2 2 + C n n − 1 2 n a n − 1 + C n n − 2 2 n a n − 2 + ⋯ + C n 2 2 n a 2 x=\frac{C_{n}^2}{2}+\frac{C_{n}^{n-1}}{2^{n}}a_{n-1}+\frac{C_{n}^{n-2}}{2^{n}}a_{n-2}+\cdots+\frac{C_{n}^{2}}{2^{n}}a_{2} x=2Cn2+2nCnn1an1+2nCnn2an2++2nCn2a2
那么原式就会变成

a n = x + C n n 2 n ( x + C n n 2 n ( x + C n n 2 n ( ⋯   ) ) a_n=x+\frac{C_{n}^n}{2^n}(x+\frac{C_n^n}{2^n}(x+\frac{C_n^n}{2^n}(\cdots)) an=x+2nCnn(x+2nCnn(x+2nCnn())
⋯ \cdots 为无穷

这个的序列的含义是,程序是随机产生一个序列的所以有 C n k 2 n \frac{C_n^k}{2^n} 2nCnk的概率产生长度为 k k k的子序列,若 k < n k<n k<n,那么我们加上 a k a_k ak的期望就可以了,但是若 k = n k=n k=n,就是长度为 n n n的排列再来一次,所以对长度为 n n n的序列会产生无限递归的情况。
那么我们对于式子将括号展开再将 x x x提出就有(其中 C n n 2 n = 1 2 n \frac{C_n^n}{2^n}=\frac{1}{2^n} 2nCnn=2n1)
a n = x ∑ i = 0 ∞ ( 1 2 n ) i a_n=x\sum_{i=0}^{\infty}(\frac{1}{2^n})^i an=xi=0(2n1)i
后面的部分就是一个等比数列求和再趋近于无穷那么就有
a n = 2 n x 2 n − 1 a_n=\frac{2^nx}{2^n-1} an=2n12nx
带入 x x x
a n = ( C n 2 2 + C n n − 1 2 n a n − 1 + C n n − 2 2 n a n − 2 + ⋯ + C n 2 2 n a 2 ) 2 n 2 n − 1 a_n=(\frac{C_{n}^2}{2}+\frac{C_{n}^{n-1}}{2^{n}}a_{n-1}+\frac{C_{n}^{n-2}}{2^{n}}a_{n-2}+\cdots+\frac{C_{n}^{2}}{2^{n}}a_{2})\frac{2^n}{2^n-1} an=(2Cn2+2nCnn1an1+2nCnn2an2++2nCn2a2)2n12n
这就是一个递推式,对于 n n n的范围是 1 ∼ 3000 1\sim3000 13000,所以 O ( n 2 ) O(n^2) O(n2)预处理还是不虚的, 2 2 2的幂次和幂次的逆元都可以预处理,但是 2 n − 1 2^n-1 2n1的逆元只能每次带快速幂求逆元了。
处理完 a n a_n an还不是答案,由于答案是要求在 [ 1 , N ] [1,N] [1,N]中随机产生长度为 n n n的序列的期望,所以有
A n = 1 n ( a 2 + a 3 + ⋯ + a n ) A_n=\frac{1}{n}(a_2+a_3+\cdots+a_n) An=n1(a2+a3++an)
所以还有多预处理一个线性求逆元
也可以试着打表出前几项有
2 → 1 3 2\rightarrow \frac{1}{3} 231
3 → 8 9 3\rightarrow \frac{8}{9} 398
4 → 15 9 4\rightarrow \frac{15}{9} 4915
5 → 24 9 5\rightarrow \frac{24}{9} 5924
就可以发现答案是 n 2 − 1 9 \frac{n^2-1}{9} 9n21

#include 
using namespace std;
const int N=3e3+5;
const int mod=998244353;
const int inv2=(mod+1)>>1;
int C[N][N];
long long quickmod(long long a,long long b)
{
    long long ans=1;
    while(b)
    {
        if(b%2==1)
            ans=ans*a%mod;
        a=a*a%mod;
        b=b/2;
    }
    return ans;
}
void get_C()
{
    for(int i=0;i=0;i--)
    {
        inv[i]=1ll*inv[i+1]*2%mod;
    }
    _inv[0]=_inv[1]=1;
    for(int i=2;i=2;j--)
        {
            a[i]=(a[i]+1ll*C[i][j]*inv[i]%mod*a[j]%mod)%mod;
        }
        a[i]=a[i]*fac[i]%mod*quickmod((fac[i]-1+mod)%mod,mod-2)%mod;
    }
    for(int i=2;i

根据结论 n 2 − 1 9 \frac{n^2-1}{9} 9n21的代码

#include 
using namespace std;
const int mod=998244353;
long long quickmod(long long a,long long b)
{
    long long ans=1;
    while(b)
    {
        if(b%2==1)
            ans=ans*a%mod;
        a=a*a%mod;
        b=b/2;
    }
    return ans;
}
int main()
{
    long long inv=quickmod(9,mod-2);
    long long n;
    while(scanf("%lld",&n)!=EOF)
    {
        printf("%lld\n",(n*n%mod-1+mod)%mod*inv%mod);
    }
    return 0;
}

你可能感兴趣的:(概率dp,排列组合)