标签:enc lcm can 之一 math 复习 static std play
写在前面
记录了个人的学习过程,同时方便复习
中国剩余定理
【物不知数】是中国古代著名算题 原载《孙子算经》卷下第二十六题: “今有物不知其数,三三数之剩二;五五数之剩三;七七数之剩二。问物几何?” 当时虽已有了答案23,但它的系统解法是秦九韶在《数书九章·大衍求一术》中给出的 中国剩余定理是中国古算中最有独创性的成就之一,属现代数论中的一次同余式组问题 ——bia度百科 |
有x个物件,三个三个数剩2个,五个五个位数剩3个,七个七个数剩2个
那么就是求解以下同余方程:
x ≡ 2 (MOD 3)
x ≡ 3 (MOD 5)
x ≡ 2 (MOD 7)
可以用分治的思想来做
先求得这样的三个数,使得对于每个模数而言,仅有模它得到的余数为1
(注意,这样的解法仅在模数两两互质的情况下成立)
x1 ≡ 1 (MOD 3) x2 ≡ 0 (MOD 3) x3 ≡ 0 (MOD 3)
x1 ≡ 0 (MOD 5) x2 ≡ 1 (MOD 5) x3 ≡ 0 (MOD 5)
x1 ≡ 0 (MOD 7) x2 ≡ 0 (MOD 7) x3 ≡ 1 (MOD 7)
就第一组x1的同余方程来说,它的解是5*7*n1
n1*35 ≡ 1 (MOD 3)
也就是 n1*2 ≡ 1 (MOD 3)
n1 == 2,x1 == 70
同理得到n2 == 1,x2 == 21,n3 == 1,x3 == 15
因为要求的余数为2,3,2,分别将x1,x2,x3乘上对应的余数
再把得到的x1*2,x2*3,x3*2加起来就好了,这样的得到的就是一种解
希望求最小正整数解,把得到的数模上3,5,7的最小公倍数就好了
推广到其他的情形,需要解这样的一组同余方程
x ≡ k1 (MOD p1)
x ≡ k2 (MOD p2)
......
x ≡ kn (MOD pn)
(其中p1,p2,......,pn之间两两互质)
求出它们的最大公因数M == ∏ki=1?pi (因为这些数两两互质)
则对于每一个数p,p与M/p的最大公因数为1
使用拓展欧几里得算法求出一组x,y,使得M/p*x + p*y ≡ 1 (MOD M)
留下来x就好,y不用管了
x == (x1*p1*k1 + x2*p2*k2 + ...... + xn*pn*kn) MOD M
这样就算好啦
代码如下:
C++:
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 int const MAXN=10010; 6 int x,y; 7 int k;//k组同余方程 8 int a[MAXN];//每个同余方程的余数 9 int b[MAXN];//每个同余方程的模数 10 int ans; 11 int lcm=1; 12 13 void exgcd(int a,int b) 14 { 15 if(b==0){x=1;y=0;} 16 else{ 17 exgcd(b,a%b); 18 int tmp=x; 19 x=y;y=tmp-a/b*y; 20 } 21 return; 22 } 23 24 int main(int argc,char *argv[],char *enc[]) 25 { 26 scanf("%d",&k); 27 for(int i=1;i<=k;++i) 28 scanf("%d%d",&b[i],&a[i]); 29 30 for(int i=1;i<=k;++i) 31 lcm*=b[i]; 32 for(int i=1;i<=k;++i) 33 { 34 exgcd(lcm/b[i],b[i]); 35 x=(x%b[i]+b[i])%b[i]; 36 37 ans=(ans+(lcm/b[i])*x*a[i])%lcm; 38 } 39 40 printf("%d",ans); 41 return 0; 42 }
Java:
1 import java.io.*; 2 import java.util.*; 3 4 class pony{ 5 6 static int MAXN=10010; 7 static int x,y; 8 static int k;//k组同余方程 9 static int[] a=new int[MAXN];//每个同余方程的余数 10 static int[] b=new int[MAXN];//每个同余方程的模数 11 static int ans; 12 static int lcm=1; 13 14 static void exgcd(int a,int b) 15 { 16 if(b==0){x=1;y=0;} 17 else{ 18 exgcd(b,a%b); 19 int tmp=x; 20 x=y;y=tmp-a/b*y; 21 } 22 return; 23 } 24 25 public static void main(String[] args) throws Exception { 26 27 Scanner cin=new Scanner(System.in); 28 29 k=cin.nextInt(); 30 for(int i=1;i<=k;++i) 31 { 32 b[i]=cin.nextInt(); 33 a[i]=cin.nextInt(); 34 } 35 36 for(int i=1;i<=k;++i) 37 lcm*=b[i]; 38 for(int i=1;i<=k;++i) 39 { 40 exgcd(lcm/b[i],b[i]); 41 x=(x%b[i]+b[i])%b[i]; 42 43 ans=(ans+(lcm/b[i])*x*a[i])%lcm; 44 } 45 46 System.out.println(ans); 47 } 48 }
因为两两互质,最小公倍数就是这些数的积,我在对唯一分解定理的研究中提到过
拓展中国剩余定理
以上方法仅仅适用于每个模数两两互质的情况
但是最常见的情况还是所有模数不满足两两互质
这样的话,中国剩余定理就不再适用
需要使用[?]拓展中国剩余定理
标签:enc lcm can 之一 math 复习 static std play
原文地址:https://www.cnblogs.com/Antigonae/p/10129122.html