第七届蓝桥杯本科B组省赛
Posted _osayes_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第七届蓝桥杯本科B组省赛相关的知识,希望对你有一定的参考价值。
煤球数目
有一堆煤球,堆成三角棱锥形。具体:
第一层放1个,
第二层3个(排列成三角形),
第三层6个(排列成三角形),
第四层10个(排列成三角形),
….
如果一共有100层,共有多少个煤球?
请填表示煤球总数目的数字。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
思路:
推出第i层有i*(i+1)/2个煤球,累加到100层即可,答案为171700
#include <bits/stdc++.h>
using namespace std;
int main() {
int ans = 0;
for (int i = 1; i <= 100; i++) {
ans += i * (i + 1) / 2;
}
cout << ans << endl;
return 0;
}
生日蜡烛
某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。
现在算起来,他一共吹熄了236根蜡烛。
请问,他从多少岁开始过生日party的?
请填写他开始过生日party的年龄数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
思路
根据题目意思,假设他从x岁开始过生日,现在是y岁,这么多年的岁数和是236,由于每一年年龄会加1,相当于是一个项数位(y-x+1),公差为1的等差数列求和。于是只要枚举x和y,然后根据公式算一下(直接累加求和也是可以的)是不是等于236就行了。答案等于26。
#include <bits/stdc++.h>
using namespace std;
int main() {
for (int i = 1; i <= 100; i++) {
for (int j = i + 1; j <= 100; j++) {
if ((i + j) * (j - i + 1) / 2 == 236) cout << i << endl;
}
}
return 0;
}
凑算式
B DEF
A + - + --- = 10
C GHI
这个算式中A~I代表1~9的数字,不同的字母代表不同的数字。
比如:
6+8/3+952/714 就是一种解法,
5+3/1+972/486 是另一种解法。
这个算式一共有多少种解法?
注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。
思路
利用全排列生成所有A~I和1~9可能的对应情况,对每一种对应情况判断一下等式是否成立即可。答案是29。(当时比赛的时候逗比了,看见”/”就以为必须是整除,所以代码里多了个B%C==0&&DEF%GHI==0)
#include <bits/stdc++.h>
using namespace std;
int a[10], ans;
int main() {
for (int i = 1; i <= 9; i++) {
a[i] = i;
}
do {
double A = a[1];
double B = a[2];
double C = a[3];
double DEF = a[4] * 100 + a[5] * 10 + a[6];
double GHI = a[7] * 100 + a[8] * 10 + a[9];
if (fabs(A + B / C + DEF / GHI - 10) < 1e-12) ans++;
} while (next_permutation(a + 1, a + 10));
cout << ans << endl;
return 0;
}
快速排序
排序在各种场合经常被用到。
快速排序是十分常用的高效率的算法。
其思想是:先选一个“标尺”,
用它把整个队列过一遍筛子,
以保证:其左边的元素都不大于它,其右边的元素都不小于它。
这样,排序问题就被分割为两个子区间。
再分别对子区间排序就可以了。
下面的代码是一种实现,请分析并填写划线部分缺少的代码。
#include <stdio.h>
void swap(int a[], int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
int partition(int a[], int p, int r) {
int i = p;
int j = r + 1;
int x = a[p];
while(1) {
while(i < r && a[++i] < x);
while(a[--j] > x);
if(i >= j) break;
swap(a, i, j);
}
______________________;
return j;
}
void quicksort(int a[], int p, int r) {
if(p < r) {
int q = partition(a, p, r);
quicksort(a, p, q - 1);
quicksort(a, q + 1, r);
}
}
int main() {
int i;
int a[] = {5, 13, 6, 24, 2, 8, 19, 27, 6, 12, 1, 17};
int N = 12;
quicksort(a, 0, N - 1);
for(i = 0; i < N; i++) printf("%d ", a[i]);
printf("\n");
return 0;
}
注意:只填写缺少的内容,不要书写任何题面已有代码或说明性文字。
思路
相信对每一位计算机相关的考研党和学霸来说这种题目都是小case吧。。。根据quicksort的参数和main函数的调用,以及partition里面的参数可以猜到partition的参数a[],p,r的含义是要排序的数组、开始位置、结束位置,那么partition的功能就是将a数组的p位置到r位置的序列划分成两半,让左一半全部小于等于右一半,同时返回那个临界值的位置。在partition里面,将a[p]选为了参考值(int x=a[p]),而后这个a[p]就再没变化,这显然是不行的,因为参考值放在了最前面,比它小的只能放后面。所以还缺了“将a[p]这个临界值换到后面去”这一步。换到哪里呢?由于后面return的是j,那么答案就出来了,swap(a, p, j)。填进代码里面测试,对或错就知道了,如果还不放心,用rand()给a数组赋值,排完序再打出来看看。
抽签
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行)
#include <stdio.h>
#define N 6
#define M 5
#define BUF 1024
void f(int a[], int k, int m, char b[]) {
int i, j;
if(k == N) {
b[M] = 0;
if(m == 0) printf("%s\n", b);
return;
}
for(i = 0; i <= a[k]; i++) {
for(j = 0; j < i; j++) b[M - m + j] = k + ‘A‘;
______________________; //填空位置
}
}
int main() {
int a[N] = {4, 2, 2, 1, 1, 3};
char b[BUF];
f(a, 0, M, b);
return 0;
}
思路:
其实最喜欢这样的填空题了,因为很容易判断填的是对还是错=.=这个题其实当时都没怎么思考,直接就填了个f(a, k+1, m-i, b)试一试,打出来的结果跟题目中的一致,还自己加个统计变量,刚好是101行。。。大概就是要搞出几个变量的含义吧,f(a, k, m, b)里面,a限制了每一次往答案数组b填的相同字母个数,k是表示第几个字母,m表示剩余的字母个数,b是答案数组。f函数里面的i就是表示第k个字母选i个往b里放,而j就是放的过程,放完以后自然就要考虑下一个了。所以答案就是f(a, k+1, m-i, b),表示放下一个字母,这一次放了i个,所以还剩下m-i个可以放。
方格填数
填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)
+--+--+--+
| | | |
+--+--+--+--+
| | | | |
+--+--+--+--+
| | | |
+--+--+--+
一共有多少种可能的填数方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
思路
用全排列生成所有情况,然后判断是否合法就行了。另外题目中给的条件:“连续的两个数字不能相邻” 等价于 “相邻的数字不连续”,这个是至关重要的。答案是1580。
#include <bits/stdc++.h>
using namespace std;
int ans;
int a[10];
bool chk(int i, int j) {
return abs(a[i] - a[j]) != 1;
}
bool chk() {
return chk(0, 1) && chk(1, 2) && chk(3, 4) && chk(4, 5) && chk(5, 6) && chk(7, 8) && chk(8, 9) &&
chk(0, 4) && chk(1, 5) && chk(2, 6) && chk(3, 7) && chk(4, 8) && chk(5, 9) &&
chk(0, 5) && chk(1, 6) && chk(3, 8) && chk(4, 9) &&
chk(0, 3) && chk(1, 4) && chk(2, 5) && chk(4, 7) && chk(5, 8) && chk(6, 9);
}
int main() {
for (int i = 0; i < 10; i++) a[i] = i;
do {
ans += chk();
} while (next_permutation(a, a + 10));
cout << ans << endl;
return 0;
}
剪邮票
+--+--+--+--+
| | | | |
+--+--+--+--+
| | | | |
+--+--+--+--+
| | | | |
+--+--+--+--+
有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
请你计算,一共有多少种不同的剪取方法。
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
思路
先生成所有邮票的形状,然后看这个形状在一个连通块内,对每个格子编号,那么它的形状可以用5个数来表示,判断是否为联通块用dfs或bfs都行。答案是116。
#include <bits/stdc++.h>
using namespace std;
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
int a[5], ans;
bool flag[3][4], vis[3][4];
void dfs2(int x, int y) {
vis[x][y] = 1;
for (int i = 0; i < 4; i++) {
int xx = x + dx[i];
int yy = y + dy[i];
if (xx >= 0 && xx < 3 && yy >= 0 && yy < 4 && !flag[xx][yy] && !vis[xx][yy]) dfs2(xx, yy);
}
}
bool work() {
memset(flag, 1, sizeof(flag));
memset(vis, 0, sizeof(vis));
for (int i = 0; i < 5; i++) flag[a[i] / 4][a[i] % 4] = 0;
dfs2(a[0] / 4, a[0] % 4);
for (int i = 0; i < 5; i++) {
if (!vis[a[i] / 4][a[i] % 4]) return 0;
}
return 1;
}
void dfs(int k, int b) {
if (k == 5) {
ans += work();
return;
}
for (int i = b; i <= 7 + k; i++) {
a[k] = i;
dfs(k + 1, i + 1);
}
}
int main() {
dfs(0, 0);
cout << ans << endl;
return 0;
}
四平方和
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多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
思路
最简单的思路4重for循环,不知道这样能过多少组数据,毕竟这个复杂度不好确定,虽然最坏是
#include <bits/stdc++.h>
using namespace std;
#include "local.h"
struct Node {
int x, y;
Node() {}
Node(int x, int y) {
this->x = x;
this->y = y;
}
};
map<int, vector<Node> > mp;
int n;
void work() {
for (int i = 0; i * i <= n; i++) {
for (int j = i; i * i + j * j <= n; j++) {
vector<Node>::iterator it, st = mp[n - i * i - j * j].begin(), ed = mp[n - i * i - j * j].end();
for (it = st; it != ed; it++) {
if (j <= it->x) {
cout << i << " " << j << " " << it->x << " " << it->y << endl;
return;
}
}
}
}
}
int main() {
cin >> n;
for (int i = 0; i * i <= n; i++) {
for (int j = i; i * i + j * j <= n; j++) {
mp[i * i + j * j].push_back(Node(i, j));
}
}
work();
return 0;
}
交换瓶子
有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
思路
每一种该序列都可以看成一种置换,每一种置换都可以写成若干循环的乘积,比如
2 1 3 5 4
1 2 3 4 5
可以写成(1 2)(3)(4 5),显然我们的目标使使得循环个数最多即(1)(2)(3)(4)(5)
在循环内部交换,除最后一次外,每次可以让一个到达目标位置,即循环个数增加1。在循环外部交换,会较少循环的个数,得不偿失。因此得到结论,先把序列写成若干循环的乘积,然后再循环内部交换,交换的次数为循环的大小-1,最后结果等于n-循环的个数
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 7;
int a[N], ans, n;
bool vis[N];
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
scanf("%d", a + i);
}
for (int i = 1; i <= n; i++) {
if (!vis[i]) {
ans++;
vis[i] = 1;
for (int j = a[i]; j != i; j = a[j]) vis[j] = 1;
}
}
cout << n - ans << endl;
return 0;
}
最大比例
X星球的某个大奖赛设了M级奖励。每个级别的奖金是一个正整数。
并且,相邻的两个级别间的比例是个固定值。
也就是说:所有级别的奖金数构成了一个等比数列。比如:
16,24,36,54
其等比值为:3/2
现在,我们随机调查了一些获奖者的奖金数。
请你据此推算可能的最大的等比值。
输入格式:
第一行为数字N,表示接下的一行包含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
思路
首先将原序列从小到大排序去重,然后得到最大可能的比值a[1]/a[0],因为如果比这个大,显然第1、2项就不能满足。而且其它的可能的比值只能是a[1]/a[0]的平方根、立方根等等(如果它们是有理数的话)。那么一个暴力的思路就出来了,枚举所有a[0]和a[1]之间”隐藏”的项数,比如为1,那么就应该把比例确定为
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[100], A, B, g, x, y, s, t;
int n, m;
ll gcd(ll a, ll b) {
return b? gcd(b, a % b) : a;
}
ll power(ll a, int b) {
ll ans = 1;
for (int i = 0; i < b; i++) ans *= a;
return ans;
}
ll chk(ll A, int d) {
double r = pow(A, 1.0 / d);
ll ir = (ll)(r + 0.5);
if (power(ir, d) == A) return ir;
return 0;
}
ll calc(ll A, ll x) {
if (x == 1) return 0;
ll cnt = 0;
while (A >= x) {
A /= x;
cnt++;
}
if (A == 1) return cnt;
return 0;
}
bool work(ll x, ll y) {
ll A, B;
for (int i = 1; i < m - 1; i++) {
A = a[i + 1];
B = a[i];
g = gcd(A, B);
A /= g;
B /= g;
s = calc(A, x);
t = calc(B, y);
if (y == 1) t = s;
if (s != t || !s) return false;
}
cout << x << "/" << y << endl;
return true;
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
sort(a, a + n);
m = unique(a, a + n) - a;
if (m == 1) {
puts("1/1");
return 0;
}
A = a[1];
B = a[0];
g = gcd(A, B);
A /= g;
B /= g;
for (int i = 1; power(2, i) <= A; i++) {
x = chk(A, i);
y = chk(B, i);
if (B == 1) y = 1;
if (x && y) {
if (work(x, y)) break;
}
}
return 0;
}
以上是关于第七届蓝桥杯本科B组省赛的主要内容,如果未能解决你的问题,请参考以下文章