数学【洛谷P4071】 [SDOI2016]排列计数

P4071 [SDOI2016]排列计数

求有多少种长度为 n 的序列 A,满足以下条件:

1 ~ n 这 n 个数在序列中各出现了一次

若第 i 个数 A[i] 的值为 i,则称 i 是稳定的。序列恰好有 m 个数是稳定的

满足条件的序列可能很多,序列数对 10^9+7 取模。

错排+组合数。

首先n-m个元素是完全错排,带公式即可。

剩下的m个是要有序的,也就是从n个选m个。

code:

#include <iostream>
#include <cstdio>

#define int long long

using namespace std;

const int wx=1000007;

const int mod=1e9+7;

inline int read(){
	int sum=0,f=1; char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();}
	return sum*f;
}

int T,n,m;
int d[wx],fac[wx],inv[wx];

int ksm(int a,int b){
	int re=1;
	while(b){
		if(b&1)re=re*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return re;
}

void pre(){
	d[0]=1; d[1]=0; d[2]=1;
	for(int i=3;i<=1000000;i++)d[i]=(((i-1)%mod)*((d[i-1]+d[i-2])%mod))%mod;
	fac[0]=1;fac[1]=1;for(int i=2;i<=1000000;i++)fac[i]=i*fac[i-1]%mod;
	inv[1000000]=ksm(fac[1000000],mod-2);
	for(int i=1000000-1;i>=0;i--)
		inv[i]=inv[i+1]*(i+1)%mod;
}

int CC(int x,int y){
	if(x<y)return 0;
	return (((fac[x]%mod*inv[y]%mod)%mod)*(inv[x-y]%mod))%mod;
}

int C(int x,int y){
	return d[x-y]*(CC(x,y))%mod;
}

signed main(){
	T=read(); pre();
	while(T--){
		n=read(); m=read();
		printf("%lld\n",C(n,m));
	}
	return 0;
}
posted @ 2018-11-01 19:10  _王小呆  阅读(181)  评论(0编辑  收藏  举报