bzoj4517[Sdoi2016]排列计数

bzoj4517[Sdoi2016]排列计数

题意:

求有多少种长度为n的序列 A,满足1~n在序列中各出现了一次,且序列恰好有m个数是稳定的(若第i个数A[i]的值为i,则称i是稳定的)。共T组数据,方案数模10^9+7。T=500000,n≤1000000,m≤1000000。
题解:
显然结果为C(n,m)*f[n-m],f[n-m]为错排数满足f[i]=(f[i-1]+f[i-2])*(i-1),f[1]=0,f[0]=1。因为n,m过大,求组合数的递推法行不通,因此只能用公式:C(n,m)=n!/(m!*(n-m)!),n!先递推出来,因为最后有除法,故还须求个逆元,刚好模数是质数,所以利用费马小定理,写个快速幂就好了。
代码:
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define maxn 1000010
 6 #define mod 1000000007
 7 using namespace std;
 8 
 9 inline int read(){
10     char ch=getchar(); int f=1,x=0;
11     while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
12     while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
13     return f*x;
14 }
15 long long power(int a,int b){
16     if(b==0)return 1; if(b==1)return a;
17     long long c=power(a,b>>1);
18     if(b&1)return c*c%mod*a%mod;else return c*c%mod;
19 }
20 long long a[maxn],b[maxn]; int t,n,m;
21 long long c(int n,int m){
22     return a[n]*power(a[n-m]*a[m]%mod,mod-2)%mod;
23 }
24 int main(){
25     a[0]=1; inc(i,1,maxn-10)a[i]=a[i-1]*i%mod; b[0]=1; b[1]=0; inc(i,2,maxn-10)b[i]=(b[i-1]+b[i-2])%mod*(i-1)%mod;
26     t=read();
27     while(t--){n=read(); m=read(); printf("%lld\n",c(n,m)*b[n-m]%mod);}
28     return 0;
29 }

 

20160814

posted @ 2016-08-16 22:18  YuanZiming  阅读(192)  评论(0编辑  收藏  举报