第十五届蓝桥杯 省赛 C/C++ 大学B组

        个人感觉蓝桥杯管的不是很严,可以提前打好快读模板和对拍代码(C/C++组只能使用Dev-cpp),快读模板和对拍代码放在最后了;也可以自己带点吃的喝饮料(比赛时间是9:00 — 13:00,中午有可能会饿)。最后也是成功拿到了一个广东省一等奖。

A. 握手问题(5分)

问题描述

        小蓝组织了一场算法交流会议,总共有 50 人参加了本次会议。在会议上,大家进行了握手交流。按照惯例他们每个人都要与除自己以外的其他所有人进行一次握手(且仅有一次)。但有 7 个人,这 7 人彼此之间没有进行握手(但这 7 人与除这 7 人以外的所有人进行了握手)。请问这些人之间一共进行了多少次握手?
        注意 A 和 B 握手的同时也意味着 B 和 A 握手了,所以算作是一次握手。

答案提交

        这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

思路

        当时拿到题目一看感觉像是一道高中的排列组合,用 C_{50}^{2} - C_{7}^{2} = 1204 就行了

B. 小球反弹(5分)

问题描述

        有一长方形,长为 343720 单位长度,宽为 233333 单位长度。在其内部左上角顶点有一小球(无视其体积),其初速度如图所示且保持运动速率不变,分解到长宽两个方向上的速率之比为 dx : dy = 15 : 17。小球碰到长方形的边框时会发生反弹,每次反弹的入射角与反射角相等,因此小球会改变方向且保持速率不变(如果小球刚好射向角落,则按入射方向原路返回)。从小球出发到其第一次回到左上角顶点这段时间里,小球运动的路程为多少单位长度?答案四舍五入保留两位小数。

答案提交

        这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个小数,在提交答案时只填写这个小数,填写多余的内容将无法得分。

思路

        当时在考场感觉这道题很麻烦就先跳了,想着最后在回来做,结果最后面时间不够了只能随便蒙一个答案上去(好像没对...)。

C. 好数(10分)

时间限制:1.0s        内存限制:256.0MB

问题描述

        一个整数如果按从低位到高位的顺序,奇数位(个位、百位、万位…)上的数字是奇数,偶数位(十位、千位、十万位…)上的数字是偶数,我们就称之为“好数”。

        给定一个正整数 N,请计算从 1 到 N 一共有多少个好数。

输入格式

        一个整数 N

输出格式

        一个正数表示答案

样例输入1

24

样例输出1

7

样例输入2

2024

样例输出2

150

样例说明

        对于第一个样例,24 以内的好数有 1、3、5、7、9、21、23,一共 7 个。

评测用例规模与约定

        对于 10% 的评测用例,1 ≤ N ≤ 100。
        对于 100% 的评测用例,1 ≤ N ≤ 10^{7}

思路

        正确答案应该是要用数位dp,但是感觉数据量不是很大,所以暴力应该也能过。

代码 

#include <bits/stdc++.h>
using namespace std;

inline int read() {
	int x = 0, f = 1; char c = getchar();
	while (c < '0' || c > '9') {
		if (c == '-') f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return x * f;
}

int main() {
	int n = read(), cnt = 0;
    for (int i = 1; i <= n; i += 2) {
		int m = i, t = 0, flag = 1;
		while (m) {
			if (m % 2 == t) { flag = 0; break; }
			m /= 10, t ^= 1;
		}
		if (flag) cnt++;
	}
    printf("%d", cnt);
    return 0;
}

D. R 格式(10分)

时间限制:1.0s        内存限制:256.0MB

问题描述

        小蓝最近在研究一种浮点数的表示方法:R 格式。对于一个大于 0 的浮点数 d,可以用 R 格式的整数来表示。给定一个转换参数 n,将浮点数转换为 R 格式整数的做法是:
        1.将浮点数乘以 2^{n};
        2.四舍五入到最接近的整数。

输入格式

        一行输入一个整数 n 和一个浮点数 d,分别表示转换参数,和待转换的浮点数。

输出格式

        输出一行表示答案:d 用 R 格式表示出来的值。

样例输入

2  3.14

样例输出

13

样例说明

        3.14 \times 2^{2} = 12.56,四舍五入后为 13。

评测用例规模与约定

        对于 50% 的评测用例:1 ≤ n ≤ 10,1 ≤ 将 d 视为字符串时的长度 ≤ 15。
        对于 100% 的评测用例:1 ≤ n ≤ 1000,1 ≤ 将 d 视为字符串时的长度 ≤ 1024;保证 d 是小数,即包含小数点。

思路

        因为 n \leq 1000 ,所以很明显需要用到高精度快速幂(long long 无法存下 2^{1000})。

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 1010;
int ans[N], temp[N], a[N], oup[N], n, len, zs, xs;
char d[1030];

inline int read() {
	int x = 0, f = 1; char c = getchar();
	while (c < '0' || c > '9') {
		if (c == '-') f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return x * f;
}

void mul_1()
{
    memset(temp, 0, sizeof(temp));
    for (int i = 1; i <= 500; i++)
        for (int j = 1; j <= 500; j++) temp[i + j - 1] += ans[i] * a[j];
    for (int i = 1; i <= 500; i++)
    {
        temp[i + 1] += temp[i] / 10;
        temp[i] %= 10;
    }
    for (int i = 1; i <= 500; i++) ans[i] = temp[i];
}


void mul_2()
{
    memset(temp, 0, sizeof(temp));
    for (int i = 1; i <= 500; i++)
        for (int j = 1; j <= 500; j++) temp[i + j - 1] += a[i] * a[j];
    for (int i = 1; i <= 500; i++)
    {
        temp[i + 1] += temp[i] / 10;
        temp[i] %= 10;
    }  
    for (int i = 1; i <= 500; i++) a[i] = temp[i];
}

int main()
{
    n = read(); cin >> d;
    for (int i = 0; i < strlen(d); i++) {
    	if (d[i] == '.') { len = i; break; }
    	zs = zs * 10 + d[i] - '0';
	}
	for (int i = len + 1; i < strlen(d); i++) {
		xs = xs * 10 + d[i] - '0';
	}
    // 将浮点数d拆成整数和小数两部分并且记下整数部分长度
	len = strlen(d) - len - 1; // 算出小数部分长度

    ans[1] = 1, a[1] = 2;
    while (n > 0)
    {
        if (n % 2 == 1) mul_1();
        mul_2();
        n /= 2;
    } // 利用高精快速幂计算2的n次方

    for (int i = 1; i <= len; i++) oup[i] = ans[i] * zs;
    for (int i = 1; i <= 500; i++) {
    	oup[i + 1] += oup[i] / 10;
    	oup[i] %= 10;
	}
	for (int i = 1; i <= len; i++) ans[i] *= xs;
	for (int i = 1; i <= 500; i++) {
		ans[i + 1] += ans[i] / 10;
		ans[i] %= 10;
	}
	if (ans[len] >= 5) ans[len + 1]++; // 四舍五入
	for (int i = 1; i <= 500; i++) {
		oup[i] += ans[i + len]; // 只加d的小数乘2的n次方后的整数部分
		if (oup[i] > 9) {
			oup[i + 1] += oup[i] / 10;
			oup[i] /= 10;
		}
	} // 将整数小数部分分别乘上2的n次方

	int p;
    for (int i = 500; i; i--) {
        if (oup[i]) {
        	p = i;
        	break;
		}
    } // 记下第一位的位置
    for (int i = p; i; i--) putchar(oup[i] + '0'); // 按位输出
    return 0;
}

E. 宝石组合(15分)

时间限制:1.0s        内存限制:256.0MB

问题描述

        在一个神秘的森林里,住着一个小精灵名叫小蓝。有一天,他偶然发现了一个隐藏在树洞里的宝藏,里面装满了闪烁着美丽光芒的宝石。这些宝石都有着不同的颜色和形状,但最引人注目的是它们各自独特的“闪亮度”属性。每颗宝石都有一个与生俱来的特殊能力,可以发出不同强度的闪光。小蓝共找到了 N 枚宝石,第 i 枚宝石的“闪亮度”属性值为 H_{i},小蓝将会从这 N 枚宝石中选出三枚进行组合,组合之后的精美程度 S 可以用以下公式来衡量:


S = H_{a}H_{b}H_{c} \cdot \frac{LCM(H_{a}, H_{b}, H_{c})}{LCM(H_{a}, H_{b}) \cdot LCM(H_{a}, H_{c}) \cdot LCM(H_{b}, H_{c})}

        其中 LCM 表示的是最小公倍数函数。
        小蓝想要使得三枚宝石组合后的精美程度 S 尽可能的高,请你帮他找出精美程度最高的方案。如果存在多个方案 S 值相同,优先选择按照 H 值升序排列后字典序最小的方案。

输入格式

        第一行包含一个整数 N 表示宝石个数。

        第二行包含 N 个整数表示 N 个宝石的“闪亮度”。

输出格式

        输出一行包含三个整数表示满足条件的三枚宝石的“闪亮度”。

样例输入

5\\ 1 \hspace{0.5em} 2 \hspace{0.5em} 3 \hspace{0.5em} 4 \hspace{0.5em} 9

样例输出

1 \hspace{0.5em} 2 \hspace{0.5em} 3

评测用例规模与约定

        对于 30% 的评测用例:3 ≤ N ≤ 100,1 ≤ H_{i} ≤ 1000。
        对于 60% 的评测用例:3 ≤ N ≤ 2000。
        对于 100% 的评测用例:3 ≤ N ≤ 10^{5},1 ≤ H_{i} ≤10

F. 数字接龙(15分)

时间限制:1.0s        内存限制:256.0MB

问题描述

        小蓝最近迷上了一款名为《数字接龙》的迷宫游戏,游戏在一个大小为 N x N 的格子棋盘上展开,其中每一个格子处都有着一个 0 … K - 1 之间的整数。游戏规则如下:
        1. 从左上角(0,0)处出发,目标是到达右下角(N - 1,N - 1)处的格子,每一步可以选择沿着水平/垂直/对角线方向移动到下一个格子。
        2. 对于路径经过的棋盘格子,按照经过的格子顺序,上面的数字组成的序列要满足:0,1,2,...,K - 1,0,1,2,...,K - 1,0,1,2 ...。
        3. 途中需要对棋盘上的每个格子恰好都经过一次(仅一次)。
        4. 路径中不可以出现交叉的线路。例如之前有从(0,0)移动到(1,1),那么再从(1,0)移动到(0,1)线路就会交叉。
        为了方便表示,我们对可以行进的所有八个方向进行了数字编号,如下图 2 所示:因此行进路径可以用一个包含 0 ... 7 之间的数字字符串表示,如下图 1 是一个迷宫示例,它所对应的答案就是:41255214。

        现在请你帮小蓝规划出一条行进路径并将其输出。如果有多条路径,输出字典序最小的那一个:如果不存在任何一条路径,则输出 -1。

输入格式

        第一行包含两个整数 N,K。
        接下来输入 N 行,每行 N 个整数表示棋盘格子上的数字。

输出格式

        输出一行表示答案。如果存在答输出路径,否则输出 -1。

样例输入

3 \hspace{0.5em} 3\\ 0 \hspace{0.5em} 2 \hspace{0.5em} 0\\ 1 \hspace{0.5em} 1 \hspace{0.5em} 1\\ 2 \hspace{0.5em} 0 \hspace{0.5em} 2

样例输出

41255214

样例说明

        行进路径如图 1 所示。

评测用例规模与约定

        对于 80% 的评测用例:1 ≤ N ≤ 5。
        对于 100%的评测用例:1 ≤ N ≤ 10,1 ≤ K ≤ 10。

思路

        本题数据量非常小所以可以考虑直接搜索,深搜广搜应该都行,看个人习惯。

G. 爬山(20分)

时间限制:1.0s        内存限制:256.0MB

问题描述

        小明这天在参加公司团建,团建项目是爬山。在 x 轴上从左到右一共有座山,第 i 座山的高度为 h_{i}。他们需要从左到右依次爬过所有的山,需要花费的体力值为S = \sum_{i = 1}^{n}h_{i}
        然而小明偷偷学了魔法,可以降低一些山的高度。他掌握两种魔法,第一种魔法可以将高度为 H 的山的高度变为 \lfloor \sqrt{H} \rfloor,可以使用 P 次;第二种魔法可以将高度为 H 的山的高度变为 \lfloor \frac{H}{2} \rfloor,可以使用 Q 次。并且对于每座山可以按任意顺序多次释放这两种魔法。
        小明想合理规划在哪些山使用魔法,使得爬山花费的体力值最少。请问最优情况下需要花费的体力值是多少?

输入格式

        输入共两行。
        第一行为三个整数 n,P,Q。
        第二行为 n 个整数 h_{1}, h_{2}, \cdots, h_{n}

输出格式

        输出共一行,一个整数代表答案。

样例输入

4 \hspace{0.5em} 1 \hspace{0.5em} 1\\ 4 \hspace{0.5em} 5 \hspace{0.5em} 6 \hspace{0.5em} 49

样例输出

18

样例说明

        将第四座山变为 \lfloor \sqrt{49} \rfloor = 7,然后再将第四座山变为 \lfloor \frac{7}{2} \rfloor = 3
        体力值为 4 + 5 + 6 + 3 = 18。

评测用例规模与约定

        对于 20% 的评测用例,保证 n ≤ 8,P = 0。
        对于 100% 的评测用例,保证 n ≤ 100000,0 ≤ P ≤ n,0 ≤ Q ≤ n,0 ≤ h_{i} ≤ 100000。

代码

暴力代码

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 1e5 + 10;
int n, p, q, h[N], sum = 0;

inline int read() {
	int x = 0, f = 1; char c = getchar();
	while (c < '0' || c > '9') {
		if (c == '-') f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return x * f;
}

signed main() {
	n = read(), p = read(), q = read();
	for (int i = 1; i <= n; i++) h[i] = read();
	for (int i = 1; i <= p; i++) {
		sort(h + 1, h + n + 1);
		h[n] = sqrt(h[n]);
	}
	for (int i = 1; i <= q; i++) {
		sort(h + 1, h + n + 1);
		h[n] /= 2;
	}
	for (int i = 1; i <= n; i++) sum += h[i];
	printf("%lld", sum);
    return 0;
}

H. 拔河(20分)

时间限制:1.0s        内存限制:256.MB

问题描述

        小明是学校里的一名老师,他带的班级共有 n 名同学,第 i 名同学力量值为 a_{i}。在闲暇之余,小明决定在班级里组织一场拔河比赛。

        为了保证比赛的双方实力尽可能相近,需要在这 n 名同学中挑选出两个队伍,队伍内的同学编号连续:\{a_{l_{1}}, a_{l_{1} + 1}, \cdots, a_{r_{1} - 1}, a_{r_{1}}\} 和 \{a_{l_{2}}, a_{l_{2} + 1}, \cdots, a_{r_{2} - 1}, a_{r_{2}}\},其中 l_{1} \leq r_{1} \leq l_{2} \leq r_{2}
        两个队伍的人数不必相同,但是需要让队伍内的同学们的力量值之和尽可能相近。请计算出力量值之和差距最小的挑选队伍的方式。

输入格式

        输入共两行。
        第一行为一个正整数 n。
        第二行为 n 个正整数 a_{i}

输出格式

        输出共一行,一个非负整数,表示两个队伍力量值之和的最小差距。

样例输入

5\\ 10 \hspace{0.5em} 9 \hspace{0.5em} 8 \hspace{0.5em} 12 \hspace{0.5em} 14

样例输出

1

样例说明

        其中一种最优选择方式:
        队伍 1:\{a_{1}, a_{2}, a_{3}\},队伍 2:\{a_{4}, a_{5}\},力量值和分别为 10 + 9 + 8 = 27,12 + 14 = 26,差距为|27 - 26| = 1。

评测用例规模与约定

        对于 20% 的评测用例,保证 n ≤ 50。
        对于 100% 的评测用例,保证 n ≤ 10^{3},a ≤ 10^{9}

快读模板

inline int read() {
	int x = 0, f = 1; char c = getchar();
	while (c < '0' || c > '9') {
		if (c == '-') f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
}

        如果题目中有的变量需要用 long long 的话,可以直接在宏里面把 int 扩展到 long long,这样比较方便(如下图)。

#include <bits/stdc++.h>
using namespace std;

#define int long long

inline int read() {
	int x = 0, f = 1; char c = getchar();
	while (c < '0' || c > '9') {
		if (c == '-') f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
}

// 代码

signed main() {
    // 代码
    return 0;
}

对拍代码

        整个对拍需要以下文件。bf.cpp文件里是暴力代码,std.cpp文件里是用了算法的代码,data.cpp用来生成输入样例,pai.cpp用来比较bf.cpp和stdcpp.out的结果是否相同。

        注意:每次更改bf.cpp,std.cpp或data.cpp之后都需要重新编译之后再运行pai.cpp进行对拍。

        接下来以输出 a + b 的程序来说明。

bf.cpp

#include <bits/stdc++.h>
using namespace std;

int main() {
	int a, b, oup = 0;
	cin >> a >> b;
	for (int i = 1; i <= a; i++) oup++;
	for (int i = 1; i <= b; i++) oup++;
	cout << oup;
	return 0;
}

std.cpp

#include <bits/stdc++.h>
using namespace std;

int main() {
	int a, b;
	cin >> a >> b;
	if (a > 0) cout << a << endl;
	cout << a + b << endl;
	return 0;
}

data.cpp

#include <bits/stdc++.h>
using namespace std;

int main() {
	srand(time(0));
	int a = rand(), b = rand(); // 随机生成两个数字
	cout << a << ' ' << b << endl; // 按照格式输出
	return 0;
}

pai.cpp

可以不用自己创建txt文件,编译运行一次pai.cpp之后会自动生成相应txt文件

#include <bits/stdc++.h>
using namespace std;

int main() {
	int t = 1;
	while (1) {
		printf("test%d: ", t++);
		system("data.exe > in.txt"); // 用 data.exe 生成输入样例,并存入 in.txt 文件中
		system("std.exe < in.txt > stdout.txt");
        // 将 in.txt 文件中的输入样例用来测试 std.cpp 中的代码,并将结果输出到 stdout.txt 文件中
		system("bf.exe < in.txt > bfout.txt");
        // 将 in.txt 文件中的输入样例用来测试 bf.cpp 中的代码,并将结果输出到 bf.out 文件中

        // 比较 stdout.txt 和 bfout.txt 文件是否一样,一样返回 false,不一样返回 true
		if (system("fc stdout.txt bfout.txt")) {
			cout << "WA\n";
			return 0;
		}
		cout << "AC\n";
	}
	cout << "AC\n";
}

        下图是pai.cpp运行后的输出结果,会显示WA和输出不一样的地方。

        如果输出样例一样的话,会一直显示AC。 

这个时候接着写下一道题就好了,让它在后台接着运行,有可能后面会出现不一样的地方。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值