1. 程式人生 > >藍橋杯 矩陣翻硬幣

藍橋杯 矩陣翻硬幣

article compare 畫蛇添足 equals http 等於 最大值 行號 兩個

矩陣翻硬幣

本文轉自 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 }

藍橋杯 矩陣翻硬幣