2016-第七届蓝桥杯大赛个人赛省赛(软件类)真题 C大学A组
题目一览:
1.网友年龄
2.生日蜡烛
3.方格填数
4.快速排序
5.消除尾一
6.寒假作业
7.剪邮票
8.四平方和
9.密码脱落
10.最大比例
1.网友年龄
某君新认识一网友。
当问及年龄时,他的网友说:
“我的年龄是个2位数,我比儿子大27岁,
如果把我的年龄的两位数字交换位置,刚好就是我儿子的年龄”
请你计算:网友的年龄一共有多少种可能情况?
提示:30岁就是其中一种可能哦.
请填写表示可能情况的种数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
思路:枚举判断
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 bool check(int x) { 5 int y = x - 27; 6 int xx = x%10 * 10 + x/10; 7 if(xx == y) return true; 8 return false; 9 } 10 11 int main() { 12 int cnt = 0; 13 for(int i=10; i<=99; ++i) 14 if(check(i)) { 15 printf("%d\n", i); 16 cnt ++; 17 } 18 cout << cnt << endl; 19 return 0; 20 }
答案:7
2.生日蜡烛
某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。
现在算起来,他一共吹熄了236根蜡烛。
请问,他从多少岁开始过生日party的?
请填写他开始过生日party的年龄数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
思路:枚举+判断
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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.方格填数
如下的10个格子
+--+--+--+
| | | |
+--+--+--+--+
| | | | |
+--+--+--+--+
| | | |
+--+--+--+
(如果显示有问题,也可以参看【图1.jpg】)
填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)
一共有多少种可能的填数方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
方法一:将该10个格子按顺序拉成一个一维数组,然后将十个数字填进去(全排列),填完之后进行判断即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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即可。如图:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
4.快速排序
排序在各种场合经常被用到。
快速排序是十分常用的高效率的算法。
其思想是:先选一个“标尺”,
用它把整个队列过一遍筛子,
以保证:其左边的元素都不大于它,其右边的元素都不小于它。
这样,排序问题就被分割为两个子区间。
再分别对子区间排序就可以了。
下面的代码是一种实现,请分析并填写划线部分缺少的代码。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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.消除尾一
下面的代码把一个整数的二进制表示的最右边的连续的1全部变成0
如果最后一位是0,则原数字保持不变。
如果采用代码中的测试数据,应该输出:
00000000000000000000000001100111 00000000000000000000000001100000 00000000000000000000000000001100 00000000000000000000000000001100
请仔细阅读程序,填写划线部分缺少的代码。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 3 void f(int x) 4 { 5 int i; 6 for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1); 7 printf(" "); 8 9 x = _______________________; // 填空 10 11 for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1); 12 printf("\n"); 13 } 14 15 int main() 16 { 17 f(103); 18 f(12); 19 return 0; 20 }
注意:只填写缺少的内容,不要书写任何题面已有代码或说明性文字。
思路:很显然两个输出是一样的,改变的关键就是我们填空的地方。那就用到了位运算'&'-按位与:如果两个相应的二进制位都为1,则该位的结果值为1,否则为0。看下图
答案:
x&(x+1)
6.寒假作业
现在小学的数学题目也不是那么好玩的。
看看这个寒假作业:
□ + □ = □
□ - □ = □
□ × □ = □
□ ÷ □ = □
(如果显示不出来,可以参见【图1.jpg】)
每个方块代表1~13中的某一个数字,但不能重复。
比如:
6 + 7 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5
以及:
7 + 6 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5
就算两种解法。(加法,乘法交换律后算不同的方案)
你一共找到了多少种方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
思路:其实也是全排列问题,把12个格子看成一维数组,然后填充,最后判断。值得注意的是13!很大,直接跑大约需要一分钟左右,这是填空题所以没什么事。但是我们可以添加几个优化。第22行加的语言可以排除很多无用的排列,大大的提高了效率。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int a[13] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; 5 int Ans; 6 7 bool check() { 8 if(a[9]%a[10] != 0) return false; // 不能整除 9 if(a[0]+a[1] != a[2]) return false; // + - * / 10 if(a[3]-a[4] != a[5]) return false; 11 if(a[6]*a[7] != a[8]) return false; 12 if(a[9]/a[10] != a[11]) return false; 13 return true; 14 } 15 16 void dfs(int x) { 17 if(x == 13) { // 填完了 18 if(check()) Ans++; 19 } 20 for(int i=x; i<13; ++i) { 21 swap(a[x], a[i]); 22 // 剪枝 不满足加法或减法 的跳过 23 // 因为加减法所需数字在前面 这样就减少了许多无用的 计算 24 if((x==2&&a[0]+a[1]!=a[2]) || (x==5&&a[3]-a[4]!=a[5])) { 25 swap(a[x], a[i]); 26 continue; 27 } 28 dfs(x+1); 29 swap(a[x], a[i]); 30 } 31 } 32 33 int main() { 34 dfs(0); 35 cout << Ans << endl; 36 return 0; 37 }
答案:64
7.剪邮票
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
思路:直接搜索是不大可能的,我们可以把它转变成全排列问题。因为一共12张,需要5张,我们可以创建一个数组,存放5个1和7个0,然后对其进行全排列(这里值得注意的是普通的全排列对重复的数字会产生重复的全排列,简单起见,我们使用c++里面STL中的next_permutation()),然后将其转化成二维数组,然后用dfs搜索看看有几个连通块,只有一个连通块就是一个可行的方案。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //#include <bits/stdc++.h> 2 #include <iostream> 3 #include <map> 4 #include <cmath> 5 using namespace std; 6 7 map<int, int> Map; 8 int N; 9 10 int main() { 11 scanf("%d", &N); 12 for(int c=0; c*c<=N/2; ++c) 13 for(int d=c; c*c+d*d<=N; ++d) 14 if(Map.find(c*c+d*d) == Map.end()) 15 Map[c*c+d*d] = c; 16 for(int a=0; a*a<=N/4; ++a) { 17 for(int b=a; a*a+b*b<=N/2; ++b) { 18 if(Map.find(N-a*a-b*b) != Map.end()) { 19 int c = Map[N-a*a-b*b]; 20 int d = (int)sqrt(N-a*a-b*b-c*c); 21 printf("%d %d %d %d\n", a, b, c, d); 22 return 0; 23 } 24 } 25 } 26 return 0; 27 }
9.密码脱落
X星球的考古学家发现了一批古代留下来的密码。
这些密码是由A、B、C、D 四种植物的种子串成的序列。
仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串)。
由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征。
你的任务是:
给定一个现在看到的密码串,计算一下从当初的状态,它要至少脱落多少个种子,才可能会变成现在的样子。
输入一行,表示现在看到的密码串(长度不大于1000)
要求输出一个正整数,表示至少脱落了多少个种子。
例如,输入:
ABCBA
则程序应该输出:
0
再例如,输入:
ABDCDCBABC
则程序应该输出:
3
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
方法一:爆搜,两端若不相等就分别往左、右添加,代码很简短,但时间复杂度数2^n,是会T的。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 string s; 5 6 int dfs(int l, int r, int cnt) { 7 if(l >= r) return cnt; 8 if(s[l] != s[r]) 9 return min(dfs(l+1, r, cnt+1), dfs(l, r-1, cnt+1)); 10 else return dfs(l+1, r-1, cnt); 11 } 12 13 int main() { 14 cin >> s; 15 int Ans = dfs(0, s.length()-1, 0); 16 printf("%d\n", Ans); 17 return 0; 18 }
方法二:要求是对称,那我我们把原串翻转一下,在进行对比可以发现两串有3个不同的字母,那么我们添加这三个字母不就好了。所以答案就是长度-LCS(最长公共子序列)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 #include <string> 3 using namespace std; 4 5 string s, r_s; 6 int a[1010][1010]; 7 8 int LCS() { 9 int len = s.length(); 10 for(int i=1; i<=len; ++i) { 11 for(int j=1; j<=len; ++j) { 12 if(s[i-1] == r_s[j-1]) 13 a[i][j] = a[i-1][j-1] + 1; 14 else 15 a[i][j] = max(a[i-1][j], a[i][j-1]); 16 } 17 } 18 return a[len][len]; 19 } 20 21 int main() { 22 cin >> s; 23 r_s = s; 24 reverse(r_s.begin(), r_s.end()); 25 int lcs = LCS(); 26 int Ans = s.length() - lcs; 27 printf("%d\n", Ans); 28 return 0; 29 }
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>, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
posted on 2020-03-31 10:30 Marginalin 阅读(2349) 评论(0) 编辑 收藏 举报