ZOJ 3688
来源:互联网 发布:vs mysql 编辑:程序博客网 时间:2024/06/14 14:12
题解:
很显然利用容斥原理,对于k个章节放错的排列方法,因为放错章节的序列为1 2 2 3 3 4,...,n,1,要满足从这个序列中取出k个数,k个数不想邻,可知即递增序列,且两个1不能同时取到,可以证明自增序列的个数为C(n-k+1,k),而1同时取到的个数为C(2n-4-(k-2)+1,k-2),于是可解
需要注意的是求解逆元的时候要用到快速幂,而且初始化要将fac[n]的每一个数的逆元也要初始化,否则会T
代码:
#include <cstdio>#include <cstring>#define ll long long#define mod 1000000007using namespace std;const int MAX=200010;ll fac[MAX],inv[MAX];ll quickPow(ll n,ll k){ ll ans=1; while(k) { if(k&1) ans=ans*n%mod; n=n*n%mod; k=k>>1; } return ans;}void pre(){ fac[0]=1; for(int i=1;i<=200000;i++) fac[i]=fac[i-1]*i%mod; for(int i=1;i<=200000;i++) inv[i]=quickPow(fac[i],mod-2); inv[0]=quickPow(fac[0],mod-2);}ll cal(ll n,ll k){ return fac[n]*inv[k]%mod*inv[n-k]%mod;}int main(){ ll n; pre(); while(scanf("%lld",&n)!=EOF) { ll ans=fac[n]; if(n==1) { printf("0\n"); continue; } for(int k=1;k<=n;k++) { if(k==1) ans=(ans-cal(n,k)*2*fac[n-1]%mod)%mod; else if(k&1) ans=(ans-(cal(2*n-k+1,k)-cal(2*n-k-1,k-2))*fac[n-k]%mod)%mod; else ans=(ans+(cal(2*n-k+1,k)-cal(2*n-k-1,k-2))*fac[n-k]%mod)%mod; } printf("%lld\n",(ans%mod+mod)%mod); } return 0;}
- ZOJ 3688
- zoj 3688
- ZOJ
- ZOJ
- ZOJ
- ZOJ
- ZOJ
- ZOJ
- ZOJ
- ZOJ
- ZOJ
- ZOJ
- ZOJ
- ZOJ
- ZOJ
- ZOJ
- ZOJ
- ZOJ
- linux tr 命令详解
- Unity Application Block 1.0系列(1): 快速开始
- poj Sightseeing Cows 分数规划+spfa
- VC简单实现播放音乐
- 不用replace方法,实现 - 只能输入数字的input
- ZOJ 3688
- iPhone 5s指纹识别存在什么安全隐患?
- [Git]多平台协作 忽略WhiteSpace
- HDU4726Kia's Calculation 贪心
- Unity Application Block 1.0系列(2): 构造子注入(Constructor Injection)
- Vxwoks系统入门知识学习(一)
- 三星 samsung odin线刷包和卡刷包的制作方法
- 心静是一门艺术
- MFC VC 中 TreeView 全面解析