題意:
給定一個N,隨機從[1,N]里產生一個n,然后隨機產生一個n個數的全排列,求出n的逆序數對的數量,加到cnt里,然后隨機地取出這個全排列中的一個非連續子序列(注意這個子序列可以是原序列),再求出這個子序列的逆序數對,加到cnt里,重復這個過程,直到最后取出的為空。
題解:
先不考慮第一步隨機從[1,N]里產生一個n,只考慮n給定的情況,求出了f[n],那么最后的結果就是
$ ans[N]=\frac{\sum_{n=1}^N f[n]}{N} $
賽時和隊友利用找規律法和暴力模擬法推出
$ f[i]=\sum_{i=1}^{n-1}\frac{2i}{3} $
下面給出證明:
因為任意一個長度為n的全排列,其所含的逆序對的期望為
$ \binom{n}{2}/2 $ (不難理解,就是隨便取兩個點交換一下就出來一個逆序對)
而取出的那一個非連續子序列,我們把它里面的數字離散化以后也是一個全排列,所以
$ f[i]=\binom{n}{2}/2+\frac{1}{2^i}\sum_{j=0}^i\binom{i}{j}f[j] $
移項,得到遞推公式
$ f[i]=\frac{2^{i-1}}{2^i-1}\binom{n}{2}/2+\frac{1}{2^i-1}\sum_{j=0}^{i-1}\binom{i}{j}f[j] $
f[1]=0,不難推出通項公式
$ f[i]=\sum_{i=1}^{n-1}\frac{2i}{3} $
代碼:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <cctype> #include <string> #include <vector> #include <map> #include <set> #include <vector> #include <queue> #include <stack> const int MOD = 998244353; #define rep(i,n,m) for(int i=n;i<=m;++i) const double eps = 1e-16; #define ll long long using namespace std; const int maxn = 10000000; const int maxm = 2e5 + 10; const int inf = 1 << 28; typedef pair<int, int> P; #define zero(a) fabs(a)<eps inline int read() { int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = 10 * x + ch - '0'; ch = getchar(); } return x * f; } ll quick_mod(ll x, ll n) { ll res = 1; while (n) { if (n & 1) res = res * x % MOD; x = x * x % MOD; n = n >> 1; } return res; } ll a[3005]; void init() { a[0] = a[1] = 0; a[2] = 2; for (int i = 3; i <= 3000; ++i) a[i] = a[i - 1] + (i - 1) * 2; for (int i = 1; i <= 3000; ++i) a[i] += a[i - 1]; } int main() { ll n; init(); while (~scanf("%lld", &n)) { if (n == 1) { cout << "0" << endl; continue; } ll a1 = a[n]; ll b = 3 * n; ll x = quick_mod(b, MOD - 2); cout << a1 % MOD * x % MOD<<endl; } }
