[数据丢失]围坐问题 Menage数
壹、题目描述 ¶
见 BZOJ P30181 Seat.
题目
有一张圆形的餐桌,这张餐桌有 \(2n\) 个座位。现在有 \(n\) 对夫妻就坐,要求男士和女士隔位就坐,并且每对夫妻不能相邻,求安排座位的方案数,答案对 \(998244353\) 取模。
数据范围与提示
保证 \(3\le n\le 10^5\),没有任何提示 😃
注意,由于是一个圆形的餐桌,所以经过旋转变换得到的坐法相同则认为是同一种方案。
贰、题解 ¶
我们首先可以考虑将女士安置好,不难发现 \(n\) 个女士构成圆排列,方案数为 \((n-1)!\),接下来考虑男士的坐法。
但是似乎不同的女士的坐法,会影响男士的可行坐法方案数?事实上,并非如此,考察下列问题:
有一个数列,共有 \(n\) 位,现要将 \(1,2,3,\cdots n\) 放入这 \(n\) 位中,对于每个位置有个要求,必须保证 \(a_i\neq p_i\),且 \(p_i\) 两两不同,求方案数?
不难发现,该问题的方案数即 \(D(n)\),由于每一位都是独立的,我们可以考虑将 \(p_i=1\) 的 \(i\) 放到第一位,将 \(p_j=2\) 的 \(j\) 放到第二位......然后问题即变为:在 \(n\) 个位置上放数,必须有 \(a_i\neq i\),这就是经典错排模板。故而,即使这个 \(p\) 怎么变,在方案数上,总是与最经典的错排问题方案数是相同的。
该问题也是同样的,无论女士怎样坐,男士落座的方案数都与 “第一个女士坐第一位,第二个女士坐第二位......” 的方案数相同,因此我们将这个问题进行了简化,我们可以不用在意女士具体应当是怎样坐,我们只将他们当成最简单的情形(上述)。接下来考虑在该情形下男士落座的方案。
由于第 \(i\) 个女士左右都不能放第 \(i\) 个男士,又因为我们已经将情形简化,故而此时,我们可以认为第 \(i\) 个女士的右边不能坐第 \(i\) 个或者第 \((i+1)\bmod n\) 个男士(如果它右边坐第 \((i+1)\bmod n\) 个男士,就相当于下一个女士(第 \((i+1)\bmod n\) 的女士)的左边坐了第 \((i+1)\bmod n\) 个男士,这是不合法的),我们考虑设 \(p_i\) 表示第 \(i\) 个女士的右边坐下了第 \(i\) 或 \((i+1)\bmod n\) 个男士,接下来我们想要求的就是
有了该式子,我们不难往容斥方向想,考虑枚举有多少个女士满足了自己的 \(p_i\) 性质,那么可以得到下列式子:
关于这个 \(F(k)\) 应该如何选择?考虑这个 \(F(k)\) 的组合意义:有 \(k\) 个女士满足自身 \(p_i\) 性质,剩下的 \(n-k\) 个女士右边随便坐的方案数。
后者即为 \((n-k)!\),这很好办,但是前者?我们不妨将所有女士想要满足自己 \(p_i\) 性质的男士编号写成一排(同一个女士的限制写在一个括号中),那么可以得到:
对于这个序列,我们要选出 \(k\) 个数,要求有:
- 同一个数不能被选择两次(相当于一个男士同时坐在两个女士右边
请务必让我来承受这般酷刑); - 不能同时选择同一个括号中的两个数,这相当于一个女士右边坐了两个男士(?);
如果我们将括号撇去不看,还是上面俩限制,那么,这就相当于:从围成一圈(因为头尾都是 \(1\))的 \(2n\) 个球中选出 \(k\) 个不相邻的球的方案数,共 \(2n\) 个球,故方案数即为 \({2n\over 2n-k}{2n-k\choose k}\),所以容斥式子即为:
该式子得到的数又被称为 \(\rm Menage\) 数。
最后的答案 \(Ans=(n-1)!\times Ans'\),因为我们从始至终都将女士坐法当成 \(1,2,3,4,\cdots\) 来看,但是女士坐法也是可以变化的。
组合式 \({2n\over 2n-k}{2n-k\choose k}\) 是怎么得到的?
我们先考虑一个简单的情形 —— 从一排(并非一个圈)\(n\) 个球中选出 \(k\) 个互不相邻的出来,方案数?
分两种情况讨论:
- 当 \(n<2k-1\) 时,无合法方案;
- 当 \(n\ge 2k-1\) 时,我们可以考虑拿出 \(k-1\) 个球当成 \(k\) 个球的强制隔板,然后我们从剩下 \(n-k+1\) 个球中随便选 \(k\) 个出来就行了,不难发现方案数就是 \({n-k+1\choose k}\),由于所有球都是相同的,
接下来,我们分析 \(n\) 个球围成一个圈的问题:
- 当 \(n<2k\) 时,无合法方案;
- 当 \(n\ge 2k\) 时,考虑破环成链 —— 选择 \(1\) 号球与不选 \(1\) 号球;
-
- 如果选择了第 \(1\) 个球,那么就相当于从 \(3\sim n-1\) 中选出 \(k-1\) 个不相邻的球,套用上文结论,方案数 \({n-k-1\choose k-1}\);
- 如果没选择第 \(1\) 个球,相当于从 \(2\sim n\) 中选出 \(k\) 个不相邻的球,方案数 \({n-k\choose k}\);
总方案数即为
这就得到上文的式子。
残留问题:
\(k\) 阶错排怎么搞?
预备知识:棋盘多项式等......
总时间复杂度 \(\mathcal O(\;n\log \bmod)\),由于使用了费马小定理求逆元。但是应该可以不用。
叁、参考代码 ¶
const int maxn=2e5;
const int mod=998244353;
inline int qkpow(int a, int n){
int ret=1;
for(; n>0; n>>=1, a=1ll*a*a%mod)
if(n&1) ret=1ll*ret*a%mod;
return ret;
}
int fac[maxn+5], finv[maxn+5];
inline void prelude(){
finv[0]=fac[0]=1;
rep(i, 1, maxn) fac[i]=1ll*fac[i-1]*i%mod;
finv[maxn]=qkpow(fac[maxn], mod-2);
drep(i, maxn-1, 1) finv[i]=1ll*finv[i+1]*(i+1)%mod;
}
inline int C(int n, int m){
if(n<m || n<0 || m<0) return 0;
return 1ll*fac[n]*finv[m]%mod*finv[n-m]%mod;
}
int n;
#define sign(i) (((i)&1)? -1: 1)
signed main(){
prelude(); n=readin(1);
int ans=0;
rep(k, 0, n)
ans=(ans+1ll*sign(k)*2*n*qkpow(2*n-k, mod-2)%mod*C(2*n-k, k)%mod*fac[n-k]%mod)%mod;
ans=(ans+mod)%mod;
writc(1ll*ans*fac[n-1]%mod);
return 0;
}
肆、关键之处 ¶
在恰当的地方对问题进行简化,或者将比较复杂的情形与一般情形建立关系。