卢卡斯定理

今天终于明白了卢卡斯定理的证法!

定理

卢卡斯(Lucas)定理:若 p 是质数

(nm)modp=(n/pm/p)(nmodpmmodp)modp

貌似可以写成同余形式?

(nm)=(n/pm/p)(nmodpmmodp)(modp)

这里 (nm) 就是 Cnm

这个定理很是神奇,是将组合数学和数论联系在一起了,有意思。

证明

这个证明用到了二项式定理。

首先我们先证明两个引理:

1、pCpx,即 Cpx0(modp)

Cpx=p!(px)!x!=px(p1)!(px)!(x1)!

故:

Cpxp×x1×(p1)!(px)!(x1)!(modp)

其实写这么多步,很显然证明完了。

2、(1+x)p1+xp(modp),可以推广至在同余意义下的二项式定理:(a+b)pap+bp(modp)

(1+x)pi=0pCpixi(modp)

这里需要掌握二项式定理。然后我们结合引理1继续思考,发现 Cpi 除了 i=0i=p 的时候(这个时候 Cpi=1)不绝对能被 p 整除之外,其他情况都是一定被 p 整除。

于是式子化简~只需要考虑 i=0i=p

(1+x)pi=0pCpixi1p+xp1+xp(modp)

引理证明完毕,我们证明定理。

定理

思路是比较系数法(并不高深)。

n=ap+b,m=cp+d

那么考虑 (1+x)nmodp 如何和建立关系

(1+x)n(1+x)ap+b(1+x)ap(1+x)b((1+x)p)a(1+x)b(1+xp)a(1+x)b(modp)

过程中用到了引理1。再对其分别做二项式展开:

(i=0aCaixip)(j=0bCbjxj)(modp)(1)

这个式子看着复杂实则只是两个二项式展开相乘,如果看不懂可以自己在纸上彻底展开。

再回到原式

(1+x)ni=0nxi(modp)(2)

我们就可以将两个(1)、(2)联立。

i=0nxi(i=0aCaixip)(j=0bCbjxj)(modp)

于是乎~我们比较系数,左式中 xm 的系数是 Cnm,右式中 xm=xcpxd 的系数是 CacCbd

a=n/p,c=m/p,b=mmodp,d=nmodp

带回去,证毕。

参考这个视频版更助于理解:https://www.bilibili.com/video/BV1Jd4y127oY/?spm_id_from=333.999.0.0&vd_source=700dde1e30c453844bbbd11aff30a401


做题

学会这个,我们就可以轻松切掉洛谷模板题:

#include <bits/stdc++.h>
#define rei register int
#define LL long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define cvar int n, m, T;
#define rep(i, s, n, c) for (register int i = s; i <= n; i+=c)
#define repd(i, s, n, c) for (register int i = s; i >= n; i-=c)
#define CHECK cout<<"WALKED"<<endl;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0' && ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
#define pb push_back
#define ls id<<1
#define rs id<<1|1
const int INF = INT_MAX;
long long binpow(long long a, long long b, LL mod){long long res = 1;  while (b > 0){if (b & 1) res = res * a % mod;a = a * a % mod;  b >>= 1;  }  return res;}
using namespace std;
LL fac[100010];
LL exgcd(LL a, LL b, LL &x, LL &y)// 拓欧
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    LL d = exgcd(b, a % b, y, x);
    y -= (a / b) * x;
    return d;
}
LL inv(LL a, LL p)
{
    LL x, y;
    if (exgcd(a, p, x, y) != 1) // 无解的情形
        return -1;
    return (x % p + p) % p;
}
inline LL C(LL n, LL m, LL p) // 求解组合数
{
	if (n > m) return 0;
	return fac[m] * inv(fac[m - n], p) % p * inv(fac[n], p) % p;
}

LL lucas(LL n, LL m, LL p)
{
    if (m == 0) return 1;
    return (C(n % p, m % p, p) * lucas(n / p, m / p, p)) % p; // 公式主要部分,还有调用组合数
}

int main()
{
    LL T, a, b, p;
    cin >> T;
    while (T--)
    {
        cin >> a >> b >> p;
        fac[0] = 1; // 预处理阶乘
	    rep (i, 1, 100009, 1) // 可以到p
	    	fac[i] = fac[i - 1] * i % p;
        b = b + a;
        cout << lucas(a,b,p) << endl; // lucas定理优化
    }
    return 0;
}

好了好了,入门题结束,来道提高些的:P4345 [SHOI2015]超能粒子炮·改

要求 i=0k(ni)mod2333

推柿子+整除分块,我还不会,所以改日再来……

posted @   Vegdie  阅读(84)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示