题目传送门
http://poj.org/problem?id=1006
思路
中国剩余定理果题。
求 x≡ai(modmi) 的最小正整数解。
简要说一下步骤,证明什么的网上有很多,不再赘述。
首先令 M=∏mi ,令 Mi=Mmi ,求出 Mi 的某个倍数使得其满足模 mi 等于 ai ,即 kMi≡ai(modmi) ,发现 k≡aiM−1i(modmi) ,于是 kMi≡aiMiM−1i(modmi) ,其中 M−1i 是 Mi 关于 mi 的逆元。(正确性其实是显然的)
将所有求得的数相加得到一解,尽可能减去所有 mi 的 lcm 即得最小解。
答案就是一条公式:
ans=∑aiMiM−1imodM
注意答案要大于0。(话说本题暴力也可以)
代码
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
int d, Case, ans, MOD = 21252;
int m[5] = {0, 23, 28, 33}, M[5] = {0, 21252/23, 21252/28, 21252/33};
int A[5], InvM[5];
void Exgcd(int a, int b, int& x, int& y){
if(!b){
x = 1;
y = 0;
return;
}
Exgcd(b, a % b, y, x);
y -= x * (a / b);
}
int CRT(){
int x, y;
for(int i = 1; i <= 3; i++){
Exgcd(M[i], m[i], x, y);
InvM[i] = (x % m[i] + m[i]) % m[i];
}
int res = 0;
for(int i = 1; i <= 3; i++)
res = (res + A[i] * M[i] % MOD * InvM[i] % MOD) % MOD;
return res;
}
int main(){
for(;;){
for(int i = 1; i <= 3; i++) scanf("%d", &A[i]);
if(A[1] == -1) break;
scanf("%d", &d);
ans = CRT() - d;
if(ans <= 0) ans += MOD;
printf("Case %d: the next triple peak occurs in %d days.\n", ++Case, ans);
}
return 0;
}
接下来要写三模数NTT。