[Sdoi2016]排列计数
[Sdoi2016]排列计数
时间限制: 3 Sec 内存限制: 512 MB题目描述
求有多少种长度为 n 的序列 A,满足以下条件:
1 ~ n 这 n 个数在序列中各出现了一次
若第 i 个数 A[i] 的值为 i,则称 i 是稳定的。序列恰好有 m 个数是稳定的
满足条件的序列可能很多,序列数对 10^9+7 取模。
输入
第一行一个数 T,表示有 T 组数据。
接下来 T 行,每行两个整数 n、m。
T=500000,n≤1000000,m≤1000000
输出
输出 T 行,每行一个数,表示求出的序列数
样例输入
5
1 0
1 1
5 2
100 50
10000 5000
样例输出
0
1
20
578028887
60695423
solution:
考试的时候推出来的f[i]表示长度为i的不稳定序列的种类数,f[0]=1,f[1]=0,f[2]=1,f[i]=(f[i-1]+f[i-2])*(i-1)%mod;
剩下的求一下组合数就可以了,记得用逆元,本蒟蒻考试的时候lucas呵呵T了5个点。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define mod 1000000007 7 #define maxn 1000000 8 int read() { 9 int s=0,f=1; 10 char ch=getchar(); 11 while(ch>'9'||ch<'0') { 12 if(ch=='-') { 13 f=-1; 14 } 15 ch=getchar(); 16 } 17 while(ch>='0'&&ch<='9') { 18 s=(s<<1)+(s<<3)+(ch^48); 19 ch=getchar(); 20 } 21 return s*f; 22 } 23 int n,T,m; 24 long long f[maxn+5],anv[maxn+5]; 25 void init() { 26 f[0]=1,f[1]=0,f[2]=1; 27 anv[1]=1;anv[0]=1; 28 for(int i=3; i<=maxn; ++i) { 29 f[i]=(f[i-1]+f[i-2])*(i-1)%mod; 30 } 31 for(int i=2; i<=maxn; ++i) { 32 anv[i]=(anv[i-1]*i)%mod; 33 } 34 } 35 long long qpow(long long x,int t) { 36 long long ans=1; 37 for(; t; t>>=1,x=(x*x)%mod) { 38 if(t&1) { 39 ans=(ans*x)%mod; 40 } 41 } 42 return ans; 43 } 44 signed main() { 45 T=read(); 46 init(); 47 for(int i=1; i<=T; ++i) { 48 n=read(),m=read(); 49 long long ans=anv[n]*qpow(anv[m],mod-2)%mod*qpow(anv[n-m],mod-2)%mod*f[n-m]%mod; 50 printf("%lld\n",ans); 51 } 52 return 0; 53 }