NOIP 2016 組合數問題

2022-03-20 04:57:42 字數 1788 閱讀 3690

洛谷傳送門

jdoj傳送門

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

cnm=n!m!(n−m)!

其中n! = 1 × 2 × · · · × n

小蔥想知道如果給定n,m和k,對於所有的0 <= i <= n,0 <= j <= min(i,m)有多少對 (i,j)滿足cij是k的倍數。

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

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

t行,每行乙個整數代表答案。

1 2 3 3

【樣例解釋】

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

【子任務】

noip2016提高組

一開始動手做這道題的時候,自己還是乙個對組合數沒什麼概念的蒟蒻。強行套公式理解後各種tle、ole、wa,總之就是爆零。我太菜了

後來就自學了組合數:

詳解組合數相關性質

發現其實很好理解,沒多少東西。

所以掌握了從通項公式到遞推公式高階的我成功地拿到了70分:

**:

#include#include#define int long long

using namespace std;

int t,k;

int n,m,ans;

int c[2010][2010];

signed main()

while(t--)

printf("%lld\n",ans);

} return 0;

}

後來加取模之後還可以多過兩個點(wa了的那倆,是由於資料太大爆long long的)

**:

#include#include#define int long long

using namespace std;

int t,k;

int n,m,ans;

int c[2010][2010];

signed main()

while(t--)

printf("%lld\n",ans);

} return 0;

}

然後絞盡腦汁地想那倆tle了的點是怎麼錯的。各種卡常還是失敗了。然後分析時間複雜度,發現最後出問題的還是列舉判斷的地方。

想一下,這個程式的時間複雜度,就算把預處理的部分除掉,最後還會出現\(o(t\times n\times m)\)的複雜度。必\(t\)無疑,這是無論怎麼加優化都沒有用的。

我們得優化演算法本身的複雜度:

如果\(o(nm)\)的級別不夠,那就化成\(o(1)\)級別的。

是的,你沒看錯,在給定\(k\)之後,完全可以在預處理的部分提前處理出所有的答案。

**:

#include#include#define ll long long

using namespace std;

int t,k;

int n,m;

ll c[2010][2010];

ll ans[2010][2010];

signed main()

ans[i][i+1]=ans[i][i];

} while(t--)

printf("%lld\n",ans[n][m]);

} return 0;

}

NOIP2016 組合數問題

題目描述 第一行有兩個整數t,k,其中t代表該測試點總共有多少組測試資料,k的意義見 問題描述 接下來t行每行兩個整數n,m,其中n,m的意義見 問題描述 t行,每行乙個整數代表答案。輸入樣例 1 1 23 3 輸入樣例 2 2 54 5 6 7 輸出樣例 1 1輸出樣例 2 07 樣例1說明 在所...

NOIP2016組合數問題

題目分析 dp不解釋。首先要來乙個組合數將cnm的值都預處理出來,不過在加起來的時候記得取模。接下來就是二維字首和的事情了。define m 2000 include include include include using namespace std int c m 3 m 3 sum m 3 ...

NOIP2016 組合數問題

題目描述 題目背景 noip2016 提高組 day2 t1 組合數 表示的是從 n 個物品中選出 m 個物品的方案數。舉個例子,從 1,2,3 三個物品中選擇兩個物品可以有 1,2 1,3 2,3 這三種選擇方法。根據組合數的定義,我們可以給出計算組合數 的一般公式 1 2 n。小蔥想知道如果給定...