題目一覽:
1.煤球數目
2.生日蠟燭
3.湊算式
4.快速排序
5.抽簽
6.方格填數
7.剪郵票
8.四平方和
9.交換瓶子
10.最大比例
1.煤球數目
有一堆煤球,堆成三角棱錐形。具體:
第一層放1個,
第二層3個(排列成三角形),
第三層6個(排列成三角形),
第四層10個(排列成三角形),
....
如果一共有100層,共有多少個煤球?
請填表示煤球總數目的數字。
注意:你提交的應該是一個整數,不要填寫任何多余的內容或說明性文字。
思路:枚舉

1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int main() { 5 int cnt = 0; 6 int Ans = 0; 7 for(int i=1; i<=100; ++i) { // 枚舉層數 8 cnt += i; // 每一層比上一層多i個 9 Ans += cnt; // 計算每一層 10 } 11 printf("%d\n", Ans); 12 return 0; 13 }
答案:171700
2.生日蠟燭
某君從某年開始每年都舉辦一次生日party,並且每次都要吹熄與年齡相同根數的蠟燭。
現在算起來,他一共吹熄了236根蠟燭。
請問,他從多少歲開始過生日party的?
請填寫他開始過生日party的年齡數。
注意:你提交的應該是一個整數,不要填寫任何多余的內容或說明性文字。
思路:枚舉+判斷

1 #include <bits/stdc++.h> 2 using namespace std; 3 4 bool flag = true; 5 int age = 0; 6 7 bool check(int x) { 8 int sum = 0; 9 while(sum < 236) { // 這里是< 10 sum += x; 11 x++; 12 } 13 if(sum == 236) return true; 14 else return false; 15 } 16 17 int main() { 18 while(flag && age<100) { 19 age++; 20 if(check(age)) 21 flag = false; 22 } 23 cout << age << endl; 24 return 0; 25 }
答案:26
3.湊算式
B DEF A + --- + ------- = 10 C GHI
(如果顯示有問題,可以參見【圖1.jpg】)
這個算式中A~I代表1~9的數字,不同的字母代表不同的數字。
比如:
6+8/3+952/714 就是一種解法,
5+3/1+972/486 是另一種解法。
這個算式一共有多少種解法?
注意:你提交應該是個整數,不要填寫任何多余的內容或說明性文字。
思路:拉成一維數組全排練+判斷,值得注意的是B/C和DEF/GHI都是整除。

1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 5 6 bool check() { 7 int x = a[3]*100 + a[4]*10 + a[5]; 8 int y = a[6]*100 + a[7]*10 + a[8]; 9 if((a[1]*y+a[2]*x)%(a[2]*y) != 0) return false; // 一定要是整除.. 10 // 這里注意兩個除法合並到一起 不然單個除不凈 11 int t = a[0] + (a[1]*y+a[2]*x)/(a[2]*y); 12 if(t == 10) return true; 13 return false; 14 } 15 16 int main() { 17 int Ans = 0; 18 do { 19 if(check()) Ans++; 20 }while(next_permutation(a, a+9)); 21 printf("%d\n", Ans); 22 return 0; 23 } 24 // 29
答案:29
4.快速排序
排序在各種場合經常被用到。
快速排序是十分常用的高效率的算法。
其思想是:先選一個“標尺”,
用它把整個隊列過一遍篩子,
以保證:其左邊的元素都不大於它,其右邊的元素都不小於它。
這樣,排序問題就被分割為兩個子區間。
再分別對子區間排序就可以了。
下面的代碼是一種實現,請分析並填寫划線部分缺少的代碼。

1 #include <stdio.h> 2 3 void swap(int a[], int i, int j) 4 { 5 int t = a[i]; 6 a[i] = a[j]; 7 a[j] = t; 8 } 9 10 int partition(int a[], int p, int r) 11 { 12 int i = p; 13 int j = r + 1; 14 int x = a[p]; 15 while(1){ 16 while(i<r && a[++i]<x); 17 while(a[--j]>x); 18 if(i>=j) break; 19 swap(a,i,j); 20 } 21 ______________________; // 填空 22 return j; 23 } 24 25 void quicksort(int a[], int p, int r) 26 { 27 if(p<r){ 28 int q = partition(a,p,r); 29 quicksort(a,p,q-1); 30 quicksort(a,q+1,r); 31 } 32 } 33 34 int main() 35 { 36 int i; 37 int a[] = {5,13,6,24,2,8,19,27,6,12,1,17}; 38 int N = 12; 39 40 quicksort(a, 0, N-1); 41 42 for(i=0; i<N; i++) printf("%d ", a[i]); 43 printf("\n"); 44 45 return 0; 46 }
注意:只填寫缺少的內容,不要書寫任何題面已有代碼或說明性文字。
思路:我們發現在partition函數中,是以a[p]為標尺,在[p, r]中比a[p]大的和比a[p]小的做交換,那么完成之后就是:a[p],小,小,大,大,大。a[p]顯然是要與一個數交換的,那么是i,還是j呢(可以輸入i,j輸出看一下)。因為我們這個partition函數是要求吧所有小於a[p]的數字放到左邊,大於的放到右邊,而下標i所指的數是大於a[p]的,與其交換就無法滿足要求,所以是與j交換。
答案:
swap(a, p, j);
5.抽簽
X星球要派出一個5人組成的觀察團前往W星。
其中:
A國最多可以派出4人。
B國最多可以派出2人。
C國最多可以派出2人。
....
那么最終派往W星的觀察團會有多少種國別的不同組合呢?
下面的程序解決了這個問題。
數組a[] 中既是每個國家可以派出的最多的名額。
程序執行結果為:
DEFFF
CEFFF
CDFFF
CDEFF
CCFFF
CCEFF
CCDFF
CCDEF
BEFFF
BDFFF
BDEFF
BCFFF
BCEFF
BCDFF
BCDEF
....
(以下省略,總共101行)
1 #include <stdio.h> 2 #define N 6 3 #define M 5 4 #define BUF 1024 5 6 void f(int a[], int k, int m, char b[]) 7 { 8 int i,j; 9 10 if(k==N){ 11 b[M] = 0; 12 if(m==0) printf("%s\n",b); 13 return; 14 } 15 16 for(i=0; i<=a[k]; i++){ 17 for(j=0; j<i; j++) b[M-m+j] = k+'A'; 18 ____________; //填空位置 19 } 20 } 21 int main() 22 { 23 int a[N] = {4,2,2,1,1,3}; 24 char b[BUF]; 25 f(a,0,M,b); 26 return 0; 27 }
仔細閱讀代碼,填寫划線部分缺少的內容。
注意:不要填寫任何已有內容或說明性文字。
思路:顯然第18行我們要調用f函數,首先肯定是(a, , , b),兩個數組嘛,然后第10行k==N,說明k是填到第k個,那么就變成了(a, k+1, , b),第12行判斷m==0,說明這第三個參數可能輸m-1,但測試一下發現並不是,那就只能是m-i了,測試發現正確。
答案:
f(a, k+1, m-i, b)
6.方格填數
如下的10個格子
+--+--+--+
| | | |
+--+--+--+--+
| | | | |
+--+--+--+--+
| | | |
+--+--+--+
(如果顯示有問題,也可以參看【圖1.jpg】)
填入0~9的數字。要求:連續的兩個數字不能相鄰。
(左右、上下、對角都算相鄰)
一共有多少種可能的填數方案?
請填寫表示方案數目的整數。
注意:你提交的應該是一個整數,不要填寫任何多余的內容或說明性文字。
方法一:將該10個格子按順序拉成一個一維數組,然后將十個數字填進去(全排列),填完之后進行判斷即可。

1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int a[11], Ans; 5 6 int calc(int x, int y) { 7 return abs(a[x]-a[y]); 8 } 9 10 bool check() { 11 if(calc(0, 1) == 1) return false; 12 if(calc(0, 3) == 1) return false; 13 if(calc(0, 4) == 1) return false; 14 if(calc(0, 5) == 1) return false; 15 16 if(calc(1, 2) == 1) return false; 17 if(calc(1, 4) == 1) return false; 18 if(calc(1, 5) == 1) return false; 19 if(calc(1, 6) == 1) return false; 20 21 if(calc(2, 5) == 1) return false; 22 if(calc(2, 6) == 1) return false; 23 24 if(calc(3, 4) == 1) return false; 25 if(calc(3, 7) == 1) return false; 26 if(calc(3, 8) == 1) return false; 27 28 if(calc(4, 5) == 1) return false; 29 if(calc(4, 7) == 1) return false; 30 if(calc(4, 8) == 1) return false; 31 if(calc(4, 9) == 1) return false; 32 33 if(calc(5, 6) == 1) return false; 34 if(calc(5, 8) == 1) return false; 35 if(calc(5, 9) == 1) return false; 36 37 if(calc(6, 9) == 1) return false; 38 if(calc(7, 8) == 1) return false; 39 if(calc(8, 9) == 1) return false; 40 return true; 41 } 42 43 void dfs(int pos) { 44 if(pos == 10) { 45 if(check()) Ans ++; 46 return ; 47 } 48 for(int i=pos; i<10; ++i) { 49 int t = a[pos]; a[pos] = a[i]; a[i] = t; 50 dfs(pos+1); 51 t = a[pos]; a[pos] = a[i]; a[i] = t; 52 } 53 } 54 55 int main() { 56 for(int i=0; i<=10; ++i) 57 a[i] = i; 58 dfs(0); 59 printf("%d\n", Ans); 60 return 0; 61 }
方法二:在原圖的基礎上加一圈,然后判斷。這個方法的check函數較為簡潔。初始化可以不是-10,只要不與0-9相差±1即可。如圖:

1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int Map[5][6], Ans; 5 bool vis[10]; 6 7 bool check(int x, int y) { 8 for(int i=x-1; i<=x+1; ++i) { 9 for(int j=y-1; j<=y+1; ++j) { 10 if(abs(Map[x][y]-Map[i][j]) == 1) 11 return false; 12 } 13 } 14 return true; 15 } 16 17 void dfs(int x, int y) { 18 if(x==3 && y==4) { 19 Ans++; 20 return ; 21 } 22 for(int i=0; i<10; ++i) { 23 if(vis[i]) continue; //這個數字用了 24 Map[x][y] = i; // 先放着 25 if(!check(x, y)) { 26 Map[x][y] = -10; // 27 continue; //放下不符規則 28 } 29 vis[i] = true; 30 if(y == 4) 31 dfs(x+1, 1); // 換行 32 else dfs(x, y+1); // 右邊的格子 33 Map[x][y] = -10; // 回溯 34 vis[i] = false; 35 } 36 } 37 38 int main() { 39 for(int i=0; i<10; ++i) vis[i] = false; 40 for(int i=0; i<5; ++i) // 外面加一圈 41 for(int j=0; j<6; ++j) 42 Map[i][j] = -10; 43 dfs(1, 2); //第一個填數的格子是(1,2) 44 printf("%d\n", Ans); 45 return 0; 46 }
答案:1580
7.剪郵票
如【圖1.jpg】, 有12張連在一起的12生肖的郵票。
現在你要從中剪下5張來,要求必須是連着的。
(僅僅連接一個角不算相連)
比如,【圖2.jpg】,【圖3.jpg】中,粉紅色所示部分就是合格的剪取。
請你計算,一共有多少種不同的剪取方法。
請填寫表示方案數目的整數。
注意:你提交的應該是一個整數,不要填寫任何多余的內容或說明性文字。
思路:直接搜索是不大可能的,我們可以把它轉變成全排列問題。因為一共12張,需要5張,我們可以創建一個數組,存放5個1和7個0,然后對其進行全排列(這里值得注意的是普通的全排列對重復的數字會產生重復的全排列,簡單起見,我們使用c++里面STL中的next_permutation()),然后將其轉化成二維數組,然后用dfs搜索看看有幾個連通塊,只有一個連通塊就是一個可行的方案。

1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int n = 3, m = 4, Map[3][4], Ans; 5 int a[] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}; 6 int u[4] = {-1, 0, 0, 1}, 7 v[4] = {0, -1, 1, 0}; 8 9 void dfs(int x, int y) { 10 Map[x][y] = 0; 11 for(int i=0; i<4; ++i) { 12 int xx = x + u[i]; 13 int yy = y + v[i]; 14 if(xx>=0 && xx<3 && yy>=0 && yy<4 && Map[xx][yy]==1) 15 dfs(xx, yy); 16 } 17 } 18 19 bool check() { 20 for(int i=0; i<3; ++i) 21 for(int j=0; j<4; ++j) 22 Map[i][j] = a[4*i+j]; 23 int cnt = 0; 24 for(int i=0; i<3; ++i) 25 for(int j=0; j<4; ++j) { 26 if(Map[i][j] == 1) { 27 dfs(i, j); 28 cnt++; 29 } 30 } 31 if(cnt == 1) return true; 32 return false; 33 } 34 35 void work() { // 利用next_permutation生成不重復的排列 36 do { 37 if(check()) Ans++; 38 }while(next_permutation(a, a+12)); 39 } 40 41 int main() { 42 43 work(); 44 printf("%d\n", Ans); 45 46 return 0; 47 }
答案:116
8.四平方和
四平方和定理,又稱為拉格朗日定理:
每個正整數都可以表示為至多4個正整數的平方和。
如果把0包括進去,就正好可以表示為4個數的平方和。
比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符號表示乘方的意思)
對於一個給定的正整數,可能存在多種平方和的表示法。
要求你對4個數排序:
0 <= a <= b <= c <= d
並對所有的可能表示法按 a,b,c,d 為聯合主鍵升序排列,最后輸出第一個表示法
程序輸入為一個正整數N (N<5000000)
要求輸出4個非負整數,按從小到大排序,中間用空格分開
例如,輸入:
5
則程序應該輸出:
0 0 1 2
再例如,輸入:
12
則程序應該輸出:
0 2 2 2
再例如,輸入:
773535
則程序應該輸出:
1 1 267 838
資源約定:
峰值內存消耗 < 256M
CPU消耗 < 3000ms
請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多余內容。
所有代碼放在同一個源文件中,調試通過后,拷貝提交該源碼。
注意: main函數需要返回0
注意: 只使用ANSI C/ANSI C++ 標准,不要調用依賴於編譯環境或操作系統的特殊函數。
注意: 所有依賴的函數必須明確地在源文件中 #include <xxx>, 不能通過工程設置而省略常用頭文件。
提交時,注意選擇所期望的編譯器類型。
方法一:由題可知a*a<=N/4,b*b<=N/3,c*c<=N/2,d*d<=N,那么我們就可以四層循環來做,但一個很明顯的問題就是會T。然后就是各種神奇的優化,比如說讓a*a<=50,b*b<=500。。。

1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int N; 5 6 int main() { 7 cin >> N; 8 for(int a=0; a*a<=50; a++) { 9 for(int b=a; b*b<=500; b++) { 10 if(b*b > N) break; 11 for(int c=b; c*c<=N/2; c++) { 12 if(c*c > N) break; 13 for(int d=c; d*d<=N; d++) { 14 if(d*d > N) break; 15 if(a*a+b*b+c*c+d*d == N) { 16 printf("%d %d %d %d\n", a, b, c, d); 17 return 0; 18 } 19 } 20 } 21 } 22 } 23 return 0; 24 }
方法二:我們可以事先處理c*c+d*d,把結果存起來,用map把結果與c或者d形成映射。然后再枚舉a、b,用N-a*a-b*b來得到c*c+d*d,判斷預處理里面有沒有,有的話在N-a*a-b*b-c*c開方求出d即可。

1 #include <bits/stdc++.h> 2 using namespace std; 3 4 map<int, int> Map; 5 int N; 6 7 int main() { 8 scanf("%d", &N); 9 for(int c=0; c*c<=N/2; ++c) 10 for(int d=c; c*c+d*d<=N; ++d) 11 if(Map.find(c*c+d*d) == Map.end()) 12 Map[c*c+d*d] = c; 13 for(int a=0; a*a<=N/4; ++a) { 14 for(int b=a; a*a+b*b<=N/2; ++b) { 15 if(Map.find(N-a*a-b*b) != Map.end()) { 16 int c = Map[N-a*a-b*b]; 17 int d = (int)sqrt(N-a*a-b*b-c*c); 18 printf("%d %d %d %d\n", a, b, c, d); 19 return 0; 20 } 21 } 22 } 23 return 0; 24 }
9.交換瓶子
有N個瓶子,編號 1 ~ N,放在架子上。
比如有5個瓶子:
2 1 3 5 4
要求每次拿起2個瓶子,交換它們的位置。
經過若干次后,使得瓶子的序號為:
1 2 3 4 5
對於這么簡單的情況,顯然,至少需要交換2次就可以復位。
如果瓶子更多呢?你可以通過編程來解決。
輸入格式為兩行:
第一行: 一個正整數N(N<10000), 表示瓶子的數目
第二行:N個正整數,用空格分開,表示瓶子目前的排列情況。
輸出數據為一行一個正整數,表示至少交換多少次,才能完成排序。
例如,輸入:
5
3 1 2 5 4
程序應該輸出:
3
再例如,輸入:
5
5 4 3 2 1
程序應該輸出:
2
資源約定:
峰值內存消耗 < 256M
CPU消耗 < 1000ms
請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多余內容。
所有代碼放在同一個源文件中,調試通過后,拷貝提交該源碼。
注意: main函數需要返回0
注意: 只使用ANSI C/ANSI C++ 標准,不要調用依賴於編譯環境或操作系統的特殊函數。
注意: 所有依賴的函數必須明確地在源文件中 #include <xxx>, 不能通過工程設置而省略常用頭文件。
提交時,注意選擇所期望的編譯器類型。
思路:從左到右掃一遍,碰到一個數在不是他的位置上,就找到它應該所在的位置(無論該位置上是誰),與其進行交換,然后答案加一。

1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int N, a[10101], Ans; 5 6 int get_pos(int x) { 7 for(int i=1; i<=N; ++i) 8 if(a[i] == x) 9 return i; 10 return -1; 11 } 12 13 int main() { 14 cin >> N; 15 for(int i=1; i<=N; ++i) scanf("%d", &a[i]); 16 for(int i=1; i<=N; ++i) { 17 if(a[i] != i) { 18 int pos = get_pos(i); 19 swap(a[i], a[pos]); 20 Ans ++; 21 } 22 } 23 printf("%d\n", Ans); 24 return 0; 25 }
10.最大比例
X星球的某個大獎賽設了M級獎勵。每個級別的獎金是一個正整數。
並且,相鄰的兩個級別間的比例是個固定值。
也就是說:所有級別的獎金數構成了一個等比數列。比如:
16,24,36,54
其等比值為:3/2
現在,我們隨機調查了一些獲獎者的獎金數。
請你據此推算可能的最大的等比值。
輸入格式:
第一行為數字 N (0<N<100),表示接下的一行包含N個正整數
第二行N個正整數Xi(Xi<1 000 000 000 000),用空格分開。每個整數表示調查到的某人的獎金數額
要求輸出:
一個形如A/B的分數,要求A、B互質。表示可能的最大比例系數
測試數據保證了輸入格式正確,並且最大比例是存在的。
例如,輸入:
3
1250 200 32
程序應該輸出:
25/4
再例如,輸入:
4
3125 32 32 200
程序應該輸出:
5/2
再例如,輸入:
3
549755813888 524288 2
程序應該輸出:
4/1
資源約定:
峰值內存消耗 < 256M
CPU消耗 < 3000ms
請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多余內容。
所有代碼放在同一個源文件中,調試通過后,拷貝提交該源碼。
注意: main函數需要返回0
注意: 只使用ANSI C/ANSI C++ 標准,不要調用依賴於編譯環境或操作系統的特殊函數。
注意: 所有依賴的函數必須明確地在源文件中 #include <xxx>, 不能通過工程設置而省略常用頭文件。
提交時,注意選擇所期望的編譯器類型。