传送门
顺便把弱化版一起切了:P4921
解析:
这种数数问题还是考虑分部分计算。
一,匹配的k对
这部分很简单,选出
k
k
k个位置上火刑柱
(
n
k
)
n\choose k
(kn),选出
k
k
k对送到FFF大本营
(
n
k
)
n\choose k
(kn),在
k
k
k个位置里面选择
k
!
k!
k!,每一对两个人位置可以互换
2
k
2^k
2k。
所以这一部分的计算就是 ( n k ) 2 k ! 2 k {n\choose k}^2k!2^k (kn)2k!2k
二,不能匹配的n-k对
显然现在剩下的位置确定了,剩下的情侣也确定了。
也就是说,我们要求的就是 n − k n-k n−k对情侣全部错开的方案数。
设 d n d_n dn表示 n n n对情侣全部错开的方案数。
接下来有两种方法求出 { d } \{d\} {d}数列的递推式,我第一次做的时候用的是第二种方法。
(1)组合分析
在第一排的两个位置放两个不是情侣的人,显然方案数是 2 n ( 2 n − 2 ) 2n(2n-2) 2n(2n−2)。
然后看这两个人的另一半,我们对这两个人的限制分情况讨论。
1.强制不坐在一起
那么相当于这两个人形成了新的情侣 (大自然的力量) ,直接从子问题
d
n
−
1
d_{n-1}
dn−1转移过来。
2.强制坐在一起
在剩下 n − 1 n-1 n−1排中任意选择一排,两人位置允许互换,子问题转化为 d n − 2 d_{n-2} dn−2
综上,我们得到递推式: d n = 4 n ( n − 1 ) ( d n − 1 + 2 ( n − 1 ) d n − 2 ) d_n=4n(n-1)(d_{n-1}+2(n-1)d_{n-2}) dn=4n(n−1)(dn−1+2(n−1)dn−2)
(2)生成函数分析
这种方法较为复杂,建议数学(微积分)基础较好再来尝试。
考虑配对对数为 [ 0 , n ] [0,n] [0,n]的所有情况可以得到一个组合恒等式: ∑ k = 0 n ( n k ) 2 k ! 2 k d n − k = ( 2 n ) ! \sum_{k=0}^n{n\choose k}^2k!2^kd_{n-k}=(2n)! k=0∑n(kn)2k!2kdn−k=(2n)!
开始化简:
∑
k
=
0
n
(
n
k
)
2
k
!
2
k
d
n
−
k
=
(
2
n
)
!
∑
k
=
0
n
2
k
d
n
−
k
k
!
(
n
−
k
)
!
2
=
(
2
n
)
!
n
!
2
\begin{aligned} \sum_{k=0}^n{n\choose k}^2k!2^kd_{n-k}&=&&(2n)!\\ \sum_{k=0}^n\frac{2^kd_{n-k}}{k!(n-k)!^2}&=&&\frac{(2n)!}{n!^2} \end{aligned}
k=0∑n(kn)2k!2kdn−kk=0∑nk!(n−k)!22kdn−k==(2n)!n!2(2n)!
好像是一个卷积的形式,两边进行 ∑ n = 0 ∞ \sum\limits_{n=0}^{\infty} n=0∑∞的求和,强行转化成EGF。
( ∑ n = 0 ∞ 2 n n ! x n ) ( ∑ n = 0 ∞ d n n ! 2 x n ) = ∑ n = 0 ∞ ( 2 n ) ! n ! 2 x n \begin{aligned} (\sum_{n=0}^{\infty}\frac{2^n}{n!}x^n)(\sum_{n=0}^{\infty}\frac{d_n}{n!^2}x^n)=\sum_{n=0}^{\infty}\frac{(2n)!}{n!^2}x^n \end{aligned} (n=0∑∞n!2nxn)(n=0∑∞n!2dnxn)=n=0∑∞n!2(2n)!xn
根据泰勒展开,我们可以知道
∑
n
=
0
∞
(
2
n
)
!
n
!
2
x
n
=
(
1
−
4
x
)
−
1
2
\sum_{n=0}^{\infty}\frac{(2n)!}{n!^2}x^n=(1-4x)^{-\frac{1}2}
n=0∑∞n!2(2n)!xn=(1−4x)−21
∑
n
=
0
∞
2
n
n
!
x
n
=
e
2
x
\sum_{n=0}^{\infty}\frac{2^n}{n!}x^n=e^{2x}
n=0∑∞n!2nxn=e2x
令 D ( x ) = ∑ n = 0 ∞ d n n ! 2 x n D(x)=\sum\limits_{n=0}^{\infty}\frac{d_n}{n!^2}x^n D(x)=n=0∑∞n!2dnxn,则有
D ( x ) = e − 2 x 1 − 4 x D(x)=\frac{e^{-2x}}{\sqrt{1-4x}} D(x)=1−4xe−2x
当然如果你硬是要算通项公式的话,直接用 e − 2 x e^{-2x} e−2x展开形式和 ∑ n = 0 ∞ ( 2 n ) ! n ! x n \sum_{n=0}^{\infty}\frac{(2n)!}{n!}x^n ∑n=0∞n!(2n)!xn做卷积可以得到
d n = ∑ k = 0 n ( n k ) 2 ( − 2 ) k k ! ( 2 n − 2 k ) ! d_n=\sum_{k=0}^n{n\choose k}^2(-2)^kk!(2n-2k)! dn=k=0∑n(kn)2(−2)kk!(2n−2k)!
发现又是一个卷积,可以用 F F T O ( n log n ) FFTO(n\log n) FFTO(nlogn)做了,但是 5 e 6 5e6 5e6就不要想了。。。
对
D
(
x
)
D(x)
D(x)求导得到
D
′
(
x
)
=
8
x
⋅
e
−
2
x
(
1
−
4
x
)
3
2
=
8
x
1
−
4
x
D
(
x
)
D^\prime(x)=\frac{8x\cdot e^{-2x}}{(1-4x)^{\frac{3}2}}=\frac{8x}{1-4x}D(x)
D′(x)=(1−4x)238x⋅e−2x=1−4x8xD(x)
(
1
−
4
x
)
D
′
(
x
)
=
8
x
D
(
x
)
(1-4x)D^\prime(x)=8xD(x)
(1−4x)D′(x)=8xD(x)
对应项还原系数可以得到:
d n = 4 n ( n − 1 ) ( d n − 1 + 2 ( n − 1 ) d n − 2 ) d_n=4n(n-1)(d_{n-1}+2(n-1)d_{n-2}) dn=4n(n−1)(dn−1+2(n−1)dn−2)
总算写完了
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
cs int mod=998244353;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a<b?a-b+mod:a-b;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline int sqr(int a){return (ll)a*a%mod;}
template<class ...Args>
inline int mul(int a,Args ...args){
return mul(a,mul(args...));
}
cs int N=5e6+6;
int fac[N],inv[N],ifac[N],pow2[N];
int d[N];
inline int C(int n,int m){
return mul(fac[n],mul(ifac[m],ifac[n-m]));
}
int T,n,k;
signed main(){
fac[0]=fac[1]=ifac[0]=ifac[1]=inv[0]=inv[1]=pow2[0]=d[0]=1;pow2[1]=2;
for(int re i=2;i<N;++i){
fac[i]=mul(fac[i-1],i);
inv[i]=mul(inv[mod%i],mod-mod/i);
ifac[i]=mul(ifac[i-1],inv[i]);
pow2[i]=add(pow2[i-1],pow2[i-1]);
d[i]=mul(4,i,i-1,add(d[i-1],mul(2,i-1,d[i-2])));
}
std::ios::sync_with_stdio(false);
T=getint();
while(T--){
n=getint(),k=getint();
std::cout<<mul(sqr(C(n,k)),fac[k],pow2[k],d[n-k])<<"\n";
}
return 0;
}