[数据丢失]围坐问题 Menage数

原博客地址

壹、题目描述 ¶

见 BZOJ P30181 Seat.

题目

有一张圆形的餐桌,这张餐桌有 2 n 2n 2n 个座位。现在有 n n n 对夫妻就坐,要求男士和女士隔位就坐,并且每对夫妻不能相邻,求安排座位的方案数,答案对 998244353 998244353 998244353 取模。

数据范围与提示

保证 3 ≤ n ≤ 1 0 5 3\le n\le 10^5 3n105,没有任何提示 😃

注意,由于是一个圆形的餐桌,所以经过旋转变换得到的坐法相同则认为是同一种方案。

贰、题解 ¶

我们首先可以考虑将女士安置好,不难发现 n n n 个女士构成圆排列,方案数为 ( n − 1 ) ! (n-1)! (n1)!,接下来考虑男士的坐法。

但是似乎不同的女士的坐法,会影响男士的可行坐法方案数?事实上,并非如此,考察下列问题:


有一个数列,共有 n n n 位,现要将 1 , 2 , 3 , ⋯ n 1,2,3,\cdots n 1,2,3,n 放入这 n n n 位中,对于每个位置有个要求,必须保证 a i ≠ p i a_i\neq p_i ai=pi,且 p i p_i pi 两两不同,求方案数?

不难发现,该问题的方案数即 D ( n ) D(n) D(n),由于每一位都是独立的,我们可以考虑将 p i = 1 p_i=1 pi=1 i i i 放到第一位,将 p j = 2 p_j=2 pj=2 j j j 放到第二位…然后问题即变为:在 n n n 个位置上放数,必须有 a i ≠ i a_i\neq i ai=i,这就是经典错排模板。故而,即使这个 p p p 怎么变,在方案数上,总是与最经典的错排问题方案数是相同的。


该问题也是同样的,无论女士怎样坐,男士落座的方案数都与 “第一个女士坐第一位,第二个女士坐第二位…” 的方案数相同,因此我们将这个问题进行了简化,我们可以不用在意女士具体应当是怎样坐,我们只将他们当成最简单的情形(上述)。接下来考虑在该情形下男士落座的方案。

由于第 i i i 个女士左右都不能放第 i i i 个男士,又因为我们已经将情形简化,故而此时,我们可以认为第 i i i 个女士的右边不能坐第 i i i 个或者第 ( i + 1 )   m o d   n (i+1)\bmod n (i+1)modn 个男士(如果它右边坐第 ( i + 1 )   m o d   n (i+1)\bmod n (i+1)modn 个男士,就相当于下一个女士(第 ( i + 1 )   m o d   n (i+1)\bmod n (i+1)modn 的女士)的左边坐了第 ( i + 1 )   m o d   n (i+1)\bmod n (i+1)modn 个男士,这是不合法的),我们考虑设 p i p_i pi 表示第 i i i 个女士的右边坐下了第 i i i ( i + 1 )   m o d   n (i+1)\bmod n (i+1)modn 个男士,接下来我们想要求的就是
∣ U ∣ − ∣ ∪ i = 1 n p i ∣ |U|-\left|{\huge\cup}_{i=1}^np_i\right| Ui=1npi
有了该式子,我们不难往容斥方向想,考虑枚举有多少个女士满足了自己的 p i p_i pi 性质,那么可以得到下列式子:
A n s ′ = ∑ k = 0 n ( − 1 ) k F ( k ) Ans'=\sum_{k=0}^n(-1)^kF(k) Ans=k=0n(1)kF(k)
关于这个 F ( k ) F(k) F(k) 应该如何选择?考虑这个 F ( k ) F(k) F(k) 的组合意义:有 k k k 个女士满足自身 p i p_i pi 性质,剩下的 n − k n-k nk 个女士右边随便坐的方案数。

后者即为 ( n − k ) ! (n-k)! (nk)!,这很好办,但是前者?我们不妨将所有女士想要满足自己 p i p_i pi 性质的男士编号写成一排(同一个女士的限制写在一个括号中),那么可以得到:
( 12 ) ( 23 ) ( 34 ) ( 45 ) ⋯ ( ( n − 1 ) n ) ( n 1 ) (12)(23)(34)(45)\cdots {\large(}(n-1)n{\large)}(n1) (12)(23)(34)(45)((n1)n)(n1)
对于这个序列,我们要选出 k k k 个数,要求有:

  • 同一个数不能被选择两次(相当于一个男士同时坐在两个女士右边请务必让我来承受这般酷刑);
  • 不能同时选择同一个括号中的两个数,这相当于一个女士右边坐了两个男士(?);

如果我们将括号撇去不看,还是上面俩限制,那么,这就相当于:从围成一圈(因为头尾都是 1 1 1)的 2 n 2n 2n 个球中选出 k k k不相邻的球的方案数,共 2 n 2n 2n 个球,故方案数即为 2 n 2 n − k ( 2 n − k k ) {2n\over 2n-k}{2n-k\choose k} 2nk2n(k2nk),所以容斥式子即为:
A n s ′ = ∑ k = 0 n ( − 1 ) k 2 n 2 n − k ( 2 n − k k ) ( n − k ) ! Ans'=\sum_{k=0}^n(-1)^k{2n\over 2n-k}{2n-k\choose k}(n-k)! Ans=k=0n(1)k2nk2n(k2nk)(nk)!
该式子得到的数又被称为 M e n a g e \rm Menage Menage 数。

最后的答案 A n s = ( n − 1 ) ! × A n s ′ Ans=(n-1)!\times Ans' Ans=(n1)!×Ans,因为我们从始至终都将女士坐法当成 1 , 2 , 3 , 4 , ⋯ 1,2,3,4,\cdots 1,2,3,4, 来看,但是女士坐法也是可以变化的。


组合式 2 n 2 n − k ( 2 n − k k ) {2n\over 2n-k}{2n-k\choose k} 2nk2n(k2nk) 是怎么得到的?

我们先考虑一个简单的情形 —— 从一排(并非一个圈) n n n 个球中选出 k k k 个互不相邻的出来,方案数?

分两种情况讨论:

  • n < 2 k − 1 n<2k-1 n<2k1 时,无合法方案;
  • n ≥ 2 k − 1 n\ge 2k-1 n2k1 时,我们可以考虑拿出 k − 1 k-1 k1 个球当成 k k k 个球的强制隔板,然后我们从剩下 n − k + 1 n-k+1 nk+1 个球中随便选 k k k 个出来就行了,不难发现方案数就是 ( n − k + 1 k ) {n-k+1\choose k} (knk+1),由于所有球都是相同的,

接下来,我们分析 n n n 个球围成一个圈的问题:

  • n < 2 k n<2k n<2k 时,无合法方案;
  • n ≥ 2 k n\ge 2k n2k 时,考虑破环成链 —— 选择 1 1 1 号球与不选 1 1 1 号球;
    • 如果选择了第 1 1 1 个球,那么就相当于从 3 ∼ n − 1 3\sim n-1 3n1 中选出 k − 1 k-1 k1 个不相邻的球,套用上文结论,方案数 ( n − k − 1 k − 1 ) {n-k-1\choose k-1} (k1nk1)
    • 如果没选择第 1 1 1 个球,相当于从 2 ∼ n 2\sim n 2n 中选出 k k k 个不相邻的球,方案数 ( n − k k ) {n-k\choose k} (knk)

总方案数即为
( n − k − 1 k − 1 ) + ( n − k k ) = n ( n − k k ) n − k {n-k-1\choose k-1}+{n-k\choose k}={n{n-k\choose k}\over n-k} (k1nk1)+(knk)=nkn(knk)
这就得到上文的式子。

残留问题:

k k k 阶错排怎么搞?

预备知识:棋盘多项式等…


总时间复杂度 O (    n log ⁡   m o d   ) \mathcal O(\;n\log \bmod) O(nlogmod),由于使用了费马小定理求逆元。但是应该可以不用。

叁、参考代码 ¶

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;
}

肆、关键之处 ¶

在恰当的地方对问题进行简化,或者将比较复杂的情形与一般情形建立关系。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函、指针等。在编写C程序时,需要注意变量的声明和定义、指针的使用、内存的分配与释放等问题。C语言中常用的数据结构包括: 1. 组:一种存储同类型数据的结构,可以进行索引访问和修改。 2. 链表:一种存储不同类型数据的结构,每个节点包含数据和指向下一个节点的指针。 3. 栈:一种后进先出(LIFO)的数据结构,可以通过压入(push)和弹出(pop)操作进行数据的存储和取出。 4. 队列:一种先进先出(FIFO)的数据结构,可以通过入队(enqueue)和出队(dequeue)操作进行数据的存储和取出。 5. 树:一种存储具有父子关系的数据结构,可以通过中序遍历、前序遍历和后序遍历等方式进行数据的访问和修改。 6. 图:一种存储具有节点和边关系的数据结构,可以通过广度优先搜索、深度优先搜索等方式进行数据的访问和修改。 这些数据结构在C语言中都有相应的实现方式,可以应用于各种不同的场景。C语言中的各种数据结构都有其优缺点,下面列举一些常见的数据结构的优缺点: 组: 优点:访问和修改元素的速度非常快,适用于需要频繁读取和修改数据的场合。 缺点:组的长度是固定的,不适合存储大小不固定的动态数据,另外组在内存中是连续分配的,当组较大时可能会导致内存碎片化。 链表: 优点:可以方便地插入和删除元素,适用于需要频繁插入和删除数据的场合。 缺点:访问和修改元素的速度相对较慢,因为需要遍历链表找到指定的节点。 栈: 优点:后进先出(LIFO)的特性使得栈在处理递归和括号匹配等问题时非常方便。 缺点:栈的空间有限,当数据量较大时可能会导致栈溢出。 队列: 优点:先进先出(FIFO)的特性使得
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值