写完扩展欧几里得就要顺便写一下中国剩余定理。
首先,什么是中国剩余定理:中国最早提出来的,又名孙子定理的一个求一次同余方程组的方法。
对,就长上面这个样子(这是百度百科复制的图片)。看起来很复杂,那要怎么求解呢?
中国剩余定理的最早版本是有所有m互质的前提的,所以就来讲一讲如何处理互质的情况。
令N[i]能被m[1]、m[2]、...、m[i-1]、m[i+1]、...、m[n]整除,但除m[i]后余1.
令M为数组m的最小公倍数。
那么x=Σ(N[i]*a[i])+t*M为所有解,t为整数。
此时我们就得到了解。但是,N数组怎么求呢?
设x为一个数,y为一个数
N[i]能被m[1]、m[2]、...、m[i-1]、m[i+1]、...、m[n]整除,所以N[i]=M/m[i]*x
N[i]除m[i]后余1,所以N[i]=m[i]*y+1
联立以上两方程,可以得到,M/m[i]*x-m[i]*y=1,这个方程用扩展欧几里得很容易可以得到一组解。
得到解后就可以得到N[i]了,最后注意细节就好了。
HDU 1370为模板题。
#include <cstdio>
#define FOR(i, x, y) for(int i = x; i <= y; ++i)
int t, n, k, ans, M, day, a[20], m[20];
int e_gcd(int a, int b, int &x, int &y)//参数可为负数的扩展欧几里德定理
{
if(b == 0)
{
x = 1;
y = 0;
return a;
}
int ans = e_gcd(b, a%b, x, y);
int temp = x;
if(a * b < 0)
{
x = -y;
y = a / b * y - temp;
}else
{
x = y;
y = temp - a / b * y;
}
return ans;
}
int CRT(int a[], int m[], int k)//Chinese Remainder theory
{
int ans = 0;
M = 1;//最小公倍数
FOR(i, 0, k-1) M *= m[i];
FOR(i, 0, k-1)
{
int x, y, temp = M / m[i];
e_gcd(temp, m[i], x, y);
ans = (ans + a[i] * temp * x) % M;
}
return (ans % M + M) % M;
}
int main()
{
scanf("%d", &t);
while(t--)
{
FOR(i, 1,100000)
{
m[0] = 23; m[1] = 28; m[2] = 33;
FOR(j, 0, 2) scanf("%d", &a[j]);
if(a[0] == -1) break;
scanf("%d", &day);
ans = CRT(a, m, 3);
while(ans <= day) ans += M;
printf("Case %d: the next triple peak occurs in %d days.\n", i, ans-day);
}
}
return 0;
}