题意:POJ上有中文翻译,题目名称右面language可以选择简体中文。
用中国剩余定理可以轻松解决,主要靠这道题学了学中国剩余定理,然而只学会了怎么写,原理还是不太理解。
首先列出式子:
p + x1 * 23 = n;
e + x2 * 28 = n;
i + x3 * 33 = n;
输出ans = n - d % 21252;
方程组可以写为:
n ≡ p (mod 23);
n ≡ e (mod 28);
n ≡ i (mod 33);
中国剩余定理(维基百科)用于解一类一元一次同余方程组:
x ≡ a[1] (mod m[1]);
x ≡ a[2] (mod m[2]);
x ≡ a[3] (mod m[3]);
….
x ≡ a[n] (mod m[n]);
当对于任意i, j ∈ [1, n]时, m[i], m[j]互质,则对于任意a[i], i ∈ [1,n],原方程组有解:
设mul = m[1] * m[2] * m[3] …… * m[n]
设M[i] = mul / m[i];
设ni[i]为M[i] 在 mod m[i]下的逆元;
设t[i] = M[i] * ni[i];
则解为k * mul + Σt[i]*a[i], i ∈ [1, n], k ∈ Z;
这道题给21252的意思大概就是假设一年是21252天,答案对21252取模,不会出现第0天,所以ans==0输出21252。
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int d, w[4], m[4] = {0, 23, 28, 33}, mul, t[4], cnt;
void Exgcd(int a, int b, int &x, int &y){
if(!b) x = 1, y = 0;
else { Exgcd(b, a%b, y, x); y -= a/b*x;}
}
int get_ni(int a, int p)
{
int x, y;
Exgcd(a, p, x, y);
return (x+p)%p;
}
int main()
{
mul = 23*28*33;
for(int i = 1; i < 4; i++)
{
t[i] = get_ni(mul/m[i], m[i])*mul/m[i];
}
while(scanf("%d", w+1) && w[1] >= 0)
{
for(int i = 2; i < 4; i++) scanf("%d", w+i);
scanf("%d", &d);
for(int i = 1; i < 4; i++) w[i] %= m[i];
int ans = -d;
for(int i = 1; i < 4; i++) ans = (ans+w[i]*t[i])%21252;
while(ans <= 0) ans += 21252;
printf("Case %d: the next triple peak occurs in %d days.\n", ++cnt, ans);
}
return 0;
}