1. 程式人生 > >【藍橋杯題解】矩陣翻硬幣

【藍橋杯題解】矩陣翻硬幣

歷屆試題 矩陣翻硬幣
時間限制: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;
  對於100%的資料,n、m <= 10^1000(10的1000次方)
題目最終轉化求sqrt(n)*sqrt(m)(開方出來取整),由於題目資料太大(10的1000次方),因此實際考點是大數的開方和乘法:
大數乘法:模擬筆算即可

/*大數相乘函式
*知識點1:m位數和n位數相乘最多有n+m位數
*步驟1.移位操作
*步驟2.進位操作
*步驟3.去除高位0
*步驟4.轉化為字串
*/
string strMul(string a, string b)
{
    int len1 = a.length();
    int len2 = b.length();
    int i, j;
    vector<int>num(len1 + len2, 0);//最多len1+len2位
    //步驟一
    //遍歷相乘,i+j相等的要相加,暫存在num中,num中由低位到高位儲存,方便進位
    for (i = 0
; i<len1; i++) for (j = 0; j<len2; j++) { num[len1 - 1 + len2 - 1 - i - j] += (a[i] - '0')*(b[j] - '0'); } //步驟二 //進位操作,由低位向高位進位 for (i = 0; i<len1 + len2 - 1; i++) { num[i + 1] = num[i + 1] + num[i] / 10; num[i] = num[i] % 10; } //步驟三
//去除高位的多餘的零 i = len1 + len2 - 1; while (i>=0) { if (num[i] != 0) break; i--; } //步驟四 //將結果轉化成字串 string result = ""; while (i>=0) { result += num[i--] + '0'; } return result; }

大數開方:

/*
*知識點1:對n位數開方,開方出來的數的位數:n是偶數為n/2位,n是奇數為n/2+1位;
*知識點2:大數比較(見後面)
*步驟1:確定開方出來的數的位數
*步驟2:從高位向低位確定每一位的值
*/
string StrQurt(string a)
{
    int len = a.length();
    //對n位數開方,開方出來的數的位數:n是偶數為n/2,n是奇數為n/2+1;
    len = len % 2 == 0 ? len / 2 : len / 2 + 1;
    string ans = "";
    for (int i = 0; i < len;i++)
    {
        ans +='0';
        int j;
        //確定當前位從0-9遍歷判斷
        for (j = 0; j <= 9;j++)
        {
            ans[i] = j + '0';
            int key = StrCompare(StrMul(ans + string(len - 1 - i, '0'), ans + string(len - 1 - i, '0')), a);
            if (key == 0)return ans + string(len - 1 - i, '0');
            else if (key==1)break;
        }
        if (j<10)
            ans[i]--;
    }
    return ans;
}
/*大數比較函式
*a>b return 1
*a<b return -1
*a=b return 0
*/
int StrCompare(string a,string b)
{
    if (a.length() < b.length())
        return  -1;
    else if (a.length() > b.length())
        return  1;
    else        
        return a.compare(b);
}

題目到此基本已經沒有多大問題了,但是在確定開方數的每一位值時會花費大量的時間,因為後面有多個零做乘法,這是非常耗時的,提供兩個方法優化:
一、優化乘法演算法(網上有很多,自己找)
二、將零相乘的部分剔除開來,重新寫一個新的比較函式,傳入比較函式有三個引數StrCmp(已經確定的高位的值得乘方,2*未確定的低位0的個數,另一個要比較的數 )

//大數比較函式
int strCmp(string a, int pos, string b)
{
    int i;
    if (a.length() + pos>b.length())
        return 1;
    if (a.length() + pos<b.length())
        return -1;
    if (a.length() + pos == b.length())
    {
        for (i = 0; i<b.length(); i++)
        {
            if (i < a.length())
            {
                if (a[i]<b[i])
                    return -1;
                if (a[i] == b[i])
                    continue;
                if (a[i]>b[i])
                    return 1;
            }
            else
            {
                if (b[i]>'0')return -1;
            }

        }
    }
    return 0;
}

相應的開方函式為:

//大數開方函式
/*
*知識點1:對n位數開方,開方出來的數的位數:n是偶數為n/2位,n是奇數為n/2+1位;
*知識點2:大數比較
*步驟1:確定開方出來的數的位數
*步驟2:從高位向低位確定每一位的值
*/
string StrQurt(string a)
{
    int len = a.length();
    //對n位數開方,開方出來的數的位數:n是偶數為n/2,n是奇數為n/2+1;
    len = len % 2 == 0 ? len / 2 : len / 2 + 1;
    string ans = "";
    for (int i = 0; i < len;i++)
    {
        ans +='0';
        int j;
        //確定當前位從0-9遍歷判斷
        for (j = 0; j <= 9;j++)
        {
            ans[i] = j + '0';
            int key = strCmp(StrMul(ans, ans),2*(len-1-i),a);
            if (key == 0)return ans + string(len - 1 - i, '0');
            else if (key==1)break;
        }
        if (j<10)
            ans[i]--;
    }
    return ans;
}

完整程式碼如下:

#include<iostream>
#include<string>
#include<cstring>
#include <vector>
using namespace std;
//
///*
/*大數相乘函式
*知識點1:m位數和n位數相乘最多有n+m位數
*步驟1.移位操作
*步驟2.進位操作
*步驟3.去除高位0
*步驟4.轉化為字串
*/
string StrMul(string a, string b)
{
    int len1 = a.length();
    int len2 = b.length();
    int i, j;
    vector<int>num(len1 + len2, 0);//最多len1+len2位
    //步驟一
    //遍歷相乘,i+j相等的要相加,暫存在num中,num中由低位到高位儲存,方便進位
    for (i = 0; i<len1; i++)
        for (j = 0; j<len2; j++)
        {
            num[len1 - 1 + len2 - 1 - i - j] += (a[i] - '0')*(b[j] - '0');
        }
    //步驟二
    //進位操作,由低位向高位進位
    for (i = 0; i<len1 + len2 - 1; i++)
    {
        num[i + 1] = num[i + 1] + num[i] / 10;
        num[i] = num[i] % 10;
    }
    //步驟三
    //去除高位的多餘的零
    i = len1 + len2 - 1;
    while (i>=0)
    {
        if (num[i] != 0)
            break;
        i--;
    }
    //步驟四
    //將結果轉化成字串
    string result = "";
    while (i>=0)
    {
        result +=  num[i--] + '0';
    }
    return result;
}
//大數比較函式
int strCmp(string a, int pos, string b)
{
    int i;
    if (a.length() + pos>b.length())
        return 1;
    if (a.length() + pos<b.length())
        return -1;
    if (a.length() + pos == b.length())
    {
        for (i = 0; i<b.length(); i++)
        {
            if (i < a.length())
            {
                if (a[i]<b[i])
                    return -1;
                if (a[i] == b[i])
                    continue;
                if (a[i]>b[i])
                    return 1;
            }
            else
            {
                if (b[i]>'0')return -1;
            }

        }
    }
    return 0;
}
//大數開方函式
/*
*知識點1:對n位數開方,開方出來的數的位數:n是偶數為n/2位,n是奇數為n/2+1位;
*知識點2:大數比較
*步驟1:確定開方出來的數的位數
*步驟2:從高位向低位確定每一位的值
*/
string StrQurt(string a)
{
    int len = a.length();
    //對n位數開方,開方出來的數的位數:n是偶數為n/2,n是奇數為n/2+1;
    len = len % 2 == 0 ? len / 2 : len / 2 + 1;
    string ans = "";
    for (int i = 0; i < len;i++)
    {
        ans +='0';
        int j;
        //確定當前位從0-9遍歷判斷
        for (j = 0; j <= 9;j++)
        {
            ans[i] = j + '0';
            int key = strCmp(StrMul(ans, ans),2*(len-1-i),a);
            if (key == 0)return ans + string(len - 1 - i, '0');
            else if (key==1)break;
        }
        if (j<10)
            ans[i]--;
    }
    return ans;
}
int main()
{
    string a, b;
    while (cin >> a>>b)
    {
        cout << StrMul(StrQurt(a),StrQurt(b)) << endl;
    }
    return 0;
}

相關推薦

藍橋題解矩陣硬幣

歷屆試題 矩陣翻硬幣 時間限制:1.0s 記憶體限制:256.0MB 提交此題 問題描述   小明先把硬幣擺成了一個 n 行 m 列的矩陣。   隨後,小明對每一個硬幣分別進行一次 Q 操作。   對第x行第y列的硬幣進行 Q 操作的定義:將所有

藍橋_PREV-34_矩陣硬幣

問題描述   小明先把硬幣擺成了一個 n 行 m 列的矩陣。隨後,小明對每一個硬幣分別進行一次 Q 操作。對第x行第y列的硬幣進行 Q 操作的定義:將所有第 i*x 行,第 j*y 列的硬幣進行翻轉。其中i和j為任意使操作可行的正整數,行號和列號

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

矩陣翻硬幣問題描述小明先把硬幣擺成了一個 n 行 m 列的矩陣。隨後,小明對每一個硬幣分別進行一次 Q 操作。對第x行第y列的硬幣進行 Q 操作的定義:將所有第 i*x 行,第 j*y 列的硬幣進行翻轉。其中i和j為任意使操作可行的正整數,行號和列號都是從1開始。當小明對所有

第四屆藍橋第八題 硬幣

i++ nbsp ans namespace == pos else main 硬幣 題解:簡單貪心, 比賽之前寫寫水題 #include <iostream> #include <cstring> #include <strin

藍橋練習題取球博弈

         今盒子裡有n個小球,A、B兩人輪流從盒中取球,每個人都可以看到另一個人取了多少個,也可以看到盒中還剩下多少個,並且兩人都很聰明,不會做出錯誤的判斷。     我們約定:       

藍橋訓練--- 演算法訓練 Torry的困惑(基本型)

問題描述   Torry從小喜愛數學。一天,老師告訴他,像2、3、5、7……這樣的數叫做質數。Torry突然想到一個問題,前10、100、1000、10000……個質數的乘積是多少呢?他把這個

藍橋 歷屆試題 6.硬幣

/*問題描述小明正在玩一個“翻硬幣”的遊戲。桌上放著排成一排的若干硬幣。我們用 * 表示正面,用 o 表示反面(是小寫字母,不是零)。比如,可能情形是:**oo***oooo如果同時翻轉左邊的兩個硬幣,則變為:oooo***oooo現在小明的問題是:如果已知了初始狀態和要達到

藍橋練習題入門訓練

序列求和 問題描述 求1+2+3+…+n的值。 輸入格式 輸入包括一個整數n。 輸出格式 輸出一行,包括一個整數,表示1+2+3+…+n的值。 樣例輸入 4 樣例輸出 10 樣例輸入 100 樣例輸出 5050 資料規模與約定 1

歷屆試題 矩陣硬幣 java大數開方

  歷屆試題 矩陣翻硬幣   時間限制:1.0s   記憶體限制:256.0MB 問題描述   小明先把硬幣擺成了一個 n 行 m 列的矩陣。   隨後,小明對每一個硬幣分別進行一次 Q 操作。   對第x行第y列的硬幣進行 Q 操作的定義:將所有第 i*x 行,第

藍橋 歷屆試題 題解

PREV-1 核桃的數量 問題描述 小張是軟體專案經理,他帶領3個開發組。工期緊,今天都在加班呢。為鼓舞士氣,小張打算給每個組發一袋核桃(據傳言能補腦)。他的要求是: 1. 各組的核桃數量必須相同 2. 各組內必須能平分核桃(當然是不能打碎的) 3. 儘量提供滿

藍橋 矩陣硬幣(打表+二分)

網上其他人的答案好像都是用數學方法解決的。做這道題的時候一看就感覺是找規律的題,所以先打個表。因為後面要用到大數處理,所以是Java語言打表程式碼(就是按題目意思暴力):import java.io.FileNotFoundException; import java.io.

矩陣硬幣 藍橋 大數開方 大數相乘

問題描述   小明先把硬幣擺成了一個 n 行 m 列的矩陣。  隨後,小明對每一個硬幣分別進行一次 Q 操作。  對第x行第y列的硬幣進行 Q 操作的定義:將所有第 i*x 行,第 j*y 列的硬幣進行翻轉。  其中i和j為任意使操作可行的正整數,行號和列號都是從1開始

藍橋 矩陣硬幣

article compare 畫蛇添足 equals http 等於 最大值 行號 兩個 矩陣翻硬幣 本文轉自 https://blog.csdn.net/xiaofengcanyuelong/article/details/79255105 小明先把硬幣擺成了一個

藍橋矩陣硬幣(大數開根號)

  對於10%的資料,n、m <= 10^3;  對於20%的資料,n、m <= 10^7;  對於40%的資料,n、m <= 10^15;  對於10%的資料,n、m <= 10^1000(10的1000次方)。 我的思路:他是問翻之前有多少個硬幣是反面朝上的,所以這個反面朝上的

藍橋-矩陣硬幣

  小明先把硬幣擺成了一個 n 行 m 列的矩陣。   隨後,小明對每一個硬幣分別進行一次 Q 操作。   對第x行第y列的硬幣進行 Q 操作的定義:將所有第 i*x 行,第 j*y 列的硬幣進行翻轉。   其中i和j為任意使操作可行的正整數,行號和列號都是從1開始。   當小明對所有硬幣都進行了一次 Q

矩陣硬幣 數學 藍橋

    小明先把硬幣擺成了一個 n 行 m列的矩陣。隨後,小明對每一個硬幣分別進行一次 Q 操作。對第x行第y列的硬幣進行 Q 操作的定義:將所有第 i*x 行,第 j*y列的硬幣進行翻轉。其中i和j為任意使操作可行的正整數,行號和列號都是從1開始。    當小明對所有硬幣都進行了一次 Q操作後,他發現了一個

ShawnZhang帶你看藍橋——演算法訓練 矩陣乘法

【ShancoLove】帶你看藍橋杯——演算法訓練 矩陣乘法   問題描述   輸入兩個矩陣,分別是m*s,s*n大小。輸出兩個矩陣相乘的結果。 輸入格式   第一行,空格隔開的三個正整數m,s,n(均不超過200)。   接下來m行,每行s個空格隔開的整數,表示

藍橋打印十字圖(圖形規律)

clas pan dos nbsp har name can data 圖形 題目描述 小明為某機構設計了一個十字型的徽標(並非紅十字會啊),如下所示: ..$$$$$$$$$$$$$.. ..$...........$.. $$$.$$$$$$$$$.$$$

藍橋歷屆試題 發現環

ring bool include mes 16px 技術分享 div lte HR 題目:歷屆試題 發現環 問題描述   小明的實驗室有N臺電腦,編號1~N。原本這N臺電腦之間有N-1條數據鏈接相連,恰好構成一個樹形網絡。在樹形網絡上,任意兩臺電腦之間有唯一的路徑相連。 

藍橋單片機10串行接口的進階與實戰應用

而已 也有 案例 font enter 代碼塊 通知 基本原理 init 【藍橋杯單片機10】串行接口的進階與實戰應用 廣東職業技術學院 歐浩源 串行接口作為51單片機的重要外設,編程操作並不復雜,但在實際的項目應用中,由於數據結構和通信規約的不同,其程序邏輯也