洛谷傳送門
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。小蔥想知道如果給定...