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<pj. For example, a permutation [4,1,3,2] contains 4 inversions: (2,1),(3,1),(4,1),(4,3).
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
n−1,
n
−
2
n-2
n−2,
⋯
\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+2nCnn−1an−1+2nCnn−2an−2+⋯+2nCn2a2+2nCnn(2Cn2+2nCnn−1an−1+2nCnn−2an−2+⋯+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+2nCnn−1an−1+2nCnn−2an−2+⋯+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=2n−12nx
带入
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+2nCnn−1an−1+2nCnn−2an−2+⋯+2nCn2a2)2n−12n
这就是一个递推式,对于
n
n
n的范围是
1
∼
3000
1\sim3000
1∼3000,所以
O
(
n
2
)
O(n^2)
O(n2)预处理还是不虚的,
2
2
2的幂次和幂次的逆元都可以预处理,但是
2
n
−
1
2^n-1
2n−1的逆元只能每次带快速幂求逆元了。
处理完
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}
2→31
3
→
8
9
3\rightarrow \frac{8}{9}
3→98
4
→
15
9
4\rightarrow \frac{15}{9}
4→915
5
→
24
9
5\rightarrow \frac{24}{9}
5→924
就可以发现答案是
n
2
−
1
9
\frac{n^2-1}{9}
9n2−1
#include <bits/stdc++.h>
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<N;i++)
{
C[i][0]=C[i][i]=1;
}
for(int i=1;i<N;i++)
{
for(int j=1;j<i;j++)
{
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
}
long long a[N];
long long ans[N];
int fac[N];//2^n
int inv[N];//2^n的逆元
int _inv[N];/线性的逆元
int main()
{
get_C();
fac[0]=1;
for(int i=1;i<N;i++)
fac[i]=fac[i-1]*2%mod;
inv[N-1]=quickmod(fac[N-1],mod-2);
for(int i=N-2;i>=0;i--)
{
inv[i]=1ll*inv[i+1]*2%mod;
}
_inv[0]=_inv[1]=1;
for(int i=2;i<N;i++)
_inv[i]=(1ll*(mod-mod/i)*_inv[mod%i])%mod;
for(int i=2;i<N;i++)
{
a[i]=1ll*C[i][2]*inv2%mod;
for(int j=i-1;j>=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;i++)
{
for(int j=2;j<=i;j++)
{
ans[i]=(ans[i]+a[j])%mod;
}
ans[i]=ans[i]*_inv[i]%mod;
}
long long n;
while(scanf("%lld",&n)!=EOF)
{
printf("%lld\n",ans[n]);
}
return 0;
}
根据结论 n 2 − 1 9 \frac{n^2-1}{9} 9n2−1的代码
#include <bits/stdc++.h>
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;
}