最后的晚餐(dinner)
链接:
https://www.nowcoder.com/acm/contest/219/B
来源:牛客网
题目描述
( t{**YZ})(已被和谐)的食堂实在是太挤辣!所以( t{Apojacsleam})现在想邀请他的一些好友去校外吃一顿饭,并在某酒店包下了一桌饭。
当( t{Apojacsleam})和他的同学们来到酒店之后,他才发现了这些同学们其实是(N)对(cp),由于要保护广大单身狗的弱小心灵((FF)!),所以他不想让任意一对情侣相邻。
说明:
- 酒店的桌子是恰好有(2N)个位置的圆桌。
- 客人恰好是(N)对(cp),也就是说,圆桌上没有空位。
- 桌子的每一个位置是一样的,也就是说,如果两种方案可以通过旋转得到,那么这就可以视为相等的。
- 现在,你需要求出,将任意一对情侣不相邻的方案数。
说明
对于(20\%)的数据,(1le Nle 5)
对于(30\%)的数据,(1le Nle20)
对于(50\%)的数据,(1le Nle100)
对于(70\%)的数据,(1le Nle 200000)
对于(100\%)的数据,(1le Nle 30000000)
思路:容斥原理
(f_i)代表至少(i)对情侣坐相邻的方案数。
首先考虑一个小问题,(n)个人围成一个可以旋转的环的方案数。
可以固定第一个人,方案数就是((n-1)!)
那么(f_i=fac_{2n-i-1} imes 2^i imes inom{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
",ans);
return 0;
}
2018.10.28