最后的晚餐(dinner)
链接:
来源:牛客网
题目描述
\(\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#define ll long longconst 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