本题目的题解写得较长,照顾一些初中同学(虽然我自己也是初中生),同时也方便作者以后复习使用。如有错误或疑问,请尽快私信作者
题目概况
洛谷链接: https://www.luogu.com.cn/problem/P2822
计蒜客链接: https://nanti.jisuanke.com/t/T2034
**难度:**普及+/提高(计蒜客评级普及T3 ,是不是低了 )
题目分析
简化题目: 定义一个数组求出C[n][min(n, m)]
中满足C(m, n)
是k
的倍数的有多少
涉及知识点: 前缀和以及杨辉三角,组合数的相关公式等数学预备知识
解题思路:
在讲思路之前,我先简单说一下预备知识供大家参考:
一、组合数
数据范围较大,阶乘计算不现实,在这里给出一个关于组合数的递推公式(本题只涉及 例1,例 2各位看官有兴趣可以了解一下)
对,就是高中数学选修二里的那玩意(翻教材去咯~)
我们也可以把该式变形为:C(m, n) = C(m, n - 1) + C(m - 1,n - 1)
所以用代码实现,递推式即为c[i][j] = c[i - 1][j] + c[i - 1][j - 1]
二、杨辉三角
形如此图即为杨辉三角,应该都听过,递推式即为dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1]
三、解题思路概括
首先我们发现组合数递推公式和杨辉三角递推公式相同,也就是说如果抽象的组合数我们无法想明白,就把它理解为杨辉三角做一个前缀和的预处理,但要注意,在最朴素的杨辉三角中,最右侧的元素无法更新,我们需要通过继承的方式从上到上更新。这个组合数我们可以在过程中直接模k,如果模k等于0,就把数量在前缀和中加1。
代码要点拆解
一、预处理环节
直接看注释
二维前缀和递推公式:
注意区分 :区域是前缀和的区域; 子矩阵指的是原矩阵中的区域
令x2 = n, y2 = m,假设A区域等于A子矩阵(视同)就是(1,1)。我们要输出的是D区域的,但是:
D = C区域(A,C子矩阵) + B区域(A,B子矩阵)
所以在加上B,C区域后,我们需要把A区域再减一遍,去重。
//预处理
c[0][0] = c[1][0] = c[1][1] = 1; //三角上第0行和第1行需要预定义(类比组合数)
for (int i =