钦定第一个数为 $p$,令 $m=n-p$ 表示比 $p$ 大的数的个数,那么答案就是

\[\sum_{m=0}^{n-1}\binom{n-1}m\sum_{j_1-j_2\ge k}{m\brack j_1}{n-1-m\brack j_2}\]

表示从 $n-1$ 个下标中选 $m$ 个放 $>p$ 的那些数字。第一类斯特林数 ${m\brack j_1}$ 表示排列 $[m]$ 恰有 $j_1$ 个前缀最值的方案数。

第一类斯特林数的生成函数 $n\brack i$ 是 $\sum\limits_{i}{n\brack i}x^i=x(x+1)(x+2)\cdots(x+n-1)=x^{\overline n}$。

而我们还有一个第一类斯特林数的范德蒙德卷积形式,或者叫做上升幂的二项式定理。

\[(x+y)^{\overline n}=\sum_{m=0}^n\binom nmx^{\overline m}y^{\overline{n-m}}\]

回到之前那个式子,我们用 $x$ 作为 $j_1$ 那块指示元,$x^{-1}$ 作为 $j_2$ 那块指示元。这样 $j_1-j_2\ge k$ 就变成求指数 $\ge k$ 的那些项的系数和。

\[\sum_{i\ge k}[x^i](x+x^{-1})^{\overline{n-1}}=\sum_{j=k}^{n-1}[x^j]\prod_{i=0}^{n-2}(x+x^{-1}+i)\]

不妨平移,乘上一个 $x^{n-1}$

\[\sum_{i\ge k}[x^i](x+x^{-1})^{\overline{n-1}}=\sum_{j=k+n-1}^{2n-2}[x^j]\prod_{i=0}^{n-2}(1+ix+x^2)\]

注意到对称性,我们把 $\sum\limits_{i=k+n-1}^{2n-2}$ 沿着 $n-1$ 翻转答案不变。

\[\sum_{i\ge k}[x^i](x+x^{-1})^{\overline{n-1}}=\sum_{j=0}^{n-1-k}[x^j]\prod_{i=0}^{n-2}(1+ix+x^2)\]

最后分治 NTT 处理即可。

#include<bits/stdc++.h>
#define siz(x) int((x).size())
#define all(x) std::begin(x),std::end(x)
#define fi first
#define se second
using namespace std;
using unt=unsigned;
using loli=long long;
using lolu=unsigned long long;
using pii=pair<int,int>;
mt19937_64 rng(random_device{}());
constexpr int P=998244353;
struct mint{
	int d;
	mint()=default;
	mint(int x):d(x){}
	friend std::istream&operator>>(std::istream&x,mint&y){return x>>y.d;}
	friend std::ostream&operator<<(std::ostream&x,mint y){return x<<y.d;}
	friend mint operator+(mint x,mint y){return (x.d+=y.d)<P?x.d:x.d-P;}
	mint&operator+=(mint z){return (d+=z.d)<P?d:d-=P,*this;}
	friend mint operator-(mint x,mint y){return (x.d-=y.d)<0?x.d+P:x.d;}
	mint&operator-=(mint z){return (d-=z.d)<0?d+=P:d,*this;}
	friend mint operator*(mint x,mint y){return int(1ll*x.d*y.d%P);}
	mint&operator*=(mint z){return d=int(1ll*d*z.d%P),*this;}
	static mint qpow(int x,int y=P-2){int z=1;for(;y;y>>=1,x=int(1ll*x*x%P))if(y&1)z=int(1ll*x*z%P);return z;}
	friend mint operator/(mint x,mint y){return x*=qpow(y.d);}
	mint&operator/=(mint z){return (*this)*=qpow(z.d);}
	friend mint operator^(mint x,mint y){return qpow(x.d,y.d);}
	mint&operator^=(mint z){return *this=qpow(d,z.d);}
	mint operator()(mint z)const{return qpow(d,z.d);}
	mint&operator[](mint z){return *this=qpow(d,z.d);}
	mint inv()const{return qpow(d);}
	mint pow(mint z)const{return qpow(d,z.d);}
	int operator+()const{return d;}
	mint operator-()const{return d?P-d:0;}
	int operator~()const{return ~d;}
};
mint operator""_m(lolu x){return mint(int(x%P));}
struct poly:vector<mint>{
	using vector<mint>::vector;
	static unt bswp(unt num,int len=32){
		num=(num>>16)|(num<<16);
		num=(num&0xff00ff00)>>8|(num&0x00ff00ff)<<8;
		num=(num&0xf0f0f0f0)>>4|(num&0x0f0f0f0f)<<4;
		num=(num&0xcccccccc)>>2|(num&0x33333333)<<2;
		num=(num&0xaaaaaaaa)>>1|(num&0x55555555)<<1;
		return num>>(32-len);
	}
	void dft(int T){
#define F (*this)
		for(int i=0;i<siz(F);i++)
			if(int j=bswp(i,__lg(siz(F)));i<j)std::swap(F[i],F[j]);
		for(int k=1;k<siz(F);k<<=1){
			mint w1=mint(3)^(mint(P-1)/(k*2)),u;
			if(T!=1)w1=1/w1;
			for(int i=0;i<siz(F);i+=k*2){
				u=1;
				for(int j=i;j<i+k;j++,u*=w1){
					mint c1=F[j],c2=u*F[j+k];
					F[j]=c1+c2;
					F[j+k]=c1-c2;
				}
			}
		}
#undef F
	}
	friend istream&operator>>(istream&x,poly&y){
		int len;x>>len;y.resize(len+1);
		return x;
	}
	friend poly operator*(poly F,poly G){
		int tmp=siz(F)+siz(G)-1;
		int len=1<<(__lg(tmp-1)+1);
		F.resize(len);G.resize(len);
		F.dft(1);G.dft(1);
		for(int i=0;i<siz(F);i++)F[i]*=G[i];
		F.dft(-1);
		mint ziv=mint(siz(F)).inv();
		for(int i=0;i<siz(F);i++)F[i]*=ziv;
		F.resize(tmp);
		return F;
	}
	poly&operator*=(const poly&f){return(*this)=(*this)*f;}
	friend poly operator+(const poly&x,const poly&y){
		poly z=x;
		z.resize(max(siz(x),siz(y)));
		for(int i=0;i<siz(y);i++)z[i]+=y[i];
		return z;
	}
	friend poly operator-(const poly&x,const poly&y){
		poly z=x;
		z.resize(max(siz(x),siz(y)));
		for(int i=0;i<siz(y);i++)z[i]-=y[i];
		return z;
	}
	poly&operator+=(const poly&t){return (*this)=(*this)+t;}
	friend poly operator*(poly x,mint y){
		for(int i=0;i<siz(x);i++)x[i]*=y;
		return x;
	}
	friend poly operator*(mint y,poly x){
		for(int i=0;i<siz(x);i++)x[i]*=y;
		return x;
	}
};
constexpr int N=1e6+7;
int n,k;
poly F[N];
poly times(const poly&x,const poly&y){
	poly z(siz(x)+siz(y)-1);
	for(int i=0;i<siz(x);i++)for(int j=0;j<siz(y);j++)
		z[i+j]+=x[i]*y[j];
	return z;
}
poly solve(int l,int r){
	// if(l==r)return F[l];
	if(r-l<=50){
		poly tmp=F[l];
		for(int i=l+1;i<=r;i++)
			tmp=times(tmp,F[i]);
		return tmp;
	}
	int mid=(l+r)/2;
	poly tmp=solve(l,mid)*solve(mid+1,r);
	if(siz(tmp)>n-k)tmp.resize(n-k);
	return tmp;
}
signed main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ios::sync_with_stdio(false);cin.tie(nullptr);
	int T;cin>>T;while(T--){
		cin>>n>>k;
		for(int i=0;i<=n-2;i++)
			F[i].assign({1,i,1});
		poly G=solve(0,n-2);
		mint ans=0;
		for(int i=0;i<n-k;i++)
			ans+=G[i];
		cout<<ans<<'\n';
	}
	// cerr<<clock();
	return 0;
}