题目大意
分析
求概率可以转化成计数,那么对于第i个位置,就是求有多少种方案数不会选到i,除以总方案数即可,总方案数很简单,就是(n-1)!!。
假如我们把i剔除掉,断开的区间合并起来形成一个长度为n-1区间,那么这个区间有多少种合法方案数?显然是(n-2)!!。但真的有那么多方案不会选到i吗?
考虑不会选到i的方案数长什么样子:设每次选取的两个数为(x,y),那么我们要保证所有的x都小于i。而很显然(n-2)!!里包含了x大于i的方案。
观察到当i<n/2的时候,方案数肯定为0,而i>=n/2时,我们要保证方案的x均位于1~i-1。那么等价于保证i+1 ~n均对应某个y。现在我们只需要求,i+1 ~n的位置均对应y的方案数即可。设req=n-i,方案数为
C
i
−
1
r
e
q
∗
r
e
q
!
∗
(
i
−
1
−
r
e
q
−
1
)
!
!
C_{i-1}^{req}*req!\ *(i-1-req \ \ -1)!!
Ci−1req∗req! ∗(i−1−req −1)!!
前面两个因子表示,我要为后面的y,在1~i-1中要选req个对应的x,然后顺序可以乱安排。第三项表示前面剩下未确定的位置的总方案数:前面未确定的还剩i-1-req个,对应的合法方案数就是 (size-1)!!
代码
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
#define cmax(a,b) (a=(a>b)?a:b)
#define cmin(a,b) (a=(a<b)?a:b)
typedef long long ll;
typedef double db;
const int N=5e6+5,M=1e6+5,mo=998244353;
ll irev[N],rev[N],rev2[N],f[N],ans,fac[N];
int T,n,i,j,req;
void irev_predo(int n,int p)
{
int i;
irev[1]=1;
fo(i,2,n)
{
irev[i]=-(ll)(p/i)*irev[p%i]%p;
if (irev[i]<0) irev[i]+=p;
}
}
void predo(int n)
{
fac[0]=1;
fo(i,1,n) fac[i]=fac[i-1]*i%mo;
rev[1]=rev[0]=1;
rev2[1]=rev2[0]=1;
fo(i,2,n) rev[i]=rev[i-1]*irev[i]%mo,rev2[i]=rev2[i-2]*irev[i]%mo;
f[0]=1;
fo(i,0,n/2)
f[i+1]=f[i]*(2*i+1)%mo*(i+1)%mo;
fo(i,0,n/2) f[i]=f[i]*rev[i]%mo;
}
ll c(int n,int m)
{
if (n>m||m<0||n<0) return 0;
if (n==m) return 1;
return 1ll*fac[m]*rev[n]%mo*rev[m-n]%mo;
}
void Print(ll x)
{
if (!x) putchar('0');
int w[20];
w[0]=0;
while (x) w[++w[0]]=x%10,x/=10;
while (w[0]) putchar('0'+w[w[0]--]);
}
int main()
{
freopen("12.in","r",stdin);
freopen("12.out","w",stdout);
n=5e6;
irev_predo(n,mo);
predo(n);
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
fo(i,1,n)
{
req=n-i;
if (i-1<req) ans=0;
else
{
//c(req,i-1)*fac[req]%mo*f[]
ans=c(req,i-1)*fac[req]%mo*f[(i-1-req)/2]%mo*rev2[n-1]%mo;
}
Print(ans);
if (i!=n) putchar(' ');
}
putchar('\n');
}
}