一.题目链接:
HDU-6595
二.题目大意:
题目给定一个正整数N.
在区间[1, N]中随机等概率地选取一个正整数n,然后随机等概率地生成一个长度为n的排列A,然后调用函数 CALCULATE(A).
SUBSEQUENCE(A):随机生成一个序列A的子序列.
CNTINVERSIONPAIRS(A):返回序列A的逆序对数.
CALCULATE(A):计算序列A的逆序数C,再随机选取一个A的子序列B,递归返回C + CALCULATE(B).
求返回结果CALCULATE(A)的期望.
三.分析:
通过找规律或递推或严格的数学证明都不难得到:长度为 n 的随机排列的逆序对数的期望为 .
在长度为n的排列中选取了长度为m的子序列的概率为.
所以 .
化简可得:.
由此可递推计算f[i].
那么最终答案为
四.代码实现:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = (int)3e3;
const int inf = 0x3f3f3f3f;
const ll mod = (ll)998244353;
const double eps = 1e-5;
ll f[M + 5];
ll fac[M + 5];
ll invfac[M + 5];
ll c[M + 5][M + 5];
ll g[M + 5];
ll quick(ll a, ll b, ll p)
{
ll s = 1;
while(b)
{
if(b & 1) s = s * a % p;
a = a * a % p;
b >>= 1;
}
return s;
}
ll inv(ll n, ll p)
{
return quick(n, p - 2, p);
}
ll C(ll n, ll m, ll p)
{
return fac[n] * invfac[m] % mod * invfac[n - m] % mod;
}
void init()
{
fac[0] = 1; for(int i = 1; i <= M; ++i) fac[i] = fac[i - 1] * i % mod, invfac[i] = inv(fac[i], mod);
for(int i = 0; i <= M; ++i) for(int j = 0; j <= i; ++j) c[i][j] = C(i, j, mod);
ll p = 1, inv4 = inv(4, mod), sum = 0;
for(int i = 1; i <= M; ++i)
{
f[i] = i * (i - 1) % mod * inv4 % mod;
ll s = 0; for(int j = 0; j < i; ++j) s = (s + c[i][j] * f[j] % mod) % mod;
p = p * 2 % mod; f[i] = (f[i] + s * inv(p, mod) % mod) % mod;
f[i] = f[i] * p % mod * inv(p - 1, mod) % mod;
sum = (sum + f[i]) % mod;
g[i] = sum * inv(i, mod) % mod;
}
}
int main()
{
// freopen("output.txt", "w", stdout);
init();
int n;
while(~scanf("%d", &n)) printf("%lld\n", g[n]);
return 0;
}