機試編程(四)——數學問題(一)
目錄:
- 基礎知識
- 進制轉換
- 最大公約數和最小公倍數
- 分解質因數
- 質數(素數)
- 應用實例
- 二進制數【北京郵電大學】
- 進制轉換【清華大學】
- 10進制VS2進制【清華大學】
- 進制轉換2【清華大學】
- 八進制【華中科技大學】
- 又一版A+B【浙江大學】
- 進制轉換【北京大學】
- 數制轉換【北京大學】
- 最大公約數【計算機歷年考研複試上機題】
- 最小公倍數【華爲機試在線訓練】
- 最簡真分數【北京大學】
- 素數判定【哈爾濱工業大學】
- 素數【北京航天航空大學】
- Prime Number【上海交通大學】
- 整除問題【上海交通大學】
一、基礎知識
1、進制轉換
- 進制由基數和位權組成。
- 基數:指進制採用的數碼,基數爲n,就稱爲n進制。
- 位權:進制中每個固定位置對應的值。
- 值 = SUM(各數位的值乘以其對應的位權)。
2、最大公約數和最小公倍數
- 最大公約數(Greatest Common Divisor,GCD)
- 定義:兩個或多個整數共有約數中,最大的一個約數。
- 常用方法:歐幾里得算法(輾轉相除法)
- a = g * m,b = g * n
- 又a = b * k + r,其中r爲a除以b後的餘數
- 則g * m = g * n * k + r,即r = g * (m - n - k)
- a、b的公約數g可以整除a除以b後的餘數r(a mob b),即a、b的公約數和(b, a mod b)是一樣的,其最大公約數也必然相等。
- 最小公倍數(Least Common Multiple,LCM)
- 定義:兩個多多個整數公有的倍數中,除0以外最小的那一個公倍數。
- a、b兩個數的最小公倍數爲兩數的乘積除以它們的最大公約數。
3、分解質因數
- 定義:每個數都可以寫成一個或幾個質數相乘的形式,其中每個質數都是這個數的質因數。把一個數用質因數相乘的形式表示出來,就稱爲分解質因數。
4、質數(素數)
- 定義:只能被其自身和1整除的正整數。
- 常用方法:用所有小於等於sqrt(n)的正整數去試着整除該數,若存在某個數能夠整除該數,則該數不是素數;若這些數都不能整除它,則該數爲素數。
二、應用實例
1、題目描述:大家都知道,數據在計算機裏中存儲是以二進制的形式存儲的。 有一天,小明學了C語言之後,他想知道一個類型爲unsigned int 類型的數字,存儲在計算機中的二進制串是什麼樣子的。 你能幫幫小明嗎?並且,小明不想要二進制串中前面的沒有意義的0串,即要去掉前導0。【北京郵電大學】
- 輸入格式:每行有一個數字n(0<=n<=10^8),表示要求的二進制串。
- 輸出格式:輸出共T行。每行輸出求得的二進制串。
- 樣例輸入:
- 23
- 535
- 2624
- 56275
- 989835
- 樣例輸出:
- 10111
- 1000010111
- 101001000000
- 1101101111010011
- 11110001101010001011
示例代碼:
#include <iostream>
#include <stack>
using namespace std;
stack<int> myStack;
void GetBinaryStr(int num){
while(num != 0){
myStack.push(num % 2);
num /= 2;
}
}
int main(){
int inputNumber;
while(cin >> inputNumber){
GetBinaryStr(inputNumber);
while(!myStack.empty()){
cout << myStack.top();
myStack.pop();
}
cout << endl;
}
return 0;
}
2、題目描述:將一個長度最多爲30位數字的十進制非負整數轉換爲二進制數輸出。【清華大學】
- 輸入格式:多組數據,每行爲一個長度不超過30位的十進制非負整數。(注意是10進制數字的個數可能有30個,而非30bits的整數)
- 輸出格式:每行輸出對應的二進制數。
- 樣例輸入:
- 0
- 1
- 3
- 8
- 樣例輸出:
- 0
- 1
- 11
- 1000
示例代碼:
#include <iostream>
#include <stack>
#include <string>
using namespace std;
string myString;
stack<int> myStack;
string Divide(string s, int x){
int remainder = 0;
for(int i = 0; i < myString.size(); i++){
int current = remainder * 10 + s[i] - '0';
s[i] = current / 2 + '0';
remainder = current % x;
}
int pos = 0;
while(s[pos] == '0'){
pos++;
}
return s.substr(pos);
}
int main(){
while(cin >> myString){
while(myString.size() != 0){
int last = myString[myString.size() - 1] - '0';
myStack.push(last % 2);
myString = Divide(myString, 2);
}
while(!myStack.empty()){
cout << myStack.top();
myStack.pop();
}
cout << endl;
}
return 0;
}
附註:
(1)字符串除法:從高位到低位逐位除以除數,如果某位不能整除,那麼就保留它除以除數的餘數,餘數乘以10後和低一位一起進行處理。
3、題目描述:對於一個十進制數A,將A轉換爲二進制數,然後按位逆序排列,再轉換爲十進制數B,我們稱B爲A的二進制逆序數。 例如對於十進制數173,它的二進制形式爲10101101,逆序排列得到10110101,其十進制數爲181,181即爲173的二進制逆序數。【清華大學】
- 輸入格式:一個1000位(即10^999)以內的十進制數。
- 輸出格式:輸入的十進制數的二進制逆序數。
- 樣例輸入:
- 173
- 樣例輸出:
- 181
示例代碼:
#include <iostream>
#include <string>
#include <queue>
#include <cmath>
using namespace std;
string inputStr;
queue<int> myQueue;
//字符串除法
string Divide(string s, int x){
int remainder = 0;
for(int i = 0; i < s.size(); i++){
int current = remainder * 10 + s[i] - '0';
s[i] = current / 2 + '0';
remainder = current % x;
}
int pos = 0;
while(s[pos] == '0'){
pos++;
}
return s.substr(pos);
}
//字符串乘法
string Multiple(string s, int x){
int carry = 0;
for(int i = s.size() - 1; i >= 0; i--){
int current = x * (s[i] - '0') + carry;
s[i] = current % 10 + '0';
carry = current / 10;
}
if(carry != 0){
s = "1" + s;
}
return s;
}
//字符串加法
string Add(string s, int x){
int carry = x;
for(int i = s.size() - 1; i >= 0; i--){
int current = (s[i] - '0') + carry;
s[i] = current % 10 + '0';
carry = current / 10;
if(carry == 0){
break;
}
}
if(carry != 0){
s = "1" + s;
}
return s;
}
int main(){
while(cin >> inputStr){
while(inputStr.size() != 0){
int last = inputStr[inputStr.size() - 1] - '0';
myQueue.push(last % 2);
inputStr = Divide(inputStr, 2);
}
string answer = "0";
while(!myQueue.empty()){
answer = Multiple(answer, 2);
answer = Add(answer, myQueue.front());
myQueue.pop();
}
cout << answer << endl;
}
return 0;
}
附註:
(1)二進制轉換爲十進制:從最高位開始,逐次乘2,然後加上該位,同時對進位進行處理。
4、題目描述:將M進制的數X轉換爲N進制的數輸出。【清華大學】
- 輸入格式:輸入的第一行包括兩個整數:M和N(2<=M,N<=36)。下面的一行輸入一個數X,X是M進制的數,現在要求你將M進制的數X轉換成N進制的數輸出。
- 輸出格式:輸出X的N進製表示的數。
- 樣例輸入:
- 10 2
- 11
- 樣例輸出:
- 1011
示例代碼:
#include <iostream>
#include <string>
#include <stack>
using namespace std;
int CharToInt(char c){
if(c >= '0' && c <= '9'){
return c - '0';
}else if(c >= 'a' && c <= 'z'){
return c - 'a' + 10;
}else{
return c - 'A' + 10;
}
}
char IntToChar(int x){
if(x >= 0 && x <= 9){
return x + '0';
}else {
return x + 'a' - 10;
}
}
int main(){
int m, n;
string inputStr;
cin >> m >> n;
cin >> inputStr;
long long num = 0;
for(int i = 0; i < inputStr.size(); i++){ //m進制轉換爲10進制
num *= m;
num += CharToInt(inputStr[i]);
}
stack<char> result;
while(num != 0){//十進制轉換爲n進制
result.push(IntToChar(num % n));
num /= n;
}
while(!result.empty()){
cout << result.top();
result.pop();
}
cout << endl;
return 0;
}
5、題目描述:輸入一個整數,將其轉換成八進制數輸出。【華中科技大學】
- 輸入格式:輸入包括一個整數N(0<=N<=100000)。
- 輸出格式:可能有多組測試數據,對於每組數據,輸出N的八進制表示數。
- 樣例輸入:
- 7
- 8
- 9
- 樣例輸出:
- 7
- 10
- 11
示例代碼:
#include <iostream>
#include <vector>
using namespace std;
vector<int> myVector;
void Divide(int n){
int tmp;
while(n != 0){
tmp = n % 8;
myVector.push_back(tmp);
n /= 8;
}
}
int main(){
int n;
while(cin >> n){
Divide(n);
for(int i = myVector.size() - 1; i >= 0; i--){
cout << myVector[i];
}
cout << endl;
myVector.clear();
}
return 0;
}
6、題目描述:輸入兩個不超過整型定義的非負10進制整數A和B(<=231-1),輸出A+B的m (1 < m <10)進制數。【浙江大學】
- 輸入格式:輸入格式:測試輸入包含若干測試用例。每個測試用例佔一行,給出m和A,B的值。當m爲0時輸入結束。
- 輸出格式:輸出格式:每個測試用例的輸出佔一行,輸出A+B的m進制數。
- 樣例輸入:
- 8 1300 48
- 2 1 7
- 0
- 樣例輸出:
- 2504
- 1000
示例代碼:
#include <iostream>
#include <vector>
using namespace std;
vector<int> myVector;
void Divide(long long n, int m){
int tmp;
while(n != 0){
tmp = n % m;
myVector.push_back(tmp);
n /= m;
}
}
int main(){
int m, a, b;
while(cin >> m && m != 0 && cin >> a >> b){
if(a + b == 0){
cout << 0 << endl;
}else{
Divide(a + b, m);
for(int i = myVector.size() - 1; i >= 0; i--){
cout << myVector[i];
}
cout << endl;
myVector.clear();
}
}
return 0;
}
7、題目描述:寫出一個程序,接受一個十六進制的數值字符串,輸出該數值的十進制字符串(注意可能存在的一個測試用例裏的多組數據)。【北京大學】
- 輸入格式:輸入一個十六進制的數值字符串。
- 輸出格式:輸出該數值的十進制字符串。
- 樣例輸入:
- 0xA
- 樣例輸出:
- 10
示例代碼1:
#include <iostream>
#include <string>
using namespace std;
int CharToInt(char c){
if(c >= '0' && c <= '9'){
return c - '0';
}else if(c >= 'a' && c <= 'z'){
return c - 'a' + 10;
}else{
return c - 'A' + 10;
}
}
int main(){
string inputStr;
while(cin >> inputStr){
long long num = 0;
for(int i = 2; i < inputStr.size(); i++){
num *= 16;
num += CharToInt(inputStr[i]);
}
cout << num << endl;
}
return 0;
}
示例代碼2:
#include <iostream>
using namespace std;
int main(){
long long inputNumber;
while(cin >> hex >> inputNumber){
cout << dec << inputNumber << endl;
}
return 0;
}
8、題目描述:求任意兩個不同進制非負整數的轉換(2進制~16進制),所給整數在long所能表達的範圍之內。 不同進制的表示符號爲(0,1,...,9,a,b,...,f)或者(0,1,...,9,A,B,...,F)。【北京大學】
- 輸入格式:輸入只有一行,包含三個整數a,n,b。a表示其後的n 是a進制整數,b表示欲將a進制整數n轉換成b進制整數。a,b是十進制整數,2 =< a,b <= 16。數據可能存在包含前導零的情況。
- 輸出格式:可能有多組測試數據,對於每組數據,輸出包含一行,該行有一個整數爲轉換後的b進制數。輸出時字母符號全部用大寫表示,即(0,1,...,9,A,B,...,F)。
- 樣例輸入:
- 15 Aab3 7
- 樣例輸出:
- 210306
示例代碼:
#include <iostream>
#include <string>
#include <stack>
using namespace std;
int CharToInt(char c){
if(c >= 'a' && c <= 'z'){
return c - 'a' + 10;
}else if(c >= 'A' && c <= 'Z'){
return c - 'A' + 10;
}else{
return c - '0';
}
}
char IntToChar(int i){
if(i >= 0 && i <= 9){
return i + '0';
}else{
return i + 'A' - 10;
}
}
int main(){
int from, to;
string str;
while(cin >> from >> str >> to){
int loc = 0;
while(str[loc] == '0' && loc <= str.size() - 1){
loc++;
}
if(loc == str.size()){
cout << "0" << endl;
continue;
}
str = str.substr(loc);
//從from進制到十進制
long long num = 0;
for(int i = 0; i < str.size(); i++){
num *= from;
num += CharToInt(str[i]);
}
//從十進制到to進制
stack<char> myStack;
while(num != 0){
myStack.push(IntToChar(num % to));
num /= to;
}
while(!myStack.empty()){
cout << myStack.top();
myStack.pop();
}
cout << endl;
}
return 0;
}
9、題目描述:讀入n個正整數,求出這n個數的最小值、最大值以及它們兩的最大公約數,並輸出。輸入中第一行爲n,接下來爲n個大於零的整數。【計算機歷年考研複試上機題】
- 輸入格式:第一行爲n。第二行是n個大於零的整數,用空格隔開。
- 輸出格式:分別輸出最小值、最大值和它們兩的最大公約數,用空格隔開。
- 樣例輸入:
- 3
- 4 8 6
- 樣例輸出:
- 4 8 4
示例代碼:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> myVector;
int GCD(int a, int b){
if(b == 0){
return a;
}else{
return GCD(b, a % b);
}
}
int main(){
int n, inputNumber;
while(cin >> n){
for(int i = 0; i < n; i++){
cin >> inputNumber;
myVector.push_back(inputNumber);
}
sort(myVector.begin(), myVector.end());
cout << myVector.front() << " " << myVector.back() << " ";
cout << GCD(myVector.front(), myVector.back()) << endl;
myVector.clear();
}
return 0;
}
10、題目描述:正整數A和正整數B 的最小公倍數是指 能被A和B整除的最小的正整數值,設計一個算法,求輸入A和B的最小公倍數。【華爲機試在線訓練】
- 輸入格式:輸入兩個正整數A和B。
- 輸出格式:輸出A和B的最小公倍數。
- 樣例輸入:
- 5 7
- 樣例輸出:
- 35
示例代碼:
#include <iostream>
using namespace std;
int GCD(int a, int b){
if(b == 0){
return a;
}else{
return GCD(b, a % b);
}
}
int main(){
int a, b;
while(cin >> a >> b){
cout << a * b / GCD(a, b) << endl;
}
return 0;
}
11、給出n個正整數,任取兩個數分別作爲分子和分母組成最簡真分數,編程求共有幾個這樣的組合。【北京大學】
- 輸入格式:每組包含n(n<=600)和n個不同的整數,整數大於1且小於等於1000。
- 輸出格式:每行輸出最簡真分數組合的個數。
- 樣例輸入:
- 7
- 3 5 7 9 11 13 15
- 3
- 2 4 5
- 0
- 樣例輸出:
- 17
- 2
示例代碼:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> myVector;
int GCD(int a, int b){
if(b == 0){
return a;
}else{
return GCD(b, a % b);
}
}
int main(){
int n;
while(cin >> n && n){
int number;
for(int i = 0; i < n; i++){
cin >> number;
myVector.push_back(number);
}
sort(myVector.begin(), myVector.end());
int count = 0;
for(int i = n - 1; i > 0; i--){
for(int j = i - 1; j >= 0; j--){
if(myVector[i] % myVector[j] != 0 && GCD(myVector[i], myVector[j]) == 1){
++count;
}
}
}
cout << count << endl;
}
return 0;
}
附註:
(1)最簡真分數:分子小於分母,且分子和分母互質的分數。
12、題目描述:給定一個數n,要求判斷其是否爲素數(0,1,負數都是非素數)。【哈爾濱工業大學】
- 輸入格式:測試數據有多組,每組輸入一個數n。
- 輸出格式:對於每組輸入,若是素數則輸出yes,否則輸入no。
- 樣例輸入:
- 13
- 樣例輸出:
- yes
示例代碼:
#include <iostream>
#include <algorithm>
using namespace std;
bool IsPrimeNumber(int number){
if(number <= 1){
return false;
}
for(int i = 2; i <= sqrt(number); i++){
if(number % i == 0){
return false;
}
}
return true;
}
int main(){
int n;
while(cin >> n){
if(IsPrimeNumber(n)){
cout << "yes" << endl;
}else{
cout << "no" << endl;
}
}
return 0;
}
13、題目描述:輸入一個整數n(2<=n<=10000),要求輸出所有從1到這個整數之間(不包括1和這個整數)個位爲1的素數,如果沒有則輸出-1。【北京航天航空大學】
- 輸入格式:輸入有多組數據。每組一行,輸入n。
- 輸出格式:輸出所有從1到這個整數之間(不包括1和這個整數)個位爲1的素數(素數之間用空格隔開,最後一個素數後面沒有空格),如果沒有則輸出-1。
- 樣例輸入:
- 100
- 樣例輸出:
- 11 31 41 61 71
示例代碼:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> myVector;
bool IsPrimeNumber(int number){
for(int i = 2; i <= sqrt(number); i++){
if(number % i == 0){
return false;
}
}
return true;
}
int main(){
int n;
while(cin >> n){
for(int i = 2; i < n; i++){
if(IsPrimeNumber(i) && i % 10 == 1){
myVector.push_back(i);
}
}
if(myVector.size() == 0){
cout << "-1" << endl;
}else{
for(int i = 0; i < myVector.size() - 1; i++){
cout << myVector[i] << " ";
}
cout << myVector[myVector.size() - 1] << endl;
}
myVector.clear();
}
return 0;
}
14、題目描述:Output the k-th prime number.【上海交通大學】
- 輸入格式:k≤10000
- 輸出格式:The k-th prime number.
- 樣例輸入:
- 3
- 7
- 樣例輸出:
- 5
- 17
示例代碼:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> myVector;
bool IsPrimeNumber(int number){
for(int i = 2; i <= sqrt(number); i++){
if(number % i == 0){
return false;
}
}
return true;
}
int main(){
int count = 10001;
for(int i = 2; count != 0; i++){
if(IsPrimeNumber(i)){
myVector.push_back(i);
count--;
}
}
int k;
while(cin >> k){
cout << *(myVector.begin() + k - 1) << endl;
}
return 0;
}
15、題目描述:給定n,a求最大的k,使n!可以被a^k整除但不能被a^(k+1)整除。【上海交通大學】
- 輸入格式:兩個整數n(2<=n<=1000),a(2<=a<=1000)
- 輸出格式:一個整數
- 樣例輸入:
- 6 10
- 樣例輸出:
- 1
示例代碼:
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
vector<int> primeVector;
map<int, int> aMap, nMap;
bool GetPrime(int n){
for(int i = 2; i <= sqrt(n); i++){
if(n % i == 0){
return false;
}
}
return true;
}
void DealMap(vector<int> primeVector, int j, map<int, int> &m){
for(int i = 0; i < primeVector.size() && primeVector[i] <= j; i++){
int factor = primeVector[i];
while(j % primeVector[i] == 0){
j /= primeVector[i];
m[primeVector[i]]++;
}
}
}
int main(){
int a, n;
cin >> n >> a;
int big = a > n ? a : n;
for(int i = 2; i < big; i++){
if(GetPrime(i)){
primeVector.push_back(i);
}
}
for(int j = n; j >= 2; j--){
DealMap(primeVector, j, nMap);
}
DealMap(primeVector, a, aMap);
int min = big;
map<int, int>::iterator aIter = aMap.begin(), nIter = nMap.begin();
while(aIter != aMap.end() && nIter != nMap.end()){
while(aIter != aMap.end() && nIter != nMap.end() && aIter->first < nIter->first){
aIter++;
}
while(aIter != aMap.end() && nIter != nMap.end() && aIter->first == nIter->first){
int divide = aIter->second > nIter->second ?
aIter->second / nIter->second : nIter->second / aIter->second;
if(divide < min){
min = divide;
}
aIter++;
nIter++;
}
while(aIter != aMap.end() && nIter != nMap.end() && nIter->first < aIter->first){
nIter++;
}
}
if(min == big){
cout << 0 << endl;
}else{
cout << min << endl;
}
return 0;
}
附註:
(1)比較n!和a的相同質因數的指數之比的最小值爲所求。
6!=2^4*3^2*5^1=720
10=2^1*5^1
有公共質因數2和5,其中質因數2的指數分別爲4和1(4:1 = 4),質因數5的指數分別爲1和1(1:1 = 1),所以答案爲1。
參考文獻:
[1]楊澤邦、趙霖. 計算機考研——機試指南(第2版). [M]北京:電子工業出版社,2019.11;