SDOI2016 排列计数

传送门

为什么又是结论题。

D [ n ] D[n] D[n]为长度为 n n n的错排方案数。考虑增量法求 D [ n ] D[n] D[n]
假设已知 D [ 1 ] D[1] D[1]~ D [ n − 1 ] D[n-1] D[n1]
现在令所有元素有序排列好,即 a [ i ] = i a[i]=i a[i]=i
n n n个元素可以选择前 n − 1 n-1 n1个位置中的任意一个放进去,假设选了某个位置 k k k,那么这个位置的元素 k k k就被挤出来了。
如果 k k k放在了位置 n n n,现在就相当于是 n n n k k k交换了位置,剩下 n − 2 n-2 n2个元素需要错排。即为 D [ n − 2 ] D[n-2] D[n2]种方案。
如果 k k k不放在位置 n n n,相当于是把 a [ k ] ! = k a[k]!=k a[k]!=k的限制变为了 a [ n ] ! = k a[n]!=k a[n]!=k,由于 n n n的位置已经固定在 k k k,所以现在问题转化为了 1 1 1~ n − 1 n-1 n1的错排问题,方案数为 D [ n − 1 ] D[n-1] D[n1]。这 n − 1 n-1 n1个限制关系依然是一一对应的。

于是有: D [ n ] = ( n − 1 ) ∗ ( D [ n − 1 ] + D [ n − 2 ] ) D[n]=(n-1)*(D[n-1]+D[n-2]) D[n]=(n1)(D[n1]+D[n2])

初始化: D [ 0 ] = 1 , D [ 1 ] = 0 , D [ 2 ] = 1 D[0]=1,D[1]=0,D[2]=1 D[0]=1,D[1]=0,D[2]=1

#include<bits/stdc++.h>
#define cs const
#define re register
cs int N=1e6+10,mod=1e9+7;
namespace IO{
	cs int Rlen=1<<22|1;
	char buf[Rlen],*p1,*p2;
	inline char gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}
	template<typename T>
	inline T get(){
		char ch=gc();T x=0;
		while(!isdigit(ch)) ch=gc();
		while(isdigit(ch)) x=((x+(x<<2))<<1)+(ch^48),ch=gc();
		return x;
	}
	inline int gi(){return get<int>();}
}
using IO::gi;
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline int quickpow(int a,int b,int ret=1){for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
int T,n,m,fac[N],ifac[N],D[N];
inline void prework(){
	fac[0]=1;
	for(int i=1;i<N;++i) fac[i]=mul(fac[i-1],i);
	ifac[N-1]=quickpow(fac[N-1],mod-2);
	for(int i=N-2;~i;--i) ifac[i]=mul(ifac[i+1],i+1);
	D[1]=0,D[2]=1,D[0]=1;
	for(int i=3;i<N;++i) D[i]=mul(i-1,add(D[i-1],D[i-2]));
}
inline int C(int n,int m){return (n<m)?0:mul(fac[n],mul(ifac[m],ifac[n-m]));}
int main(){
//	freopen("2701.in","r",stdin);
	prework(),T=gi();
	while(T--) n=gi(),m=gi(),printf("%d\n",mul(C(n,m),D[n-m]));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值