题面
有一张圆形的餐桌,这张餐桌有 2 n 2n 2n 个座位。现在有 n n n 对夫妻就坐,要求男士和女士隔位就坐,并且每对夫妻不能相邻,求安排座位的方案数。
答案可能很大,请对 998244353 \rm 998244353 998244353 取模。
3 ≤ n ≤ 1 e 5 3\leq n\leq 1e5 3≤n≤1e5.
样例输入
3
样例输出
2
样例解释
对于 3 3 3 对夫妻就坐的情况,安排座位的方案如下图所示:
题解
我们先强制把某个女士认为是序列头,然后拆环成链,只需要把最终答案数除以 n n n 就行。
我们想想,毫无限制的座位安排有多少种? ( n ! ) 2 (n!)^2 (n!)2 ,分别任意安排男士和女士。
然后,我们来容斥。我们把每对夫妻坐一起看作是一个条件,那么先打出“板子”:
∑
i
=
0
n
(
−
1
)
i
.
.
.
\sum_{i=0}^{n}(-1)^i...
i=0∑n(−1)i...
右边表示限定某 i \tt i i 个条件满足的方案数,注意不是“有” i i i 个条件,因为这样办不到。
对于每个
i
i
i ,我们首先得选出这么
i
i
i 对夫妻,然后他们之间有相对顺序,用阶乘:
∑
i
=
0
n
(
−
1
)
i
⋅
i
!
⋅
C
(
n
,
i
)
.
.
.
\sum_{i=0}^n(-1)^i\cdot i!\cdot C(n,i)...
i=0∑n(−1)i⋅i!⋅C(n,i)...
难点来了,把这 i i i 对夫妻安排在这个圆上,有两种情况:
# ♂♀ ### ♀♂ ##...##
:没有夫妻跨越首尾,那么就相当于在序列上选择 i i i 段长度为 2 2 2 的不相交子串,我们把序列长度减去 i i i ,又等价于在序列中朴素地选 i i i 个位置了,因此方案数为 C ( 2 n − i , i ) C(2n-i,i) C(2n−i,i) 。♀ #### ♂♀ ###...# ♂
:有一对夫妻在首尾相邻,我们把他们从首尾去除掉,那么就变成了长度减 2 2 2 、总夫妻数为 i − 1 i-1 i−1 的上面那个问题了,方案数为 C ( 2 n − i − 1 , i − 1 ) C(2n-i-1,i-1) C(2n−i−1,i−1) 。
因此,把这两者相加:
∑
i
=
0
n
(
−
1
)
i
⋅
i
!
⋅
C
(
n
,
i
)
⋅
(
C
(
2
n
−
i
,
i
)
+
C
(
2
n
−
i
−
1
,
i
−
1
)
)
.
.
.
\sum_{i=0}^n(-1)^i\cdot i!\cdot C(n,i)\cdot\Big( C(2n-i,i)+C(2n-i-1,i-1) \Big)...
i=0∑n(−1)i⋅i!⋅C(n,i)⋅(C(2n−i,i)+C(2n−i−1,i−1))...
剩下的没被选的男士女士们分别随便排,答案就是:
∑
i
=
0
n
(
−
1
)
i
⋅
i
!
⋅
C
(
n
,
i
)
⋅
(
C
(
2
n
−
i
,
i
)
+
C
(
2
n
−
i
−
1
,
i
−
1
)
)
⋅
(
(
n
−
i
)
!
)
2
\sum_{i=0}^n(-1)^i\cdot i!\cdot C(n,i)\cdot\Big( C(2n-i,i)+C(2n-i-1,i-1) \Big)\cdot \big((n-i)!\big)^2
i=0∑n(−1)i⋅i!⋅C(n,i)⋅(C(2n−i,i)+C(2n−i−1,i−1))⋅((n−i)!)2
最后别忘除以 n n n 。
预处理阶乘法求组合数,再枚举,时间复杂度 O ( n ) O(n) O(n) 。
CODE
#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<ctime>
#include<queue>
#include<vector>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define LL long long
#define DB double
#define ENDL putchar('\n')
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
LL read() {
LL f=1,x=0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f*x;
}
void putpos(LL x) {
if(!x) return ;
putpos(x/10); putchar('0'+(x%10));
}
void putnum(LL x) {
if(!x) putchar('0');
else if(x < 0) putchar('-'),putpos(-x);
else putpos(x);
}
const int MOD = 998244353;
int n,m,s,o,k;
int fac[MAXN<<2],inv[MAXN<<2],invf[MAXN<<2];
int C(int n,int m) {
if(m < 0 || m > n) return 0;
return fac[n] *1ll* invf[n-m] % MOD *1ll* invf[m] % MOD;
}
int main() {
n = read();
fac[0]=fac[1]=inv[0]=inv[1]=invf[0]=invf[1]=1;
for(int i = 2;i <= n*3;i ++) {
fac[i] = fac[i-1]*1ll*i % MOD;
inv[i] = (MOD-inv[MOD%i]) *1ll* (MOD/i) % MOD;
invf[i] = invf[i-1] *1ll* inv[i] % MOD;
}
int ans = 0;
for(int i = 0;i <= n;i ++) {
int as = (C(2*n-i,i)+C(2*n-1-i,i-1)) % MOD *1ll* C(n,i) % MOD *1ll* fac[i] % MOD *1ll* fac[n-i] % MOD *1ll* fac[n-i] % MOD;
(ans += ((i&1) ? (MOD-1):1) *1ll* as % MOD) %= MOD;
}
ans = ans *1ll* inv[n] % MOD;
printf("%d\n",ans);
return 0;
}