P4921 [MtOI2018]情侣?给我烧了!

题目:

给定 n n n排座位,每排两个座位,现在有 n n n对情侣,当一对情侣并排坐着的时候,认为他们是和睦的,问对于 ∀ k ∈ [ 0 , n ] \forall k \in [0,n] k[0,n],问有 k k k对情侣和睦的方案数。当存在一个人在两种方案中的座位不一样时,认为两种方案是不同的。

( 1 ≤ n ≤ 1000 , T = 1000 ) (1 \le n \le 1000,T=1000) (1n1000,T=1000)

题解:

首先想到的是直接反演硬刚,但是存在 ( 2 n ) ! (2n)! (2n)!这样的东西,无法构成卷积。这里可以发现二项式反演的钦定法在对不存在某种情况的方案进行计数时比较有用。

f k f_k fk为恰好存在 k k k对情侣的方案数,那么 f k = ( n k ) ( n k ) k ! 2 k g n − k f_k=\dbinom{n}{k}\dbinom{n}{k}k!2^kg_{n-k} fk=(kn)(kn)k!2kgnk,其中 g n g_n gn n n n对情侣都不和睦的方案数,那么问题就变成了求 g n g_n gn,这个东西就可以用二项式反演了。令 A n , k A_{n,k} An,k n n n对情侣恰好 k k k对和睦的方案数, B n , k B_{n,k} Bn,k n n n对情侣钦定 k k k对和睦的方案数,那么有 B n , k = ∑ i = k n ( i k ) A n , i \displaystyle B_{n,k}=\sum_{i=k}^{n}\dbinom{i}{k}A_{n,i} Bn,k=i=kn(ki)An,i,二项式反演可得 A n , k = ∑ i = k n ( − 1 ) i − k ( i k ) B n , i \displaystyle A_{n,k}=\sum_{i=k}^{n}(-1)^{i-k}\dbinom{i}{k}B_{n,i} An,k=i=kn(1)ik(ki)Bn,i,那么 g n = A n , 0 = ∑ i = 0 n ( − 1 ) i B n , i \displaystyle g_n=A_{n,0}=\sum_{i=0}^{n}(-1)^iB_{n,i} gn=An,0=i=0n(1)iBn,i B n , k = ( n k ) 2 k ! 2 k ( 2 n − 2 k ) ! \displaystyle B_{n,k}=\dbinom{n}{k}^2k!2^k(2n-2k)! Bn,k=(kn)2k!2k(2n2k)!,代入得 g n = ∑ i = 0 n ( − 1 ) i ( n i ) 2 i ! 2 i ( 2 n − 2 i ) ! \displaystyle g_n=\sum_{i=0}^{n}(-1)^i\dbinom{n}{i}^2i!2^i(2n-2i)! gn=i=0n(1)i(in)2i!2i(2n2i)!。所以 O ( n 2 ) O(n^2) O(n2)预处理 g n g_n gn,对于每次询问 O ( n ) O(n) O(n)计算即可。

复杂度: O ( n 2 + T n ) O(n^2+Tn) O(n2+Tn)

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<bitset>
#include<sstream>
#include<ctime>
//#include<chrono>
//#include<random>
//#include<unordered_map>
using namespace std;

#define ll long long
#define ls o<<1
#define rs o<<1|1
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
const double pi=acos(-1.0);
const double eps=1e-6;
const int mod=998244353;
const int INF=0x3f3f3f3f;
const int maxn=2005;
ll read(){
	ll x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int T,n;
ll f[maxn],g[maxn],fac[maxn],ifac[maxn],p2[maxn];
ll qpow(ll a,ll p=mod-2){
	ll res=1;
	while(p){
		if(p&1)res=res*a%mod;
		a=a*a%mod;
		p>>=1;
	}
	return res;
}
void init(int n){
	fac[0]=1;
	for(int i=1;i<=2*n;i++)fac[i]=fac[i-1]*i%mod;
	ifac[2*n]=qpow(fac[2*n]);
	for(int i=2*n-1;i>=0;i--)ifac[i]=ifac[i+1]*(i+1)%mod;
	p2[0]=1;
	for(int i=1;i<=n;i++)p2[i]=p2[i-1]*2%mod;
}
ll C(int n,int m){
	return fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
void pre(int n){
	for(int i=0;i<=n;i++){
		for(int j=0;j<=i;j++){
			g[i]+=(j%2?mod-1:1)*C(i,j)%mod*C(i,j)%mod*fac[j]%mod*p2[j]%mod*fac[2*i-2*j]%mod;
			g[i]%=mod;
		}
	}
}
int main(void){
	// freopen("in.txt","r",stdin);
	init(1000);
	pre(1000);
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		for(int i=0;i<=n;i++){
			printf("%lld\n",C(n,i)*C(n,i)%mod*fac[i]%mod*p2[i]%mod*g[n-i]%mod);
		}
	}
	return 0;
}
已标记关键词 清除标记
相关推荐
众所周知 , Xplore作为手机上最强大的文件管理软件 , 想必大家都用过 。 这是最新的1.45版 、 已经破解 , 并且不会出现三秒和一定次数后无法使用的情况。 安好后会出现两个图标,一个X-plore原版,一个是X-PUNRG破解程序。 先打开X-PUNRG,然后您就可以使用X-plore原版了, 如果以后出现原版不能打开或者需要注册,重新运行下X-PUNRG就可以了。 新兵9527 N82 测试通过。 官方简体中文,MTOi完全破解。安装前请卸载掉旧版软件。 X-plore是目前为止最实用的文件管理器.简单易用的界面.强大的文件管理功能.独有的RAR.ZIP.Jar文件解压功能让你感受到智能手机的强大文件管理系统. 树形显示所有驱动器/文件夹/文件 整合了图像浏览器 可以查看文件的详情 可以编辑文件的属性,如:隐藏,只读等等 可以重命名和删除文件 可以创建和编辑文件 可以新建文件夹 支持同时选择多个文件或文件夹 可以通过红外或蓝牙发送文件 (小技巧:可以直接按拨号键为蓝牙发送) 支持解压Zip,Rar,Jar文件 可以浏览Word文档 可以查看硬件信息 可以查看手机进程和开启的任务 内置自动升级功能 可以在收件箱中浏览或保存文件 内置16进制编辑功能 支持文件搜索和自定义热键 简单的声音.视频播放器 V1.35更新可以在文件列表查看缩略图。 1.42 - 改进的文件搜索功能(通配符), 小修复 1.43 - 修复ZIP的解压缩以及加入其它国家语言。 1.45 - 正确复制的文件,允许删除只读文件,编辑多个文件的属性
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页