1.什么是中国剩余定理?
这个问题困扰了窝好久,看了好多书上的解释,但都很片面地只进行了部分阐述...搞得我也是迷乱..
最后发现还是百度百科讲的最靠谱了...(也可能是看的多了自己就懂了吧..
百度百科上的所给的证明非常棒..浅显易懂!(窝都看懂了...
一发链接:孙子定理
然后还是说一下我的理解吧:下面这个一元线性同余方程组
对于这个方程,判断是否有解,如果有解,则求x的值。
首先若有解,则有很多个解(看百度百科中的证明..逃..
那么有节的条件是什么呢 答:整数m1,m2,m3……mn两两互质
解是什么? 方程组
其中:
*注意:
在模
的意义下,方程组
只有一个解:
具体证明
还是要看一下 百度百科的
2.对于这种m[]数组元素两两互质的情况的算法实现:
/*
fzu 1402
Andy建立了ai个猪圈,有bi头猪没有去处
输出包含一个正整数,即为Andy家至少养猪的数目
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
long long aa[15],bb[15];
long long extgcd(long long a, long long b, long long &x, long long &y){
long long d = a;
if(b != 0){
d = extgcd(b, a%b, y, x);
y -= (a / b) * x;
}
else{
x = 1; y = 0;
}
return d;
}
// 注意使用方法, 除以mi 余数是ai, 传参数的时候容易传错, 倒过来再试试
// 求解模线性方程组x = ai (mod mi)
long long China(long long a[], long long m[], int k)
{
long long M = 1;
long long ans = 0;
for(int i = 0; i < k; i++)
M *= m[i];
for(int i=0; i<k; i++){
long long x, y;
long long Mi = M / m[i];
extgcd(Mi, m[i], x, y);
ans = (ans + Mi * x * a[i]) % M;
}
if(ans < 0)
ans += M;
return ans;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i = 0; i < n; i++)
scanf("%I64d %I64d",&aa[i],&bb[i]);
printf("%I64d\n",China(bb, aa, n));
}
return 0;
}
3. 对于m[]数组元素 并非 两两互质的情况的算法实现:
/*
hdu 1573
求在小于等于N的正整数中有多少个X满足:
X mod a[0] = b[0], X mod a[1] = b[1], X mod a[2] = b[2], …, X mod a[i] = b[i], … (0 < a[i] <= 10)
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL __int64
#define M 10
int N;
long long extgcd(long long a, long long b, long long &x, long long &y){
long long d = a;
if(b != 0){
d = extgcd(b, a%b, y, x);
y -= (a / b) * x;
}
else{
x = 1; y = 0;
}
return d;
}
long long China(long long b[], long long n[], int num){
bool flag = false;
long long bb, d, t, k;
long long n1 = n[0], n2;
long long b1 = b[0], b2;
long long x, y;
for(int i = 1; i < num; i++){
n2 = n[i], b2 = b[i];
bb = b2 - b1;
d = extgcd(n1, n2, x, y);
if (bb % d){ //模线性解k1时发现无解
flag = true;
break;
}
k = bb / d * x; //相当于求上面所说的k1【模线性方程】
t = n2 / d;
if (t < 0) t = -t;
k = (k % t + t) % t; //相当于求上面的K`
b1 = b1 + n1*k;
n1 = n1 / d * n2;
}
if (flag)
return 0; //无解
/******************求正整数解******************/
if (b1 == 0) //如果解为0,而题目要正整数解,显然不行
b1 = n1; //n1刚好为所有ni的最小公倍数,就是解了
//形成的解:b1, b1+n1, b1+2n1,..., b1+xni...
/******************求正整数解******************/
if (b1 > N)
return 0;
return (N-b1)/n1+1;
}
int main()
{
int t, num, i, cc = 1;
LL b[M], n[M];
scanf ("%d", &t);
while (t--)
{
scanf ("%d%d", &N, &num);
for (i = 0; i < num; i++)
scanf ("%I64d", n+i);
for (i = 0; i < num; i++)
scanf ("%I64d", b+i);
printf ("%I64d\n", China(b, n, num));
}
return 0;
}
模板:
long long extgcd(long long a, long long b, long long &x, long long &y){
long long d = a;
if(b != 0){
d = extgcd(b, a%b, y, x);
y -= (a / b) * x;
}
else{
x = 1; y = 0;
}
return d;
}
//求模线性方程组x = bi (mod ni), ni可以不互质, num表示方程的数目
long long China(long long b[], long long n[], int num){
bool flag = false;
long long bb, d, t, k;
long long n1 = n[0], n2;
long long b1 = b[0], b2;
long long x, y;
for(int i = 1; i < num; i++){
n2 = n[i], b2 = b[i];
bb = b2 - b1;
d = extgcd(n1, n2, x, y);
if (bb % d){ //模线性解k1时发现无解
flag = true;
break;
}
k = bb / d * x; //相当于求上面所说的k1【模线性方程】
t = n2 / d;
if (t < 0) t = -t;
k = (k % t + t) % t; //相当于求上面的K`
b1 = b1 + n1*k;
n1 = n1 / d * n2;
}
if (flag)
return -1; //无解返回-1
return ((b1%n1)+n1)%n1; //这是返回的最小非负整数解
//形成的所有解:b1, b1+n1, b1+2n1,..., b1+xni...
/*
下面是求不大于N的解的个数
if (b1 > N)
return 0;
return (N-b1)/n1+1;
*/
}
中国剩余定理就先学习到这里吧~遇到题目再补充~