1. 程式人生 > >藍橋杯歷屆試題----矩陣翻硬幣

藍橋杯歷屆試題----矩陣翻硬幣

矩陣翻硬幣

問題描述

小明先把硬幣擺成了一個 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次方)

思路分析:小M的思路確實能夠解決這個問題,但是我們看看下面的資料規模就可以發現,這種方法是不能解決100%的問題的。資料量太龐大了,暴力的方式必然出不來結果。

如果一個硬幣反轉了n次後正面朝上,且初始狀態為反面朝上,那麼n一定是個奇數。根據題意“ 對第x行第y列的硬幣進行 Q 操作的定義:將所有第 i*x 行,第 j*y 列的硬幣進行翻轉”。我們逆向的理解這個意思,對與一個橫座標為x的硬幣而言,我們反轉那些硬幣時會需要翻轉它呢?答案是橫座標的x的約數。例如x=9時,翻轉橫座標為1,3,9的時候會影響它的翻轉,縱座標同理。

那麼這個題目我們就可以通過求解擁有奇數個約數的數來實現,在數學上這種數字又叫做完全平方數。即1,4,9,16,25......(2^n)

我們知道矩陣的行號和列號是從1開始的,橫座標1-n,縱座標1-m,那麼我們需要解決的及時其間的完全平方數的個數問題,最後相乘即可得到(相乘是因為橫座標的翻轉會影響縱座標,縱座標的翻轉也會影響橫座標)。

注意:這裡會涉及到大數開方的問題,不理解的讀者可以參考JAVA應試技巧----大數開方,還要注意在儲存資料時採用的變數型別,以及資料之間的轉換。

import java.math.BigInteger;
import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
    	Scanner in = new Scanner(System.in);
        String n = in.next();
        String m = in.next();
        BigInteger ans = (sqrt(n)).multiply(sqrt(m));
        System.out.println(ans);
    }
    private static BigInteger sqrt(String num) {
        int length = num.length();     
        int sqrt_len = 0;
//        獲取長度
        if(length % 2 == 0) {
            sqrt_len = length / 2;
        } else {
            sqrt_len = length / 2 + 1;
        }
        BigInteger beSqrtNum = new BigInteger(num);
        char[] ch = new char[sqrt_len];      
        Arrays.fill(ch, '0');   
        for(int i = 0; i < sqrt_len; i++) {         
            for(char j = '1'; j <= '9'; j++ ) {
                ch[i] = j;
                String s = String.valueOf(ch);
                BigInteger sqrtNum = new BigInteger(s);
                BigInteger squareNum = sqrtNum.multiply(sqrtNum);
                if(squareNum.compareTo(beSqrtNum) == 1) {
                    ch[i] -= 1;
                    break;
                }
            }
        }
        return new BigInteger(String.valueOf(ch));
    }
}