题目链接:http://poj.org/problem?id=1006
题目大意:
人体有三个周期,23,28,33. 对于每个周期分别给出从第0天开始,这三个周期的高潮出现的一个日期,不一定是第一次,p , e , i 。给出一个天数 d 表示今年已经过去了多少天,计算在这 d 天之后,三个高潮同时出现的那一天距离现在还有多少天。
思路:
23, 28, 33 是两两互素的,题目意思就是求一个数字 x ,使得这个数字 x 和 p 对23同余,同时 x 和 e 对28同余,同时 x 和 i 对33同余。所以可以用中国剩余定理解。
这是一个同余方程组。 x = p(mod 23); x = e (mod 28); x = i(mod 33); 这里的'='代表同余符号。
因为求的是大于d的,所以,当求得的解小于等于d的时候,要加上模 23*28*33;直到解大于d为止。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cctype> 6 #include <stack> 7 #include <queue> 8 #include <map> 9 #include <set> 10 #include <vector> 11 #include <cmath> 12 #include <algorithm> 13 #define lson l, m, rt<<1 14 #define rson m+1, r, rt<<1|1 15 using namespace std; 16 typedef long long int LL; 17 const int MAXN = 0x3f3f3f3f; 18 const int MIN = -0x3f3f3f3f; 19 const double eps = 1e-9; 20 const int dir[8][2] = {{0,1},{1,0},{0,-1},{-1,0},{-1,1}, 21 {1,1},{1,-1},{-1,-1}}; 22 int d, p, e, i, m[4], a[4]; 23 LL M, Mi; 24 void exgcd(int a, int b, int &d, int &x, int &y){ 25 if (!b){ 26 x = 1; y = 0; d = a; return; 27 }else{ 28 exgcd(b, a % b, d, x, y); 29 int tem = x; x = y; y = tem - (a / b) * y; 30 } 31 } 32 33 int china(int r){ 34 int ans = 0, d, x0, y0; 35 for (int i = 1; i <= r; ++i){ 36 M *= m[i]; 37 } 38 for (int i = 1; i <= r; ++i){ 39 Mi = M / m[i]; exgcd(Mi, m[i], d, x0, y0); 40 ans = (ans + a[i] * Mi * x0) % M; 41 } 42 if (ans < 0) ans += M; 43 return ans; 44 } 45 46 int main(void){ 47 #ifndef ONLINE_JUDGE 48 freopen("poj1006.in", "r", stdin); 49 #endif 50 int t = 1; 51 while (~scanf("%d%d%d%d", &p, &e, &i, &d)){ 52 M = 1; 53 if (p+e+i+d==-4) break; 54 m[1] = 23; m[2] = 28; m[3] = 33; 55 a[1] = p; a[2] = e; a[3] = i; 56 int ans = china(3); 57 while (ans <= d) ans += M; 58 printf("Case %d: the next triple peak occurs in %d days.\n", t,ans-d); 59 t++; 60 } 61 62 return 0; 63 }
中国剩余定理的模板抄的书上的,写代码的时候,竟然把扩展欧几里德写错了……找了好久才发现