在做POJ 上的1006题目时,发现总是做不对,给的测试用例能完全正确,但是总是得到Wrong Anser结果。郁闷之极,搜了下高人提示:中国剩余定理。在看定理的过程中,自己用推到的4元一次方程,成功求出,并且很容易理解。记录下来供大家共享。
题目1006:
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 83990 | Accepted: 25414 |
Description
Input
Output
Sample Input
0 0 0 0 0 0 0 100 5 20 34 325 4 5 6 7 283 102 23 320 203 301 203 40 -1 -1 -1 -1
Sample Output
Case 1: the next triple peak occurs in 21252 days. Case 2: the next triple peak occurs in 21152 days. Case 3: the next triple peak occurs in 19575 days. Case 4: the next triple peak occurs in 16994 days. Case 5: the next triple peak occurs in 8910 days. Case 6: the next triple peak occurs in 10789 days.
Source
import java.util.Scanner; public class Main { public static final int CYCLE_P = 23; public static final int CYCLE_E = 28; public static final int CYCLE_I = 33; public static void main(String[] args) { int p, e, i, d; StringBuilder buffer = new StringBuilder(512); Scanner input = new Scanner(System.in); for (int j = 1; true; j++) { p = input.nextInt(); e = input.nextInt(); i = input.nextInt(); d = input.nextInt(); if (p < 0) { break; } int days = getTriplePeak(p, e, i, d); buffer.append("Case ").append(j).append( ": the next triple peak occurs in ").append(days).append( " days.\n"); } System.out.println(buffer.toString()); input.close(); } /** * 返回从current天开始,要到三个都达到顶峰还要等待的天数。 * * @param p * @param e * @param i * @return */ public static int getTriplePeak(int p, int e, int i, int d) { int peak = 0; p %= CYCLE_P; e %= CYCLE_E; i %= CYCLE_I; for (peak = i; peak <= d; peak += CYCLE_I) ; for (; peak % CYCLE_P != p || peak % CYCLE_E != e; peak += CYCLE_I) ; return peak - d; } }
23*x + p = t; -----(1) 28*y + e = t; -----(2) 33*z + i = t; -----(3)
23*28*33*x + 28*33*p = 28*33*t; ---(5)(2) 式乘以23*33得到:
23*28*33*y + 23*33*e = 23*33*t; ---(6)(3)式乘以23*28得到:
23*28*33*z + 23*28*i = 23*28*t; ---(7)
t= (23*28*33*(x+y+z)+(28*33*p+23*33*e+23*28*i))/(28*33+23*33+23*28); ----(9)进一步化简:
t= (23*28*33*(m)+(28*33*p+23*33*e+23*28*i))/(28*33+23*33+23*28); ----(10) 其中m为整数,t为整数;根据(10)式,编写代码求解。
import java.util.Scanner; public class Main { public static final int CYCLE_P = 23; public static final int CYCLE_E = 28; public static final int CYCLE_I = 33; public static final int A = CYCLE_E * CYCLE_I; public static final int B = CYCLE_P * CYCLE_I; public static final int C = CYCLE_P * CYCLE_E; public static final int N = A + B + C; public static final long COMMON = CYCLE_P * CYCLE_E * CYCLE_I; public static void main(String[] args) { dealWithInput(); } public static void dealWithInput() { int p, e, i, d; StringBuilder buffer = new StringBuilder(512); Scanner input = new Scanner(System.in); for (int j = 1; true; j++) { p = input.nextInt(); e = input.nextInt(); i = input.nextInt(); d = input.nextInt(); if (p < 0) { break; } long days = getTriplePeak(p, e, i, d); buffer.append("Case ").append(j).append( ": the next triple peak occurs in ").append(days).append( " days.\n"); } System.out.println(buffer.toString()); input.close(); } /** * 返回从current天开始,要到三个都达到顶峰还要等待的天数。 * * @param p * @param e * @param i * @return */ public static long getTriplePeak(int p, int e, int i, int d) { long temp = 0, m = 0; p %= CYCLE_P; e %= CYCLE_E; i %= CYCLE_I; m = A * p + B * e + C * i; for (temp = m; true; temp += COMMON) { if (temp % N == 0) { long result = temp / N - d; if (result > COMMON) return result % COMMON; else if (result <= 0) return result + COMMON; else return result; } } } }
一般地,中国剩余定理是指若有一些两两互质的整数 ,则对任意的整数:a1,a2,...an,以下联立同余方程组对模 有公解:
为了便于表述,对任意的正整数用一个常用函数ζi,j表示,称之为克罗内克符号(Kronecker).定义:
使用该符号,即可给出上述一般同余方程组的求解过程,分两步完成
import java.util.Scanner; public class Main { public static final int CYCLE_P = 23; public static final int CYCLE_E = 28; public static final int CYCLE_I = 33; public static final int A = CYCLE_E * CYCLE_I; public static final int B = CYCLE_P * CYCLE_I; public static final int C = CYCLE_P * CYCLE_E; public static final long LCM = CYCLE_P * CYCLE_E * CYCLE_I; private static final int a; private static final int b; private static final int c; static { int temp = 0; int ra = A % CYCLE_P, rb = B % CYCLE_E, rc = C % CYCLE_I; // get a for (temp = CYCLE_P + 1; true; temp += CYCLE_P) { if (temp % ra == 0) { a = temp / ra; break; } } // get b for (temp = CYCLE_E + 1; true; temp += CYCLE_E) { if (temp % rb == 0) { b = temp / rb; break; } } // get c for (temp = CYCLE_I + 1; true; temp += CYCLE_I) { if (temp % rc == 0) { c = temp / rc; break; } } } public static void main(String[] args) { int p, e, i, d; StringBuilder buffer = new StringBuilder(512); Scanner input = new Scanner(System.in); for (int j = 1; true; j++) { p = input.nextInt(); e = input.nextInt(); i = input.nextInt(); d = input.nextInt(); if (p < 0) { break; } long days = getTriplePeak(p, e, i, d); buffer.append("Case ").append(j).append( ": the next triple peak occurs in ").append(days).append( " days.\n"); } System.out.println(buffer.toString()); input.close(); } /** * 返回从current天开始,要到三个都达到顶峰还要等待的天数。 * * @param p * @param e * @param i * @return */ public static long getTriplePeak(int p, int e, int i, int d) { p %= CYCLE_P; e %= CYCLE_E; i %= CYCLE_I; long peak = a * A * p + b * B * e + c * C * i; peak %= LCM; peak -= d; if (peak <= 0) return peak + LCM; else return peak; } }