[SDOI2016]排列计数 (错排数概念 + 递推公式【附带证明】)
辛勤二更
- 題目
- 題解
- 錯排數概念
- 錯排數遞推公式及其證明
- 代碼實現
這種題做的時候:
做完后:正常這就是生活,我們要學會習慣
題目
求有多少種長度為 n 的序列 A,滿足以下條件:
1 ~ n 這 n 個數在序列中各出現了一次
若第 i 個數 A[i] 的值為 i,則稱 i 是穩定的。序列恰好有 m 個數是穩定的
滿足條件的序列可能很多,序列數對 10^9+7取模。
輸入格式
第一行一個數 T,表示有 T 組數據。
接下來 T 行,每行兩個整數 n、m。
輸出格式
輸出 T 行,每行一個數,表示求出的序列數
輸入輸出樣例
輸入
5
1 0
1 1
5 2
100 50
10000 5000
輸出
0
1
20
578028887
60695423
說明/提示
測試點 1 ~ 3:T=1000, n≤8, m≤8;
測試點 4 ~ 6: T=1000, n≤12,m≤12;
測試點 7 ~ 9: T=1000, n≤100, m≤100;
測試點 10 ~ 12: T = 1000,n≤1000, m≤1000;
測試點 13 ~ 14: T = 500000, n≤1000, m≤1000;
測試點 15 ~ 20: T = 500000, n≤1000000,m≤1000000。
題解
突然想感慨一番:
步入正軌↓(我真的很討厭這種有模數的方案數題)
題意很簡單,n個數固定m個數,那么就有n-m個數上的位置是不穩定的
也就是這n-m個數要滿足A[i]≠i,對于這n-m中的某個位置i,就只有n-m-1種填法
錯排數概念
這里就引入錯排數的概念
n個有序的元素應有n!個不同的排列,如若一個排列使得所有的元素不在原來的位置上,則稱這個排列為錯排;有的也稱之為重排
錯排數遞推公式及其證明
求n個數的錯排數:DP[n]=(n?1)?(DP[n?1]+DP[n?2])DP[n]=(n-1)*(DP[n-1]+DP[n-2])DP[n]=(n?1)?(DP[n?1]+DP[n?2])
證明如下:
①考慮第n個元素,把它放在某一個位置,比如位置k,一共有n-1種放法
②考慮第k個元素,這時有兩種情況:
(1)把它放到位置n,那么對于除n以外的n-1個元素,由于第k個元素放到了位置n,所以剩下n-2個元素的錯排即可,有f(n?2)f(n-2)f(n?2)種放法;
(2)第k個元素不放到位置n,這時對于這n-1個元素的錯排,有f(n?1)f(n-1)f(n?1)種放法
運用加法以及乘法原理,得證完畢。。。
處理完n-m后,我們就要處理m,要知道選的m的位置不同算不同的方案哦(⊙o⊙)!
這個其實就是排列組合,從n個數中選m個的方案數:
Cnm=n!m!?(n?m)!C_n^m=\frac{n!}{m!*(n-m)!}Cnm?=m!?(n?m)!n!?
這里寫出來后就發現這里面涉及到了除法,而取模運算中是不能進行除法運算的
所以我們就要去求m!m!m!和(n?m)!(n-m)!(n?m)!各自的逆元與n!n!n!相乘,
有很多方法都可以完成,費馬小定理,擴展歐幾里得…
代碼實現
#include <cstdio> #define mod 1000000007 #define LL long long #define MAXN 1000000 int T, n, m; LL sum[MAXN + 5], inv[MAXN + 5], dp[MAXN + 5]; LL qkpow ( LL x, int y ) {LL ans = 1;while ( y ) {if ( y & 1 )ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans % mod; } LL getinv ( LL x ) {return qkpow ( x, mod - 2 ); } int main() {scanf ( "%d", &T );sum[0] = 1;inv[0] = 1;for ( int i = 1;i <= MAXN;i ++ ) {sum[i] = sum[i - 1] * i % mod;inv[i] = getinv ( sum[i] );}dp[0] = dp[2] = 1;for ( int i = 3;i <= MAXN;i ++ )dp[i] = ( dp[i - 1] + dp[i - 2] ) % mod * ( i - 1 ) % mod;while ( T -- ) {scanf ( "%d %d", &n, &m );printf ( "%lld\n", sum[n] * inv[n - m] % mod * inv[m] % mod * dp[n - m] % mod ); }return 0; }byebye~~~~~~
總結
以上是生活随笔為你收集整理的[SDOI2016]排列计数 (错排数概念 + 递推公式【附带证明】)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大龙虾怎么洗简单又干净 大龙虾清洗窍门
- 下一篇: 魔方俱乐部