版权声明:如需转载,记得标识出处 https://blog.csdn.net/godleaf/article/details/83004714
题目链接:http://poj.org/problem?id=1006
思路:
中国剩余定理总结:
n1, n2, n3; n % n1 = p; n % n2 = e; n % n3 = i;求最小正整数 n;
a * n2*n3 % n1 = 1; 等价于 a * n2*n3 - 1 = k * n1 ---> a * n2*n3 - k*n1 = 1; 通过扩展欧几里得求出 a ,exgcd (n2*n3, n1, a, k);
b * n1*n3 % n2 = 1; 等价于 b * n1*n3 - 1 = k * n2 ---> b * n1*n3 - k*n2 = 1; 同上求出 b ,exgcd (n1*n3, n2, b, k);
c * n1*n2 % n3 = 1; 等价于 c * n1*n2 - 1 = k * n3 ---> c * n1*n2 - k*n3 = 1;求出 c ,exgcd (n1*n2, n3, c, k);
因为扩展的欧几里得求出的值有可能是负数,通过取模的方式得出最小正整数解;比如 a = (a%n3 + n3) % n3;(即求a用k的系数取模,同理求k的最小正整数解就用a的系数取模)
则有 n = (a*n2*n3*p + b*n1*n3*e + c*n1*n2*i) % lcm (n1, n2, n3) ;
还有要注意的是:当求得的ans小于等于起始天数 d 的时候要 + lcm (n1, n2, n3);
#include <iostream>
using namespace std;
void exgcd (int a, int b, int &x, int &y) {
if (!b) {
x = 1; y = 0;
} else {
exgcd (b, a % b, y, x); y -= x*(a/b);
}
}
const int Mod = 21252; // lcm (23, 28, 33) 事先求出
int main (void)
{
int a, b ,c , k, p, e, i, d, cas = 0;
exgcd (28*33, 23, a, k); a = (a%23+23)%23;
exgcd (23*33, 28, b, k); b = (b%28+28)%28;
exgcd (23*28, 33, c, k); c = (c%33+33)%33;
while (cin >> p >> e >> i >> d) {
if (p == -1 && e == -1 && i == -1 && d == -1) break;
int ans = (a*p*28*33 + b*e*23*33 + c*i*28*23) % Mod;
ans -= d;
ans = ans <= 0 ? ans+Mod : ans; // ans 小于等于天数 d 要+Mod
cout << "Case " << ++cas << ": the next triple peak occurs in " << ans << " days." << endl;
}
return 0;
}