[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 }

 

 
posted @ 2017-08-20 11:12  Forever_goodboy  阅读(282)  评论(1编辑  收藏  举报