歷屆試題 矩陣翻硬幣 【java大數開方】
阿新 • • 發佈:2018-12-10
歷屆試題 矩陣翻硬幣
時間限制:1.0s 記憶體限制:256.0MB
問題描述
小明先把硬幣擺成了一個 n 行 m 列的矩陣。 隨後,小明對每一個硬幣分別進行一次 Q 操作。 對第x行第y列的硬幣進行 Q 操作的定義:將所有第 i*x 行,第 j*y 列的硬幣進行翻轉。 其中i和j為任意使操作可行的正整數,行號和列號都是從1開始。 當小明對所有硬幣都進行了一次 Q 操作後,他發現了一個奇蹟——所有硬幣均為正面朝上。 小明想知道最開始有多少枚硬幣是反面朝上的。於是,他向他的好朋友小M尋求幫助。 聰明的小M告訴小明,只需要對所有硬幣再進行一次Q操作,即可恢復到最開始的狀態。然而小明很懶,不願意照做。於是小明希望你給出他更好的方法。幫他計算出答案。
輸入格式
輸入資料包含一行,兩個正整數 n m,含義見題目描述。
輸出格式
輸出一個正整數,表示最開始有多少枚硬幣是反面朝上的。
樣例輸入
2 3
樣例輸出
1
資料規模和約定
對於10%的資料,n、m <= 10^3; 對於20%的資料,n、m <= 10^7; 對於40%的資料,n、m <= 10^15; 對於10%的資料,n、m <= 10^1000(10的1000次方)。
思路:
模擬一遍可以發現結果是求被翻了奇數次的硬幣數。奇數=奇數*奇數。最終反面朝上的硬幣為翻轉奇數次的行與翻轉奇數次的列的交點。所以答案就是翻轉奇數次的行數*翻轉奇數次的列數。很容易發現第n行的翻轉次數=n的因子數。而因子一般都是成對出現的,只有平方數會出現奇數個因子。所以如果行數為平方數,就會被翻奇數次。判斷一個數之前有多少個平方數直接開方取整即可。
這裡用到了大數開方。java沒有專門的方法,可以用二分進行開方。
程式碼:
import java.util.*; import java.math.*; public class Main { // 大數開方 static BigInteger Bigsqrt(BigInteger x) { BigInteger l = BigInteger.ONE; BigInteger r = x; BigInteger temp = BigInteger.ZERO; while (!l.equals(r)) { BigInteger mid = (l.add(r)).divide(BigInteger.valueOf(2)); if (temp.compareTo(BigInteger.ZERO) != 0 && temp.compareTo(mid) == 0) break; else temp = mid; if (temp.compareTo(BigInteger.ZERO) == 0) temp = mid; if (mid.multiply(mid).compareTo(x) == 1) r = mid; else l = mid; } if (l.multiply(l).compareTo(x) == 1) l = l.subtract(BigInteger.ONE); return l; } public static void main(String[] args) { Scanner cin = new Scanner(System.in); BigInteger n = cin.nextBigInteger(); BigInteger m = cin.nextBigInteger(); System.out.println(Bigsqrt(n).multiply(Bigsqrt(m))); } }