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