1. 程式人生 > >[bzoj4517][數論]排列計數

[bzoj4517][數論]排列計數

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

題解

知道了錯排這題就pj難度了.
錯排公式D[n]=(n-1)*(D[n-1]+D[n-2]) D[1]=0 D[2]=1
預處理一下組合再預處理一下錯排數
答案就是

CnmD[nm]
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std; typedef long long LL; const LL mod=1e9+7; LL pre[1110000],D[1110000]; LL pow_mod(LL a,int b) { LL ret=1; while(b) { if(b&1)ret=ret*a%mod; a=a*a%mod;b>>=1; } return ret; } int n,m,T; int main() { scanf("%d",&T); pre[1]=pre[0]=1;for
(int i=2;i<=1000000;i++)pre[i]=pre[i-1]*i%mod; D[0]=1;D[1]=0;D[2]=1; for(int i=3;i<=1000000;i++)D[i]=(i-1)*(D[i-1]+D[i-2])%mod; while(T--) { scanf("%d%d",&n,&m); LL p=pre[n]*pow_mod(pre[m],mod-2)%mod*pow_mod(pre[n-m],mod-2)%mod; LL q=D[n-m]; printf("%lld\n",p*q%mod); } return 0; }