【藍橋杯題解】矩陣翻硬幣
歷屆試題 矩陣翻硬幣
時間限制: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單片機的重要外設,編程操作並不復雜,但在實際的項目應用中,由於數據結構和通信規約的不同,其程序邏輯也