Lucas定理小推论

随便记录点数论小trick

Lucas 定理的小推论

先来看一道简单的例题:有趣的杨辉三角

题目大意:

给定一个整数 n (1n109) 和一个质数 p (2p<1000),求出杨辉三角上第 n+1 行上有多少个数不能p 整除

分析


看到数据范围很恐怖,众所周知杨辉三角的第 n+1 行上一共有 n+1 个数,分别是:

(n0),(n1),...(nn1),(nn)

n 的范围很大,而且要是暴力直接求组合数也得花费时间,显然不能直接暴力求解

但我们注意到 p 是个很小的质数,而且这题考虑的组合数都是在模 p 的意义下的,因此我们可以考虑 Lucas 定理

题目要求这 n+1 个组合数当中不能被 p 整除的数有多少个,我们可以考虑一下怎么求可以被 p 整除的数有多少个,即存在多少个 k[0,n](nk)0(mod p)

回顾一下 Lucas 定理:当 p 为质数时,将 nk 写成 p 进制数:

n=n0+n1p+n2p2+...+ndpdk=k0+k1p+k2p2+...+kdpd

则我们有:

(nk)(n0k0)·(n1k1)...(ndkd) (mod p)

那当什么情况下这个 (nk)0 (mod p) 呢?

我们将上面的式子分开来看,比如对于一个 (niki) 而言,要让它为 0 ,根据组合数的求法,只有可能是 ni<ki 时才会出现这样的情况,所以只要 kini,这个 (nk)mod p 的意义下都不为 0 ,即不被 p 整除。

那这样的 k 有多少个呢?根据乘法原理,将 n 进行 p 进制拆分后,对于 kp 进制第 i 位来说,ki 的取值可以是 [0,1,2,...,ni] 一共 ni+1 种选法,所以最终答案为:

i=0d(ni+1) ninpi

其实这是个比较出名的定理,如下图:觉得我写的烂的可以自行阅读一下文献
QQ图片20211004234059.png


Code:

#include <iostream>
#include <cstdio>

using namespace std;

const int mod = 10000;

int main() {
    int n, p, Case = 0;
    while (cin >> p >> n, n || p) {
        int res = 1;
        while (n) {
            res = res * (n % p + 1) % mod;
            n /= p;
        }
        printf("Case %d: %04d\n", ++ Case, res);
    }
    return 0;
}

时间复杂度:对 n 进行 p 进制分解的复杂度为 O(logpn),乘上测试数据组数,总时间复杂度为 O(Tlogpn),完全没问题

posted @   Xeus  阅读(102)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示