F:ios
/* 考慮每次選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\n",++cas,f[n][k]); } return 0; }