POJ 1006 Biorhythms 【中国剩余定理】

版权声明:如需转载,记得标识出处 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;
 }

猜你喜欢

转载自blog.csdn.net/godleaf/article/details/83004714