浙江大學校園裏綠樹成蔭,環境很是溫馨,所以也引來一批動物朋友來此居住。
童心未泯的NowCoder就常常帶些碎麪包什麼的去廣場喂鴿子和兔子,並和它們玩耍。 一點也沒有大學生的樣子,仍是一副老不正經的樣子,呵呵。
隨着鴿子和兔子數目的增多,NowCoder帶的那點食物已經不夠它們瓜分了。爲了能讓本身的好朋友吃的飽飽的, NowCoder決定統計一下有多少隻鴿子和有多少隻兔子,以便帶來足夠的食物。1、2、3、4、五…他開始數了。
如今,他已經知道有這些鴿子和兔子一共有n個頭和m只腳。請你幫他寫個程序計算一下一共有多少隻鴿子和兔子。java
輸入包括多組數據。
每行包括2個正整數n和m,n和m可能會很大,超過2^64,但位數不超過100位。算法
每組數據的輸出都只有一行,分別是鴿子的數量和兔子數量。
若是輸入的測試數據不能求得結果,那確定是NowCoder這個馬大哈數錯了,就輸出「Error」提示他。數組
35 94 1 3
23 12 Error
假設有x只鴿子,y只兔子,它們的頭和腳的數目分別是m和n。則有:app
{x+y=m2x+4y=n⟺{x=4m−n2y=n−2m2x∈Ny∈N ide
x和y都是天然數⇒n爲偶數,x=4m−n2⇒4m−n爲偶數(必定成立,由於n爲偶數),y=n−2m2⇒n−2m爲偶數(必定成立,由於n爲偶數)。同時由於m和n很是大,要使用大整數進行操做。測試
import java.util.Scanner; /** * Declaration: All Rights Reserved !!! */ public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); // Scanner scanner = new Scanner(Main.class.getClassLoader().getResourceAsStream("data.txt")); while (scanner.hasNext()) { String m = scanner.next(); String n = scanner.next(); String[] r = pigeonAndRabbit(m, n); if (r == null) { System.out.println("Error"); } else { System.out.println(r[0] + " " + r[1]); } } scanner.close(); } /** * 計算鴿子和兔子的數目 * * @param ms 鴿子和兔子的頭數 * @param ns 鴿子和兔子的腳數 * @return 長度爲2的數符串,分別表示鴿子的數量和兔子數量,若是無解就返回null */ private static String[] pigeonAndRabbit(String ms, String ns) { int lastN = ns.charAt(ns.length() - 1) - '0'; // ns爲偶數 if (lastN % 2 != 0) { return null; } int[] m = getNumber(ms); int[] n = getNumber(ns); // 鴿子數 // 4 * m int[] x = multiply(m, new int[]{4}); // 兔子數 // 2 * m int[] y = multiply(m, new int[]{2}); // 4m >= n && n >= 2m if (compare(x, n) >= 0 && compare(n, y) >= 0) { // 4m - n x = minus(x, n); // (4m - n) / 2 x = divide2(x); // n - 2m y = minus(n, y); // (n - 2m) / 2 y = divide2(y); return new String[]{toNumber(x), toNumber(y)}; } else { return null; } } /** * 將整數字符串表示成整數數組 * * @param n 整數字符串 * @return 整數數組 下標從小到大表示數位的從低到高 */ private static int[] getNumber(String n) { int[] r = new int[n.length()]; for (int i = 0; i < r.length; i++) { r[i] = n.charAt(n.length() - i - 1) - '0'; } return r; } /** * 兩個數相乘 * * @param m 乘數 * @param n 乘數 * @return 結果 */ private static int[] multiply(int[] m, int[] n) { // 結果最多的位數 int[] r = new int[m.length + n.length]; // 來自低位的進位 int c; int t; int k; for (int i = 0; i < n.length; i++) { // 計算n[i]*m if (n[i] == 0) { continue; } c = 0; for (int j = 0; j < m.length; j++) { t = n[i] * m[j] + r[i + j] + c; r[i + j] = t % 10; c = t / 10; } // 若是還有進位要繼續處理 k = i + m.length; while (c != 0) { t = c + r[k]; r[k] = t % 10; c = t / 10; k++; } } return r; } /** * 兩個整數相加 * * @param m 整數 * @param n 整數 * @return 結果 */ private static int[] add(int[] m, int[] n) { // 保證n不小於m if (m.length > n.length) { int[] t = m; m = n; n = t; } // 結果的最大長度 int[] r = new int[n.length + 1]; // 來自低位的進位 int c = 0; for (int i = 0; i < m.length; i++) { r[i] = m[i] + n[i] + c; c = r[i] / 10; r[i] %= 10; } // 計算餘下的部分 for (int i = m.length; i < n.length; i++) { r[i] = n[i] + c; c = r[i] / 10; r[i] %= 10; } // 最後還有進位 if (c != 0) { r[r.length - 1] = c; return r; } // 沒有進位 else { int[] ret = new int[r.length - 1]; System.arraycopy(r, 0, ret, 0, ret.length); return ret; } } /** * 比較兩個整數是否相等,下標由小到大表示由低位到高位,忽略最高有效位上的前導0 * * @param m 整數 * @param n 整數 * @return m > n返回1,m = n返回0,m < n返回-1 */ private static int compare(int[] m, int[] n) { if (m == null && n == null) { return 0; } // null最小 if (m == null) { return -1; } if (n == null) { return 1; } int lastM = m.length - 1; int lastN = n.length - 1; // 找m的最高有效位的位置,至少有一位 while (lastM >= 1 && m[lastM] == 0) { lastM--; } // 找n的最高有效位的位置,至少有一位 while (lastN >= 1 && n[lastN] == 0) { lastN--; } // m的數位比n多,說明m比n大 if (lastM > lastN) { return 1; } // m的數位比n少,說明m比n小 else if (lastM < lastN) { return -1; } else { // 位數同樣,比較每個數位上的值,從高位到低位進行比較 for (int i = lastM; i >= 0; i--) { if (m[i] > n[i]) { return 1; } else if (m[i] < n[i]) { return -1; } } return 0; } } /** * 作減法n-m,保證n大於等於m * * @param n 整數 * @param m 整數 * @return 結果 */ private static int[] minus(int[] n, int[] m) { n = format(n); m = format(m); int[] r = new int[n.length]; // 當前位被借位 int c = 0; int t; for (int i = 0; i < m.length; i++) { t = n[i] - c - m[i]; // 當前位夠減 if (t >= 0) { r[i] = t; // 沒有進行借位 c = 0; } // 不夠減 else { r[i] = t + 10; // 進行借位 c = 1; } } // 還有借位 for (int i = m.length; c != 0 && i < n.length; i++) { t = n[i] - c; // 當前位夠減 if (t >= 0) { r[i] = t; // 沒有進行借位 c = 0; } // 不夠減 else { r[i] = t + 10; // 進行借位 c = 1; } } return format(r); } /** * 將整數進行格式化,去掉高位的前導0 * * @param r 整數 * @return 結果 */ private static int[] format(int[] r) { int t = r.length - 1; // 找最高有效位 while (t > 0 && r[t] == 0) { t--; } int[] nr = new int[t + 1]; System.arraycopy(r, 0, nr, 0, nr.length); return nr; } /** * 將數n除以2 * * @param n 整數 * @return 結果 */ private static int[] divide2(int[] n) { // 結果 int[] r = new int[n.length]; // 上一位除以2後的餘數 int c = 0; int t; for (int i = n.length - 1; i >= 0; i--) { t = c * 10 + n[i]; r[i] = t / 2; c = t % 2; } return format(r); } /** * 將數組表示的整數轉換成字符串 * * @param r 整數 * @return 字符串表示的整數 */ private static String toNumber(int[] r) { if (r == null) { return null; } StringBuilder b = new StringBuilder(r.length); for (int i = r.length - 1; i >= 0; i--) { b.append(r[i]); } return b.toString(); } }