1. 程式人生 > >【錯位+組合】排列計數

【錯位+組合】排列計數

scanf 一行 組合 數據 i++ can sca sin fine

題目描述

求有多少種長度為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



有m個位置的數要等於i,其他n-m個位置腰錯位,用f[i]=(i+1)*(f[i-1]*f[i-2])推一下,最後c(n,m)*f[n-m]就行了

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1e9+7;
ll t,n,m;
ll f[5000005],fac[5000005],inv[5000005];
 
void init()
{
    ll N=2000000;
    f[0]=1,f[1]=0,f[2]=1,fac[0]=1,inv[0]=inv[1]=1;
    for(ll i=3;i<=N;i++) f[i]=(i-1)*((f[i-1]+f[i-2])%mod)%mod;
    for(ll i=1;i<=N;i++) fac[i]=fac[i-1
]*i%mod; for(ll i=2;i<=N;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod; for(ll i=1;i<=N;i++) inv[i]=inv[i]*inv[i-1]%mod; } ll c(ll n,ll m) { /*if(!n&&!m) return 0;*/ if(n<m) return 0; return fac[n]*inv[m]%mod*inv[n-m]%mod; } int main() { init(); scanf(
"%lld",&t); while(t--) { scanf("%lld %lld",&n,&m); printf("%lld\n",c(n,m)*f[n-m]%mod); } return 0; }

【錯位+組合】排列計數