卢卡斯定理

卢卡斯定理(Lucas Law)

,

核心内容

对正整数 m, n, 质数 p, 有

(nm) % p=(npmp)(n % pm % p) % p

证明

(pm) (p>m) 开始证明

(pm)=p!m!(pm)!=px(p1)!(m1)!((p1)(m1))!=pm(p1m1)

由于是模 p 意义下的运算, 且 gcd(x,p)=1, 所以对 m(0,p)

(pm) % p=pInvm(p1m1) % p=0

代入到二项式定理可得

(1+x)p % p=i=0p(pi)xi % p=(1+xp) % p

将二项式指数推广到正整数 n, 设 qm=mp, qn=np,rm=m % p,rn=n % p

(1+x)n=(1+x)qnp+rn=(1+x)qnp(1+x)rn

使用前面的结论 (1+x)p % p=(1+xp) % p, 整理上式得

(1+x)n % p=(1+xp)qn(1+x)rn % p

代入二项式定理

(1+x)n % p=i=0qn((qni)xipj=0rn(rnj)xj) % p

整理得

(1+x)n % p=i=0qnj=0rn((qni)(rnj)xip+j) % p

由于 j<p, 所以任意一组 i, j 对应唯一的 ip+j 值, 和 [0,n] 内的每一个数一一对应, 所以将式子改写为枚举 m=ip+j 的值.

(1+x)n % p=m=0n(qnqm)(rnrm)xk % p

所以, 模 p 意义下, (1+x)nm 次项系数 (nm) 就是 (qnqm)(rnrm)

定理得证

模板Luogu3807

T(n+mn) % p

1n,m,p105,1T10, p 为质数

由于 p 为质数且 p105, 可以用 Lucas 定理 递归求解

(n+mn) % p=((n+m) % pn % p)((n+m)/pm/p) % p

unsigned Lucas (unsigned x, unsigned y) {
  if(x <= Mod && y <= Mod) {
    return Binom(x, y);
  }
  return ((long long)Binom(x % Mod, y % Mod) * Lucas(x / Mod, y / Mod)) % Mod;
}

递归边界就是 x,y[0,p), 直接 O(n) 求出 (xy)

需要注意的是, 当遇到取模之后 x<y 时, (xy)=0, 因为 (1+x)x 不存在 y 次项 (括号内的 x 是自变量, 指数 x 是函数调用的参数)

还有, 当 y=0 的时候, (xy)=1, 尽管不加这个特判返回值也是 0, 但是不知道为什么我还是加了

unsigned Binom (unsigned x, unsigned y) {
  unsigned Up(1), Down(1);
  if (y > x) {
    return 0;
  }
  if(!y) {
    return 1;
  }
  for (register unsigned i(2); i <= x; ++i) {
    Up = ((long long)Up * i) % Mod;
  }
  for (register unsigned i(2); i <= y; ++i) {
    Down = ((long long)Down * i) % Mod;
  }
  for (register unsigned i(2); i <= x - y; ++i) {
    Down = ((long long)Down * i) % Mod;
  }
  Down = Power(Down, Mod - 2);
  return ((long long)Up * Down) % Mod;
}

函数 Binom() 中的 Power() 用来根据欧拉定理求乘法逆元, 即 Invx=xp2

unsigned Power (unsigned x, unsigned y) {
  if(!y) {
    return 1;
  }
  unsigned tmp(Power(((long long)x * x) % Mod, y >> 1));
  if(y & 1) {
    return ((long long)x * tmp) % Mod;
  }
  return tmp;
}

最后放出 main(), 可以看出又多了一句无关紧要的特判, 一看就是让 julian 毒害过的可怜人

int main() {
  t = RD();
  for (register unsigned T(1); T <= t; ++T){
    Clr();
    if(!(n && m)) {
      printf("1\n");
      continue; 
    }
    printf("%u\n", Lucas(n + m, n));
  }
  return Wild_Donkey;
}
posted @   Wild_Donkey  阅读(99)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
历史上的今天:
2020-03-14 数论: 莫比乌斯反演 ( 三 ) 证明
点击右上角即可分享
微信分享提示