bzoj4517[Sdoi2016]排列计数(组合数,错排)

4517: [Sdoi2016]排列计数

Time Limit: 60 Sec  Memory Limit: 128 MB
Submit: 1792  Solved: 1111
[Submit][Status][Discuss]

Description

求有多少种长度为 n 的序列 A,满足以下条件:
1 ~ n 这 n 个数在序列中各出现了一次
若第 i 个数 A[i] 的值为 i,则称 i 是稳定的。序列恰好有 m 个数是稳定的
满足条件的序列可能很多,序列数对 10^9+7 取模。

Input

第一行一个数 T,表示有 T 组数据。
接下来 T 行,每行两个整数 n、m。
T=500000,n≤1000000,m≤1000000
 

Output

输出 T 行,每行一个数,表示求出的序列数

 

Sample Input

5
1 0
1 1
5 2
100 50
10000 5000

Sample Output

0
1
20
578028887
60695423

HINT

 

Source

鸣谢Menci上传

 

/*
水水的组合数+错排 
C(n,m)*D[n-m]
tm bzoj为什么还是CE!! 
*/
#include<bits/stdc++.h>

#define N 1000002
#define M 1000000007

using namespace std;
int n,m;
long long inv[N]={1,1},fac[N]={1,1},f[N]={1,1},D[N];

inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

inline int C(int a,int b)
{
    return ((fac[a]*inv[b])%M*inv[a-b]%M)%M;
}

inline void init()
{
    fac[1]=1;
    for(int i=2;i<=N;i++)
    {
        fac[i]=(1ll*fac[i-1]%M*i)%M;
        f[i]=((M-M/i)*f[M%i])%M;
        inv[i]=(inv[i-1]*f[i])%M;
    } 
}

int main()
{
    //freopen("ly.in","r",stdin);
    D[0]=1;D[2]=1;init();
    for(int i=3;i<=N;i++)
    D[i]=((i-1)*(D[i-1]%M+D[i-2]%M))%M;
    int T;cin>>T;
    while(T--)
    {
        n=read();m=read();
        if (n-m==1) printf("0\n");
        else if(m==n) printf("1\n");
        else if(m==0) cout<<D[n]<<endl;
        else  cout<<(1ll*C(n,m)*D[n-m])%M<<endl;
    }
    return 0;
}

 

posted @ 2018-11-06 20:52  安月冷  阅读(227)  评论(0编辑  收藏  举报