nowcoder OI 周赛 最后的晚餐(dinner) 解题报告

最后的晚餐(dinner)

链接:

https://www.nowcoder.com/acm/contest/219/B

来源:牛客网

题目描述

\(\tt{**YZ}\)(已被和谐)的食堂实在是太挤辣!所以\(\tt{Apojacsleam}\)现在想邀请他的一些好友去校外吃一顿饭,并在某酒店包下了一桌饭。

\(\tt{Apojacsleam}\)和他的同学们来到酒店之后,他才发现了这些同学们其实是\(N\)\(cp\),由于要保护广大单身狗的弱小心灵(\(FF\)!),所以他不想让任意一对情侣相邻。

说明:

  • 酒店的桌子是恰好有\(2N\)个位置的圆桌。
  • 客人恰好是\(N\)\(cp\),也就是说,圆桌上没有空位。
  • 桌子的每一个位置是一样的,也就是说,如果两种方案可以通过旋转得到,那么这就可以视为相等的。
  • 现在,你需要求出,将任意一对情侣不相邻的方案数。

说明

对于\(20\%\)的数据,\(1\le N\le 5\)
对于\(30\%\)的数据,\(1\le N\le20\)
对于\(50\%\)的数据,\(1\le N\le100\)
对于\(70\%\)的数据,\(1\le N\le 200000\)
对于\(100\%\)的数据,\(1\le N\le 30000000\)


思路:容斥原理

\(f_i\)代表至少\(i\)对情侣坐相邻的方案数。

首先考虑一个小问题,\(n\)个人围成一个可以旋转的环的方案数。

可以固定第一个人,方案数就是\((n-1)!\)

那么\(f_i=fac_{2n-i-1}\times 2^i \times \binom{n}{i}\)

分别代表,捆绑法以后的方案数,情侣内部的方案数和选择情侣的可能性。

答案就是\(\sum_{i=0}^nf_i(-1)^i\)

常数写的不好。。说起来标程写的好厉害,我都没看懂。。


Code:

#include <cstdio>
#define ll long long
const ll mod=1e9+7;
const ll Inv=500000004;
const int N=3e7+10;
ll quickpow(ll d,ll k)
{
	ll f=1;
	while(k)
	{
		if(k&1) f=f*d%mod;
		d=d*d%mod;
		k>>=1;
	}
	return f;
}
ll fac,tfac=1,ans=0,inv[N],po=1;
int n;
int main()
{
	scanf("%d",&n);
	if(n==1) return puts("0"),0;
	for(ll i=1;i<=n;i++) tfac=tfac*i%mod,po=po*2%mod;

	fac=tfac*quickpow(n,mod-2)%mod;

	inv[n]=quickpow(tfac,mod-2);

	for(ll i=n-1;~i;i--) inv[i]=inv[i+1]*(i+1)%mod;

	for(ll i=n;~i;i--)
	{
		(ans+=fac*inv[i]%mod*inv[n-i]%mod*po%mod*(i&1?-1:1))%=mod;
		fac=fac*(2*n-i)%mod;
		po=po*Inv%mod;
	}
    
	ans=(ans+mod)%mod;
    ans=ans*tfac%mod;
	printf("%lld\n",ans);
	return 0;
}

2018.10.28

posted @ 2018-10-28 23:16  露迭月  阅读(295)  评论(0编辑  收藏  举报