1. 程式人生 > >【JZOJ5931】氣泡排序

【JZOJ5931】氣泡排序

description

小 S 開始專注於研究⻓度為 n 的排列,他想知道,在你運氣足夠好的情況下(即每次氣泡排序的交換次數都是可能的最少交換次數,彷彿有上帝之手在操控),對於一個等概率隨機的長度為n 的排列,進行這樣的氣泡排序的期望交換次數是多少?


analysis

  • 結論題

  • f [ i ]

    f[i] i i 的答案,推 f [ i
    + 1 ] f[i+1]
    即可

  • 插入 i + 1

    i+1 這個數,前 i i 位都會產生 1 + f [ i ] 1+f[i] 的代價,只有 i + 1 i+1 位產生 f [ i ] f[i] 的代價

  • 把式子化一下就是 f [ i + 1 ] = f [ i ] + i i + 1 f[i+1]=f[i]+{i\over i+1}

  • 要用 O ( n ) O(n) 求逆元


code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 10000005
#define mod 998244353ll
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define O3 __attribute__((optimize("-O3")))

using namespace std;

ll f[MAXN],inv[MAXN];
ll n;

O3 inline ll read()
{
    ll x=0,f=1;
    char ch=getchar();
    while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
    while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
O3 int main()
{
	freopen("inverse.in","r",stdin);
	freopen("inverse.out","w",stdout);
	f[1]=0,inv[1]=1;
	fo(i,2,MAXN)inv[i]=(mod-mod/i)*1ll*inv[mod%i]%mod,f[i]=((f[i-1]+(i-1)*inv[i])%mod+mod)%mod;
	n=read();
	while (n--)printf("%lld\n",f[read()]);
	return 0;
}