数论_CRT(中国剩余定理)& Lucas (卢卡斯定理)

前言

又是一脸懵逼的一天。

正文

按照道理来说,我们应该先做一个介绍。

中国剩余定理

中国剩余定理,Chinese Remainder Theorem,又称孙子定理,给出了一元线性同余方程组的有解判定条件,并用构造法给出了通解的具体形式。

现在有方程组:中国剩余定理指出:

扩展中国剩余定理

在一般情况下,要求任两个数互质这个条件太苛刻了,CRT派不上用场,我们需要一个更具普遍性的结论,这就是EX-CRT。虽然是称为EX-CRT,但这个定理并没有直接用到CRT的结论。

  1. typedef long long ll;
  2. const int maxn = 111;
  3. // m为模数组,a为余数数组,0~n-1
  4. ll m[maxn], a[maxn];
  5. ll exgcd(ll a, ll b, ll &x, ll &y) {
  6. if (b == 0) {
  7. x = 1; y = 0;
  8. return a;
  9. }
  10. ll ans = exgcd(b, a % b, y, x);
  11. y -= a / b * x;
  12. return ans;
  13. }
  14. ll excrt() {
  15. ll lcm = m[0], last_a = a[0];
  16. for(int i = 1; i < n; i++) {
  17. ll lcm_a = ((a[i] - last_a) % m[i] + m[i]) % m[i];
  18. ll k = lcm, x, y;
  19. ll gcd = exgcd(lcm, m[i], x, y);
  20. ll mod = m[i] / gcd;
  21. x = (x * lcm_a / gcd % mod + mod) % mod;
  22. lcm = lcm / gcd * m[i], last_a = (last_a + k * x) % lcm;
  23. }
  24. return (last_a % lcm + lcm) % lcm;
  25. }

卢卡斯定理

卢卡斯定理是关于组合数和同余的定理,它表明当p为素数时:

其中,即为的进制展开中对应次数为的系数

因为当m>n时,二项式系数为0,那么二项式系数即组合数能被p整除等价于在p进制下,存在某一位m的数值大于对应的n的数值。

基于母函数可以简单证明这个定理。

可以用除法和取模方便的在循环中求出各个系数,代码如下:

  1. typedef long long ll;
  2. const int mod = 1e9 + 7;
  3. const int maxn = 1e5 + 100;
  4. void init() {
  5. F[0] = 1;
  6. for(int i = 2; i < maxn; i++)
  7. F[i] = i * F[i - 1] % mod;
  8. }
  9. ll qpow(ll a, ll b) {
  10. ll ans = 1;
  11. while(b) {
  12. if(b & 1) ans = ans * a % mod;
  13. b >>= 1; a = a * a % mod;
  14. }
  15. return ans;
  16. }
  17. ll lucas(ll N, ll M) {
  18. ll ans = 1;
  19. while(N & M) {
  20. ll n = N % mod, m = M % mod;
  21. if(n < m) return 0;
  22. ans = ans * F[a] % mod * qpow(F[m] * F[n - m] % mod, mod - 2) % mod;
  23. N /= p; M /= p;
  24. }
  25. return ans;
  26. }

扩展卢卡斯定理

卢卡斯定理同样不能处理模数不是素数的情况,这时便需要扩展卢卡斯定理。我们一步步分析如何求解模数不是素数的组合数问题。

首先,我们要解决的问题是求,其中不一定是素数。对于非素数,我们首先会联想到质因分解后结合解决问题。假设分解得到个质数,质数对应的个数为,对质因分解有。显然对,,,假设对,我们求出了,那么我们可以得到同余方程组::这时我们便可以套用解决问题,那么问题便转化为如何求解。

现在我们要求的是,其中是素数。又,显然需要求出和关于模的逆元,但考虑到这些项中可能包含(含有则不互质,逆元不存在),所以需要先提取,得到:,这里的阶乘是指提取之后的结果。这时就可以计算和关于的逆元了。这里,为了形式的统一,同时提取了中的。那么,问题又转化为了如何求。

目标:计算,为质数。上一步中提到,我们需要先提取。提取结果为:。第一部分很好理解,对于每一个的倍数,都可以提取出一个,一共有个;第二部分为的倍数被提取之后余下的,是一个阶乘的形式。显然在中,对于的幂,的个数不止个,也就是说第二部分仍然需要提取,这一部分可以递归解决。第三部分是剔除了的倍数之后余下的。对,,都有对,这也就是说,第三部分其实是存在循环节的,一共循环了次。除去循环节的余项长度在之内,直接累乘即可。

完整代码如下:

  1. typedef long long ll;
  2. const int N = 1e6 + 100;
  3. ll n, m, p;
  4. ll qpow(ll a, ll b, ll mod) {
  5. ll ans = 1;
  6. while(b) {
  7. if(b & 1) ans = ans * a % mod;
  8. b >>= 1; a = a * a % mod;
  9. }
  10. return ans;
  11. }
  12. ll fac(ll n, ll p, ll pk) {
  13. if (!n) return 1;
  14. ll ans = 1;
  15. for (int i = 1; i < pk; i++)
  16. if (i % p) ans = ans * i % pk;
  17. ans = qpow(ans, n / pk, pk);
  18. int npk = n % pk;
  19. for (int i = 1; i <= npk; i++)
  20. if (i % p) ans = ans * i % pk;
  21. return ans * fac(n / p, p, pk) % pk;
  22. }
  23. ll exgcd(ll a, ll b, ll &x, ll &y) {
  24. if (b == 0) {
  25. x = 1; y = 0;
  26. return a;
  27. }
  28. ll ans = exgcd(b, a % b, y, x);
  29. y -= a / b * x;
  30. return ans;
  31. }
  32. ll inv(ll a, ll p) {
  33. return qpow(a, p - 2, p);
  34. }
  35. ll C(ll n, ll m, ll p, ll pk) {
  36. if (n < m) return 0;
  37. ll fn = fac(n, p, pk),
  38. fm = fac(m, p, pk),
  39. fn_m = fac(n - m, p, pk),
  40. cnt = 0;
  41. for (ll i = n; i; i /= p)
  42. cnt += i / p;
  43. for (ll i = m; i; i /= p)
  44. cnt -= i / p;
  45. for (ll i = n - m; i; i /= p)
  46. cnt -= i / p;
  47. return fn * inv(fm * fn_m % pk, pk) % pk * qpow(p, cnt, pk) % pk;
  48. }
  49. ll a[N], mod[N]; // a[]是通过卢卡斯分解出来的组合数值,m[]是对应的模数
  50. int cnt; // 质因数的种数
  51. ll CRT() {
  52. ll M = 1, ans = 0;
  53. for (int i = 0; i < cnt; i++)
  54. M *= mod[i];
  55. for (int i = 0; i < cnt; i++)
  56. ans = (ans + a[i] * (M / mod[i]) % M * inv(M / mod[i], mod[i]) % M) % M;
  57. return ans;
  58. }
  59. ll exlucas(ll n, ll m, ll p) {
  60. ll sqrtp = sqrt(p + 0.5);
  61. for (int i = 2; p > 1 && i <= sqrtp; i++) {
  62. ll pk = 1;
  63. while (p % i == 0)
  64. p /= i, pk *= i;
  65. if (pk > 1)
  66. a[cnt] = C(n, m, i, pk), mod[cnt++] = pk;
  67. }
  68. if (p > 1)
  69. a[cnt] = C(n, m, p, p), mod[cnt++] = p;
  70. return CRT();
  71. }

题目

其实这篇博客到这里几乎就可以没了,因为我。。。爆0了

难啊。。。

A题

Biorhythms HDU-1370

题意

一个人有三个值(不知道是啥),然后每个值每到一个周期就会到达顶峰,求从d天开始,他三个值都到达顶峰是第几天。

思路

然而,三个周期都是质数,显然用的是中国剩余定理(CRT)

抽象一点来说,就是给你三个同余方程。

代码

  1. 1 #include <iostream>
  2. 2 #include <cstdio>
  3. 3 #include <algorithm>
  4. 4 #include <cmath>
  5. 5 #include <cstring>
  6. 6 using namespace std;
  7. 7 typedef long long ll;
  8. 8 ll exgcd(ll a, ll b, ll &x, ll &y)
  9. 9 {
  10. 10 if(!b)
  11. 11 {
  12. 12 x = 1;
  13. 13 y = 0 * 100;
  14. 14 return a;
  15. 15 }
  16. 16 ll d = exgcd(b, a % b, x, y);
  17. 17 ll t = x;
  18. 18 x = y;
  19. 19 y = t - a / b * y;
  20. 20
  21. 21 return d;
  22. 22 }
  23. 23
  24. 24 ll inv(ll a,ll n)
  25. 25 {
  26. 26 ll y, d, x, fre, pf, qw;
  27. 27 /*cnt't*/
  28. 28 fre = pf = qw = 1;
  29. 29 fre++, pf++, qw++;
  30. 30 /*can't*/
  31. 31 d = exgcd(a,n,x,y);
  32. 32 return d == 1 ? (x + n) % n:-1;
  33. 33 }
  34. 34
  35. 35 ll CN(ll leo, ll *a, ll *m)
  36. 36 {
  37. 37 ll M = 1, ret = 0;
  38. 38 for(ll i = 0; i < leo; i ++)
  39. 39 M *= m[i];
  40. 40
  41. 41 for(ll i = 0; i < leo; i ++)
  42. 42 {
  43. 43 ll w = M / m[i];
  44. 44 ret = (ret + w * inv(w, m[i]) * a[i]) % M;
  45. 45 }
  46. 46 return (ret + M) % M;
  47. 47 }
  48. 48 int main()
  49. 49 {
  50. 50 ll t = 1, d;
  51. 51 ll a[10],m[10];
  52. 52 m[0] = 23;
  53. 53 m[1] = 28;
  54. 54 m[2] = 33;
  55. 55 /*GN*/
  56. 56 ll tea;
  57. 57 scanf("%lld", &tea);
  58. 58 while(true)
  59. 59 {
  60. 60 scanf("%lld%lld%lld%lld", &a[0], &a[1], &a[2], &d);
  61. 61
  62. 62 if(a[0] == -1 && a[1] == -1 && a[2] == -1 && d == -1)
  63. 63 break;
  64. 64 ll ans = CN(3, a, m);
  65. 65 if(ans <= d)
  66. 66 ans += 21252;
  67. 67 ans -= d;
  68. 68
  69. 69 printf("Case %lld: the next triple peak occurs in %lld days.\n", t, ans);
  70. 70 t++;
  71. 71 }
  72. 72 return 0;
  73. 73 }

B题

Big Coefficients HDU-3929

题意

思路

显然是用卢卡斯,但我不知道为哈

未完待续

CRT中国剩余定理 & Lucas卢卡斯定理的更多相关文章

  1. [SDOI2010] 古代猪文 (快速幂+中国剩余定理+欧拉定理+卢卡斯定理) 解题报告

    题目链接:https://www.luogu.org/problemnew/show/P2480 题目背景 “在那山的那边海的那边有一群小肥猪.他们活泼又聪明,他们调皮又灵敏.他们自由自在生活在那绿色 ...

  2. HDU 5446 中国剩余定理+lucas

    Unknown Treasure Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Other ...

  3. 【bzoj1951】: [Sdoi2010]古代猪文 数论-中国剩余定理-Lucas定理

    [bzoj1951]: [Sdoi2010]古代猪文 因为999911659是个素数 欧拉定理得 然后指数上中国剩余定理 然后分别lucas定理就好了 注意G==P的时候的特判 /* http://w ...

  4. 中国剩余定理&Lucas定理&按位与——hdu 5446

    链接: hdu 5446 http://acm.hdu.edu.cn/showproblem.php?pid=5446 题意: 给你三个数$n, m, k$ 第二行是$k$个数,$p_1,p_2,p_ ...

  5. hdu 5446 Unknown Treasure 中国剩余定理+lucas

    题目链接 求C(n, m)%p的值, n, m<=1e18, p = p1*p2*...pk. pi是质数. 先求出C(n, m)%pi的值, 然后这就是一个同余的式子. 用中国剩余定理求解. ...

  6. 51 Nod 1079 中国剩余定理(孙子定理)NOTE:互质情况

    1079 中国剩余定理 一个正整数K,给出K Mod 一些质数的结果,求符合条件的最小的K.例如,K % 2 = 1, K % 3 = 2, K % 5 = 3.符合条件的最小的K = 23. 收起 ...

  7. Lucas 卢卡斯定理

    Lucas: 卢卡斯定理说白了只有一条性质 $$ C^n_m \equiv C^{n/p}_{m/p} \times C^{n \bmod p}_{m \bmod p} \ (mod \ \ p) $ ...

  8. Lucas(卢卡斯)定理模板&&例题解析([SHOI2015]超能粒子炮·改)

    Lucas定理 先上结论: 当p为素数: \(\binom{ N }{M} \equiv \binom{ N/p }{M/p}*\binom{ N mod p }{M mod p} (mod p)\) ...

  9. Lucas卢卡斯定理

    当$p$为素数时 $$C_n^m\equiv C_{n/p}^{m/p}*C_{n\%p}^{m\%p}(mod\ p)$$ 设$n=s*p+q,m\equiv t*p+r(q,r<=p)$ 我 ...

随机推荐

  1. 与大神聊天1h

    与大神聊天1h 啊,与大神聊天1h真的是干货满满 解bug问题 之所以老出bug是因为我老是调用别人的包啊,在调参数的时候,并不知道内部机制 其实就自己写一个函数,然后能把功能实现就好了. 问题是,出 ...

  2. tensorflow-gpu安装

    添加清华源(输入清华仓库镜像),可以提高下载速度: conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/ ...

  3. String Buffer和String Builder(String类深入理解)

      String在Java里面JDK1.8后它属于一个特殊的类,在创建一个String基本对象的时候,String会向“ 字符串常量池(String constant pool)” 进行检索是否有该数 ...

  4. centos7关闭运行的django项目

    1.查看django项目的端口对应的PID :sudo netstat -tulpn | grep :8000 2.杀死进程命令:kill -9 pid

  5. MySQL数据库重点监控指标

    MySQL数据库重点监控指标 QPS queries per seconds 每秒中查询数量 show global status like 'Question%'; Queries/seconds ...

  6. [Codechef TASTR] Level of Difference - 后缀数组,容斥原理

    [Codechef TASTR] Level of Difference Description 给定两个字符串,求恰好在一个字符串中出现过的本质不同的子串数量. Solution 设 \(U(S)\ ...

  7. vue插槽的使用

    一.插槽的基本使用 二.具名插槽的使用 三.编译作用域的例子 四.作用域插槽 一.插槽的基本使用     1.插槽的基本使用<slot></slot>     2.插槽的默认值 ...

  8. IntelliJ IDEA 2017.3尚硅谷-----插件的使用

    在 IntelliJ IDEA 的安装讲解中我们其实已经知道,IntelliJ IDEA 本身很多功能也都 是通过插件的方式来实现的.官网插件库:https://plugins.jetbrains.c ...

  9. Mysql5.6基础命令

    Centos7下mysql5.6数据库的操作 Mysql如何修改密码? 1.使用mysqladmin修改,这种修改方式需要知道mysql的原始密码 修改密码后我们测试下看看能不能登录成功 怎么才能不需 ...

  10. spring面试合集

    Spring是一个开源的轻量级Java SE / Java EE开发应用框架.在传统应用程序开发中,一个完整的应用是由一组相互协作的对象组成.所以开发一个应用除了要开发业务逻辑之外,最多的是关注如何使 ...