藍橋杯 矩陣翻硬幣
矩陣翻硬幣
本文轉自 https://blog.csdn.net/xiaofengcanyuelong/article/details/79255105
小明先把硬幣擺成了一個 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次方)。
資源約定:
峰值內存消耗(含虛擬機) < 256M
CPU消耗 < 2000ms
請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多余內容。
題解:
Q 操作的定義:將所有第 i*x 行,第 j*y 列的硬幣進行翻轉。
(一)、找規律。
1、先看1行m列的矩陣,因為只有1行,當對其進行Q操作的時候,i和x都只能為1,
假設m為5,在對1行5列的矩陣的每個元素進行了Q操作後,推導過程如下:
初始狀態:1 1 1 1 1
對(1,1)元素進行Q操作,此時變成0 0 0 0 0
對(1,2)元素進行Q操作,此時變成0 1 0 1 0
對(1,3)元素進行Q操作,此時變成0 1 1 1 0
對(1,4)元素進行Q操作,此時變成0 1 1 0 0
對(1,5)元素進行Q操作,此時變成0 1 1 0 1
綜上,可以看出,這五個元素分別翻轉了1,2,2,3,2次,很明顯,當進行奇數次翻轉後為0,當進行偶數次翻轉後變為1。那麽,我們如果要求最終有幾個0,便是求有幾個位置可以進行奇數次翻轉。
首先,設1<=x<=m,對於(1,m)矩陣中的(1,x)硬幣,它翻轉了奇數次呢?還是偶數次呢?這時回看到Q操作的定義,會發現這樣一個規律:(1,x)位置翻轉的次數等於x的約數個數,且當x=k^2(k=1,2,3,4,5,6)時,翻轉次數為奇數次,否則為偶數次。
如1行5列矩陣中:
1的約數只有1個,因此(1,1)翻轉了1次,
2的約數有2個,因此(1,2)翻轉了2次,
3的約數有2個,因此(1,3)翻轉了2次,
4的約數有3個,因此(1,4)翻轉了3次,
5的約數有2個,因此(1,5)翻轉了2次。
當k=1,2時,即x=1,4時翻轉奇數次,其他為偶數次。
綜上,一個(1,m)矩陣在對每一個元素都進行Q操作後,0的個數為根號下m。
2、那麽(n,m)矩陣呢?這裏不再贅述,找個簡單的矩陣再走一遍流程就會得到下面的結論。
一個(n,m)矩陣在對每一個元素都進行Q操作後,0的個為根號下n乘以根號下m
參考:http://blog.csdn.net/snailset/article/details/26752435
(二)、處理大數開根。
對於100%的數據,n、m <= 10^1000(10的1000次方)。
n,m的最大值是10^1000次方,那麽普通的開根已經不適用於這種情況了,在Java中有BigInteger和BigDecimal可以滿足這樣大數開根的需求。
參考:https://www.cnblogs.com/Annetree/p/6664383.html
最後得出以下代碼:
1 public class Demo {
2
3 public static void main(String[] args) {
4
5 Scanner scanner = new Scanner(System.in);
6 BigInteger n = scanner.nextBigInteger();
7 BigInteger m = scanner.nextBigInteger();
8 BigInteger tem = sqrt(n).multiply(sqrt(m));
9 System.out.println(tem);
10
11 }
12 //大數開根--->折半查找法
13 static BigInteger sqrt(BigInteger x) {
14 BigInteger l = BigInteger.ONE;
15 BigInteger r = x;
16 BigInteger temp = BigInteger.ZERO;// 0
17 while (!l.equals(r)) {
18 BigInteger mid = (l.add(r)).divide(BigInteger.valueOf(2));// (l+r)/2
19 // temp!=0&&temp==mid---->mid!=0
20 if (temp.compareTo(BigInteger.ZERO) != 0 && temp.compareTo(mid) == 0) {
21 break;
22 } else {
23 temp = mid;
24 }
25 if (temp.compareTo(BigInteger.ZERO) == 0) {
26 temp = mid;
27 }
28 // mid*mid>x
29 if (mid.multiply(mid).compareTo(x) == 1) {
30 r = mid;
31 } else {
32 l = mid;
33 }
34 }
35 if (l.multiply(l).compareTo(x) == 1) {
36 l = l.subtract(BigInteger.ONE);
37 }
38 return l;
39
40 }
41 }
藍橋杯 矩陣翻硬幣