不会生成函数 /yun
弱化版直接二项式反演乱搞做差卷积就好了。
考虑 \(f[i]\) 为至少 \(i\) 对情侣坐一起的方案数,显然 \(f[i]=\binom{n}{i}\binom{n}{i}i!2^i*(2n-2i)!\),即钦定 \(i\) 对情侣,\(i\) 排座位,情侣座位选择可以全排列,每对情侣可以选择是否交换座位,剩下的随便坐。
\(g[i]\) 为恰好 \(i\) 对情侣坐一起。
\[f[i]=\sum_{j=i}^n\binom{j}{i}g[j] \] \[g[j]=\sum_{j=i}^n(-1)^{j-i}\binom{j}{i}f[j] \]套路化一下发现可以 NTT 优化。
强化版考虑正难则反,能不能搞出 \(i\) 对情侣错排情况数?能的话就好做了。只要钦定 \(k\) 对情侣坐一起,剩下的错排开就好了。
设 \(g[i]\) 为只有 \(i\) 对情侣且每对情侣都错排开的情况数。\(g[0]=1,g[1]=0\)。
\[g[i]=2i(2i-2)(g[i-1]+2(i-1)g[i-2]) \]因为是递推,所以可以不考虑各排的排列,因为每次新加入的人的不同已经等价于了。
或者说,你可以认为每次进来的人都去第一排,那么每次进来的人可能不一样,所以各排间的全排列不需要。
随便选 2 个不是情侣的人,然后要不要选他们的情侣,那我们当前问题的规模就减小 1。假如选他们的情侣,那么规模减小 2,再选他们的情侣所在的排。
事实上这种组合意义这么 nb 的我在考场上也应该想不到,倒是弱化版挺一眼的。
#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
int rd() {
int f=1,sum=0; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
#define N 2005
#define M (int)(4e5+5)
const int mod=998244353,G=3;
int fpow(int x,int y) {
int res=1;
while(y) {
if(y&1) res=res*x%mod;
y>>=1; x=x*x%mod;
}
return res;
}
const int invG=fpow(G,mod-2);
void NTT(int *f,int n,bool fl=1) {
static int tr[M];
for(int i=0;i<n;i++) tr[i]=(tr[i>>1]>>1)|((i&1)?(n>>1):0);
for(int i=0;i<n;i++) if(i<tr[i]) swap(f[i],f[tr[i]]);
for(int p=2;p<=n;p<<=1) {
int len=(p>>1),w=fpow(fl?G:invG,(mod-1)/p);
for(int l=0;l<n;l+=p) {
int buf=1;
for(int i=l;i<l+len;i++) {
int qwq=f[i+len]*buf%mod;
f[i+len]=(f[i]-qwq)%mod;
f[i]=(f[i]+qwq)%mod;
buf=buf*w%mod;
}
}
}
if(fl) return ;
int qwq=fpow(n,mod-2);
for(int i=0;i<n;i++) f[i]=f[i]*qwq%mod;
}
int f[M],g[M],jie[N],djie[N],n;
int C(int n,int m) {
if(m>n||n<0||m<0) return 0;
return jie[n]*djie[m]%mod*djie[n-m]%mod;
}
void solve() {
memset(f,0,sizeof(f)); memset(g,0,sizeof(g));
n=rd(); f[0]=jie[2*n];
for(int i=1;i<=n;i++) f[i]=C(n,i)*C(n,i)%mod*jie[i]%mod*fpow(2,i)%mod*jie[2*n-2*i]%mod;
// 太屑了 不放 n^3 ,你玩nmd,是个紫就要 NTT 做差卷积??
// 老子今天都不知道写几遍 NTT 了
for(int i=0;i<=n;i++) f[i]=jie[i]*f[i]%mod;
for(int i=0;i<=n;i++) g[i]=((i&1)?-1:1)*djie[i]%mod;
reverse(f,f+1+n);
int m; for(m=1;m<n+n+2;m<<=1);
NTT(f,m,1); NTT(g,m,1);
for(int i=0;i<m;i++) f[i]=f[i]*g[i]%mod;
NTT(f,m,0);
reverse(f,f+1+n);
for(int i=0;i<=n;i++) {
int qwq=f[i]*djie[i]%mod;
qwq=(qwq%mod+mod)%mod;
printf("%lld\n",qwq);
}
}
signed main() {
jie[0]=1;
for(int i=1;i<=N-5;i++) jie[i]=jie[i-1]*i%mod;
djie[N-5]=fpow(jie[N-5],mod-2);
for(int i=N-5;i;i--) djie[i-1]=djie[i]*i%mod;
int T=rd();
while(T--) solve();
return 0;
}
#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
int rd() {
int f=1,sum=0; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
#define N (int)(5e6+5)
const int mod=998244353;
int g[N],jie[N],djie[N];
int fpow(int x,int y) {
int res=1; x%=mod;
while(y) {
if(y&1) res=res*x%mod;
y>>=1; x=x*x%mod;
}
return res;
}
int C(int n,int m) {
return jie[n]*djie[m]%mod*djie[n-m]%mod;
}
void solve() {
int n,k,ans=0;
cin>>n>>k;
ans=C(n,k)*C(n,k)%mod*jie[k]%mod*fpow(2,k)%mod*g[n-k]%mod;
ans=(ans%mod+mod)%mod;
cout<<ans<<'\n';
}
signed main() {
cin.tie(0);
ios::sync_with_stdio(false);
jie[0]=1; for(int i=1;i<=N-5;i++) jie[i]=jie[i-1]*i%mod;
djie[N-5]=fpow(jie[N-5],mod-2); for(int i=N-5;i;i--) djie[i-1]=djie[i]*i%mod;
g[0]=1; g[1]=0; // 按定义
for(int i=2;i<=N-5;i++) g[i]=2*i%mod*(2*i%mod-2)%mod*((g[i-1]+g[i-2]*(i-1)%mod*2%mod)%mod)%mod;
int T; cin>>T; while(T--) solve();
return 0;
}