火题小战 C. 情侣?给我烧了!

火题小战 C. 情侣?给我烧了!

题目描述

(n) 对情侣来到电影院观看电影。在电影院,恰好留有 (n) 排座位,每排包含 (2) 个座位,共 (2×n) 个座位。

现在,每个人将会随机坐在某一个位置上,且恰好将这 (2 × n) 个座位坐满。

如果一对情侣坐在了同一排的座位上,那么我们称这对情侣是和睦的。

你的任务是求出共有多少种不同的就坐方案满足恰好有 (k) 对情侣是和睦的。

两种就坐方案不同当且仅当存在一个人在两种方案中坐在了不同的位置。不难发现,一共会有 ((2n)!) 种不同的就坐方案。

由于结果可能较大,因此输出对 (998244353) 取模的结果。

输入格式

输入包含多组数据。

输入的第 (1) 行包含 (1) 个正整数 (T),表示数据的组数。

接下来 (T) 行,每行包含 (2) 个正整数 (n,k)

输出格式

输出共 (T) 行。

对于每组输入数据,输出共 (1) 行,包含 (1) 个整数,表示恰好有 (k)对情侣和睦的就坐方案数。

输入输出样例

输入 #1

5
1 1
2 0
2 2
2333 666
2333333 1000000

输出 #1

2
16
8
798775522
300377435

说明/提示

对于 (10 \%) 的数据,满足 (1 leq T leq 10, 1 leq n leq 5)

对于 (40 \%) 的数据,满足 (1 leq n leq 3 imes 10^3)

对于 (100 \%) 的数据,满足 (1 leq T leq 2 imes 10^5, 1 leq n leq 5 imes 10^6)

分析

我们设 (f[x]) 为恰好有 (x) 对情侣都错开的方案数

我们考虑如何把其分解为子问题

首先我们可以从这 (2x) 个人中随意选取一个人

接下来我们再选取一个不能与他配对的人

总的方案数为 (2x(2x-2))

对于我们选出的这两个人的配偶,如果我们把他们也强制配对的话那么这相当于一个规模为 (x-2) 的子问题,同时我们还要乘上 (x-1) 代表在剩下的 (x-1) 行中选出一行给他们坐,他们还可以交换位置,所以还要乘 (2)

如果我们不给他们强制配对的话,那么这就是一个规模为 (x-1) 的子问题

初始化 (f[0]=1, f[1]=0)

转移方程 (f[x]=2x(2x-2)(f[x-1]+2(x-1)f[x-2]))

我们考虑了恰好有 (k) 对情侣错开的的情况,下面要考虑本题的求解,即恰好有 (k)对情侣和睦的就坐方案数

首先我们要在 (n) 对情侣中选出 (k) 对情侣和睦,还要在 (n) 排座位中选出 (k) 排让他们坐,每对情侣在这 (k) 排可以随便坐,情侣两人也可以互换位置

因此最终的结果为

[C_n^k imes C_n^k imes k! imes 2^k imes f[n-k]%mod ]

代码

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
const int maxn=5e6+5;
int ny[maxn],jc[maxn],jcc[maxn],f[maxn];
long long ksm(int ds,int zs){
	long long ans=1;
	while(zs){
		if(zs&1) ans=ans*ds%mod;
		ds=(long long)ds*ds%mod;
		zs>>=1;
	}
	return ans%mod;
}
signed main(){
	ny[1]=1;
	for(int i=2;i<maxn;i++){
		ny[i]=((long long)mod-mod/i)*ny[mod%i]%mod;
	}
	jc[0]=1,jcc[0]=1;
	for(int i=1;i<maxn;i++){
		jc[i]=(long long)jc[i-1]*i%mod;
		jcc[i]=(long long)jcc[i-1]*ny[i]%mod;
	}
	f[0]=1,f[1]=0;
	for(int i=2;i<maxn;i++){
		f[i]=(long long)2*i*(2*i-2)%mod*((long long)f[i-1]%mod+(long long)(2*i-2)*f[i-2]%mod)%mod;
	}
	int t;
	scanf("%d",&t);
	while(t--){
		int n,k;
		scanf("%d%d",&n,&k);
		long long ans=(long long)jc[n]*jcc[k]%mod*jcc[n-k]%mod*jc[n]%mod*jcc[n-k]%mod*ksm(2,k)%mod*f[n-k]%mod;
		printf("%lld
",ans%mod);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/liuchanglc/p/13497877.html