UOJ263 【NOIP2016】組合數問題


本文版權歸ljh2000和博客園共有,歡迎轉載,但須保留此聲明,並給出原文鏈接,謝謝合作。

 

 

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
轉載請注明出處,侵權必究,保留最終解釋權!

 

 

題目描述

組合數 CmnCnm 表示的是從 nn 個物品中選出 mm 個物品的方案數。舉個例子,從 (1,2,3)(1,2,3) 三個物品中選擇兩個物品可以有 (1,2),(1,3),(2,3)(1,2),(1,3),(2,3) 這三種選擇方法。根據組合數的定義,我們可以給出計算組合數 CmnCnm 的一般公式:

 

Cmn=n!m!(nm)!Cnm=n!m!(n−m)!

 

其中 n!=1×2××nn!=1×2×⋯×n;特別地,定義 0!=10!=1。

小蔥想知道如果給定 n,mn,m 和 kk,對於所有的 0in,0jmin(i,m)0≤i≤n,0≤j≤min(i,m) 有多少對 (i,j)(i,j) 滿足 CjiCij 是 kk 的倍數。

輸入格式

從標准輸入讀入數據。

第一行有兩個整數 t,kt,k,其中 tt 代表該測試點總共有多少組測試數據,kk 的意義見問題描述。

接下來 tt 行每行兩個整數 n,mn,m,其中 n,mn,m 的意義見問題描述。

輸出格式

輸出到標准輸出。

tt 行,每行一個整數代表所有的 0in,0jmin(i,m)0≤i≤n,0≤j≤min(i,m) 中有多少對 (i,j)(i,j) 滿足 CjiCij 是 kk 的倍數。

樣例一

input

1 2
3 3

output

1

explanation

在所有可能的情況中,只有 C12=2C21=2 是 22的倍數。

樣例二

input

2 5
4 5
6 7

output

0
7


正解:矩陣前綴和+組合數學
解題報告:
  

  這是一道很簡單的數學題,可以發現其實如果根據組合中的一個基本公式:C(n,m)=C(n-1,m)+C(n-1,m-1),就可以直接遞推出2000以內的所有的組合數。而我們只需要判斷有多少個點對滿足是k的倍數,很容易想到只要對k取模,對於為0的C(i,j)是肯定滿足是k的倍數的。

  因為k是所有詢問共用的,可以一開始就預處理出矩陣前綴和,之后每次O(1)查詢就可以了。

 
        

 

注意事項:

  很多人在考場上寫的是質因數分解,但是很明顯有一些k並不是質數,所以並不能直接分解,應該先對k進行質因數分解,在對於這些質因數在遞推中分析。


    

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <algorithm>
 6 #include <string>
 7 #include <ctime>
 8 #include <queue>
 9 #include <vector>
10 #include <cstdlib>
11 using namespace std;
12 typedef long long LL;
13 const int MAXN = 2011;
14 int T,k,n,m,ans;
15 int C[MAXN][MAXN],a[MAXN][MAXN];
16 int sum[MAXN][MAXN];
17 
18 void work(){
19     scanf("%d%d",&T,&k);
20     C[1][0]=C[1][1]=1;
21     for(int i=2;i<=2000;i++){
22         C[i][0]=1;
23         for(int j=1;j<=i;j++) {
24             C[i][j]=C[i-1][j-1]+C[i-1][j];            
25             C[i][j]%=k;
26             if(C[i][j]==0) {
27                 a[i][j]=1;
28             }
29         }
30     }
31     for(int i=1;i<=2000;i++)
32         for(int j=1;j<=2000;j++)
33             sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
34 
35     while(T--) {
36         scanf("%d%d",&n,&m); m=min(m,n);
37         printf("%d\n",sum[n][m]);
38     }
39 }
40 
41 int main()
42 {
43     work();
44     return 0;
45 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM