組合數取模的題……

 

聰聰考試
難度級別:C; 運行時間限制:1000ms; 運行空間限制:262144KB; 代碼長度限制:2000000B
試題描述

聰聰是一個善良可愛、睿智聰慧的好孩子。聰聰是100%的學霸,這一天她在考數學。聰聰很快作到了最後一道題:「高一八班有n我的,從1到n編號,一次互判做業時,老師隨機將做業發到這n我的手中。已知有k我的拿到的不是本身的做業,那麼請問有多少種狀況符合條件呢?」這麼簡單的問題聰聰固然會作了,她想考考你,你能不能比她先給出問題的答案呢?html

輸入
共1行,包含2個整數n和k。
輸出
共1行,包含1個整數,表示答案。因爲答案可能很大,請輸出答案模10007的餘數。
輸入示例
4 3
輸出示例
8
其餘說明
對於30%的數據,0≤k≤n≤10。
另有10%的數據,k=0。
另有10%的數據,k=1。
對於70%的數據,0≤k≤n≤10000。
對於100%的數據,0≤k≤1000000,1≤n≤1000000000。

題解:ios

n我的當中有k我的拿到的必定不是本身的做業,咱們只須要考慮k我的沒有拿到本身做業的狀況,因此咱們能夠先來一個dp數組儲存到k的全錯排列。動規方程是:dp[i]=(i-1)*dp[i-1]+(i-1)*dp[i-2](dp[i]表明i我的,所有拿到的不是本身做業的種類數)。數組

動規方程來源:ide

有一種狀況是:假如當前有i我的,咱們能夠假設前i-1我的拿到的全都不是本身的做業,那麼第i我的拿到的必定是本身的做業,因此咱們可讓第i我的的做業與前i-1任意一我的的做業進行交換,就是(i-1)dp[i-1]。spa

還有一種狀況:就是假設前i-1我的中有1我的拿到本身的做業,也就是說第i我的必定要與拿到本身的做業的人的做業進行交換,這樣算出來就是(i-1)dp[i-2]。code

以上兩種狀況構成了全部的狀況,因此咱們能夠獲得dp方程:dp[i]=(i-1)*dp[i-1]+(i-1)*dp[i-2]htm

咱們須要從n我的中選取k我的拿到的不是本身的做業,對於每一次選取,都有dp[k]種狀況,因此最後答案是dp[k]*C(n,k)。blog

可是因爲數據比較大,在處理C(n,k)的時候應該用盧卡斯定理get

如下是代碼:input

 1 #include<iostream>
 2 #define MAXN 1000000+10 
 3 using namespace std;
 4 const int mod=10007;
 5 int qp_mod(int x,int n){
 6     int b=1;
 7     while(n>0){
 8         if(n&1)b=b*x%mod;
 9         x=x*x%mod;
10         n>>=1;
11     }
12     return b;
13 }
14 int comb(int n,int m){
15     if(m>n)return 0;
16     if(m==n)return 1;
17     int M=1;
18     for(int i=1;i<=m;i++){
19         i%=mod;
20         M=M*i%mod;
21     }
22     M=qp_mod(M,mod-2);
23     for(int i=n;i>=n-m+1;i--){
24         i%=mod;
25         M=M*i%mod;
26     }
27     return M;
28 }
29 int Lucas(int n,int m){
30     int ans=1;
31     while(n&&m&&ans){
32         ans=ans*comb(n%mod,m%mod)%mod;
33         n/=mod;m/=mod;
34     }
35     return ans;
36 }
37 int n,k;
38 int dp[MAXN];
39 int main(){
40     scanf("%d%d",&n,&k);
41     if(k==0){
42         cout<<1;
43         return 0;
44     }
45     dp[1]=0;dp[2]=1;
46     for(int i=3;i<=k;i++){
47         dp[i]=(i-1)%mod*((dp[i-1]+dp[i-2])%mod)%mod;
48     }
49     cout<<Lucas(n,k)*dp[k]%mod;
50 }
View Code
相關文章
相關標籤/搜索