题解-洛谷4921&4931 情侣?给我烧了!(加不加强无所谓版)

Problem

简单版 & 加强版

题目概要(其实题面写得很清楚,这里搬运一下):

\(n\) 对情侣排座位,恰有 \(n\) 排座位,每排 \(2\) 个座位,在一个就座方案中所有人会将将座位坐满(共有 \((2n)!\) 种不同的就坐方案。)

求出共有多少种不同的就坐方案满足恰好有 \(k\) 对情侣坐在一排

  • 简单版:给出 \(T\leq 10^3\) 组数据,每组数据给出 \(n\leq 10^3\),对于每个 \(k\in [0,n]\) 输出
  • 加强版:给出 \(T\leq 2\times 10^5\) 组数据,每组数据给出 \(n\leq 5\times 10^6\),对于给出的 \(k\in[0,n]\) 输出

每组询问间 \(n,k\) 不保证相同

Complains

这题目名……让很久没见妹子的我很是心酸啊……

写完简单版发现可以直接过加强版,于是就把这两题写在一起了啦 这题为啥是黑题啊

本来想容斥搞事的,结果推出来始终过不了样例

但估计有简单版和加强版之分,估计简单版是容斥,求dalao指教怎么容斥啊

Solution

然后就尝试着直接做,那对于恰有 \(k\) 对情侣的就坐方案,首先要选出 \(k\) 对情侣 \(\binom nk\),然后要给他们安排对应的位置 \(P_n^k\),再算上一排座位间怎么坐都是一样的 \(2^n\),最后要限制其他 \(n-k\) 对情侣都不在一排

最后一个问题明显是错排,错排的式子是 \(D_n=(n-1)(D_{n-1}+D_{n-2})\),是由增量法得到的

在这题里,情侣之间不好考虑,然后错排中每加入两个人,和传统的错排一样,只是两个人要选择一个调换到前边去,所以要乘 \(2\),所以得到递推式为 \(d_i=2(i-1)(d_{i-1}+d_{i-2})\),最后要乘上加入的顺序 \(i!\)

所以最后的答案为

\[Ans=C_n^k\cdot P_n^k\cdot 2^n\cdot (n-k)!\cdot d_{n-k} \]

所以这种 \(O(n)\) 预处理 \(O(1)\) 查询的做法两道题都能过

Code

简单版

#include <cstdio>
typedef long long ll;

const int N=1013,p=998244353;
int fac[N],inv[N],g[N],f[N],pw2[N];
int n;

inline int C(int nn,int mm){return (ll)fac[nn]*inv[mm]%p*inv[nn-mm]%p;}
inline int P(int nn,int mm){return (ll)fac[nn]*inv[nn-mm]%p;}

inline int qpow(int A,int B){
	int res(1);while(B){
		if(B&1)res=(ll)res*A%p;
		A=(ll)A*A%p,B>>=1;
	}return res;
}

int main(){
	pw2[1]=2;inv[0]=g[0]=1;
	fac[0]=fac[1]=pw2[0]=1;
	for(int i=2;i<N;++i){
		fac[i]=(ll)fac[i-1]*i%p;
		pw2[i]=2ll*pw2[i-1]%p;
		g[i]=2ll*(i-1)*(g[i-1]+g[i-2])%p;
	}
	inv[N-1]=qpow(fac[N-1],p-2);
	for(int i=N-2;i;--i)inv[i]=(ll)inv[i+1]*(i+1)%p;
	
	int T,n;
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		for(int i=0;i<=n;++i)
			printf("%lld\n",(ll)C(n,i)*P(n,i)%p *pw2[n]%p *fac[n-i]%p *g[n-i]%p);
	}
}

加强版

#include <bits/stdc++.h>
typedef long long ll;

inline void read(int&x){
	char c11=getchar();x=0;while(!isdigit(c11))c11=getchar();
	while(isdigit(c11))x=x*10+c11-'0',c11=getchar();
}

const int N=5001001,p=998244353;
int fac[N],inv[N],g[N],f[N],pw2[N];
int n;

inline int C(int nn,int mm){return (ll)fac[nn]*inv[mm]%p*inv[nn-mm]%p;}
inline int P(int nn,int mm){return (ll)fac[nn]*inv[nn-mm]%p;}

inline int qpow(int A,int B){
	int res(1);while(B){
		if(B&1)res=(ll)res*A%p;
		A=(ll)A*A%p,B>>=1;
	}return res;
}

int main(){
	pw2[1]=2;inv[0]=g[0]=1;
	fac[0]=fac[1]=pw2[0]=1;
	for(int i=2;i<N;++i){
		fac[i]=(ll)fac[i-1]*i%p;
		pw2[i]=2ll*pw2[i-1]%p;
		g[i]=2ll*(i-1)*(g[i-1]+g[i-2])%p;
	}
	inv[N-1]=qpow(fac[N-1],p-2);
	for(int i=N-2;i;--i)inv[i]=(ll)inv[i+1]*(i+1)%p;
	
	int T,n,k;read(T);
	while(T--){
		read(n),read(k);
		printf("%lld\n",(ll)C(n,k)*P(n,k)%p *pw2[n]%p *fac[n-k]%p *g[n-k]%p);
	}return 0;
}
posted @ 2019-01-18 17:14  oier_hzy  阅读(236)  评论(2编辑  收藏  举报