【NOIP2016】组合数问题

本题在洛谷上的链接:https://www.luogu.org/problemnew/show/P2822


就在十一假期某学堂里有幸听出题人zhx大神讲课。。。

都说是水题,但还是需要技巧滴。首先得知道组合数的那个在杨辉三角里体现得淋漓尽致的性质:c[n][m]=c[n-1][m-1]+c[n-1][m]。

考虑到多组数据,但k是一定的,可以再开个数组来存到(i,j)时在第i行前j个的答案数,然后对应查询累加即可。

本以为这样就能过的,可是只有55分?输出中间结果一看,溢出了。。。

优化一下,判断是否能被k整除时,直接c[i][j]%=k就好,若是0则令答案数加1。

 1 #include <cstdio>
 2 #include <algorithm>
 3 
 4 using namespace std;
 5 
 6 const int mmax = 2005, maxt = 1e4 + 5;
 7 
 8 int in[maxt], im[maxt], tri[mmax][mmax], ans[mmax][mmax];
 9 
10 int main() {
11     int t, k, maxn = 0;
12     scanf("%d%d", &t, &k);
13     for (int i = 1; i <= t; ++i) {
14         scanf("%d%d", &in[i], &im[i]);
15         maxn = max(maxn, in[i]);
16     }
17     for (int i = 0; i <= maxn; ++i)
18         for (int j = 0; j <= i; ++j) {
19             if (!j || j == i) {
20                 tri[i][j] = 1;
21                 if (j == i) ans[i][j] = ans[i][j - 1];
22             }
23             else {
24                 tri[i][j] = (tri[i - 1][j - 1] + tri[i - 1][j]) % k;
25                 if (!tri[i][j]) ans[i][j] = ans[i][j - 1] + 1;
26                 else ans[i][j] = ans[i][j - 1];
27             }
28         }
29     for (int i = 1; i <= t; ++i) {
30         int out = 0;
31         for (int j = 0; j <= in[i]; ++j)
32             if (j <= im[i]) out += ans[j][j];
33             else out += ans[j][im[i]];
34         printf("%d
", out);
35     }
36     return 0;
37 }
AC代码
原文地址:https://www.cnblogs.com/Mr94Kevin/p/9818040.html