F:
/* 考虑每次选key,key=1...n的概率一样 所以下一层怎么分割这n个数的概率都相等 因此答案只和nk有关系 f[n][k]长度为n的序列 k是层数 逆序对期望个数*n! 然后 分割之后的子部分离散化之后就变成子问题 所以方程 f[i][j]=sum( f[k-1][j-1]/(k-1)!*(j-1)!+f[i-k][j-1]/(i-k)!*(j-1)! ) 然后我们把(j-1)!提出来 就可用前缀和优化 n*n */ #include<cstdio> #include<cstring> #include<iostream> #define maxn 6010 #define mod 998244353 #define ll long long using namespace std; ll T,n,k,f[maxn][maxn],cas,J[maxn],inv[maxn],sum[maxn]; ll qc(ll a,ll b){ ll res=1; while(b){ if(b&1)res=res*a%mod; a=a*a%mod;b>>=1; } return res; } void pre(){ ll n=6000,k=6000,ni=qc(4,mod-2); J[1]=1;for(ll i=2;i<=n;i++)J[i]=J[i-1]*i%mod; for(ll i=1;i<=n;i++)inv[i]=qc(J[i],mod-2); for(ll i=2;i<=n;i++){ f[i][1]=i*(i-1)*ni%mod*J[i]%mod; for(ll j=2;j<=i;j++) f[i][j]=(f[i][j]+sum[j-1]*J[i-1]%mod*2)%mod; for(ll j=1;j<=i;j++) sum[j]=(sum[j]+f[i][j]*inv[i]%mod)%mod; } } int main(){ pre();scanf("%lld",&T); while(T--){ scanf("%lld%lld",&n,&k); printf("Case #%lld: %lld ",++cas,f[n][k]); } return 0; }