Loj #6244. 七选五

link: https://loj.ac/problem/6244

 

让我们设B=N-K,再设F(P)为从1~P+B中选P个数(有序的),且这P个数是一个错排(即不存在一个i使得 i=Ai ,其中A是选出的有序的P个数)的方案数。

再设G(P)为从1~P+B中选出P个数的方案数。

 

有几个显然的结论:

1.G(P)=P(P+B,P)

2.ANS=C(K,X)*F(K-X) ,考虑x个相同的是哪些元素。。。

3.G(P)=Σ F(i) * C(P,i)  ,考虑有几个元素和原来相同。。。

 

因为3.可以用来二项式反演,然后再结合1.就可以求出F(K-X),然后直接得到答案。

#include<bits/stdc++.h>
#define ll long long
#define maxn 1000000
using namespace std;
const int ha=1000000007;
int jc[maxn+5],ni[maxn+5];
int N,X,K,B;

inline int add(int x,int y){
	x+=y;
	return x>=ha?x-ha:x;
}

inline int ksm(int x,int y){
	int an=1;
	for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha;
	return an;
}

inline void init(){
	jc[0]=1;
	for(int i=1;i<=maxn;i++) jc[i]=jc[i-1]*(ll)i%ha;
	ni[maxn]=ksm(jc[maxn],ha-2);
	for(int i=maxn;i;i--) ni[i-1]=ni[i]*(ll)i%ha;
}

inline int P(int x,int y){
	return x<y?0:jc[x]*(ll)ni[x-y]%ha;
}

inline int C(int x,int y){
	return x<y?0:P(x,y)*(ll)ni[y]%ha;
}

inline int F(int x){
	int an=0;
	for(int i=0;i<=x;i++)
	    if((x-i)&1) an=add(an,ha-P(i+B,i)*(ll)C(x,i)%ha);
	    else an=add(an,P(i+B,i)*(ll)C(x,i)%ha);
	
	return an;
}

inline int calc(){
	return C(K,X)*(ll)F(K-X)%ha;
}

int main(){
	init();
	scanf("%d%d%d",&N,&K,&X);
	B=N-K;
	printf("%d\n",calc());
}

  

posted @ 2018-03-04 18:54  蒟蒻JHY  阅读(406)  评论(0编辑  收藏  举报