2021年蓝桥杯省赛 C++ B组

目录

 1550: [蓝桥杯2021初赛] 卡片

 1551: [蓝桥杯2021初赛] 直线

 1552: [蓝桥杯2021初赛] 货物摆放

1553: [蓝桥杯2021初赛] 路径

 1555: [蓝桥杯2021初赛] 空间

1563: [蓝桥杯2021初赛] 时间显示


 1550: [蓝桥杯2021初赛] 卡片

题目描述

小蓝有很多数字卡片,每张卡片上都是数字0 到9。
小蓝准备用这些卡片来拼一些数,他想从1 开始拼出正整数,每拼一个,就保存起来,卡片就不能用来拼其它数了。
小蓝想知道自己能从1 拼到多少。
例如,当小蓝有30 张卡片,其中0 到9 各3 张,则小蓝可以拼出1 到10,但是拼11 时卡片1 已经只有一张了,不够拼出11。
现在小蓝手里有0 到9 的卡片各2021 张,共20210 张,请问小蓝可以从1拼到多少?
提示:建议使用计算机编程解决问题。

答案:3181

#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
 
int main()
{
	int arr[10];
	for (int i = 0; i < 10; i++)
	{
		arr[i] = 2021; // 0 - 9 的卡片各2021张 
	}
	for (int i = 1; ; i++)
	{
		int x = i;
		while(x != 0)
		{
			if(arr[x % 10] == 0)
			{
			//当有一张卡片的数量剩余为0时候 输出 i-1并退出 
				cout << i - 1;
				return 0; 
			} 
			arr[x % 10]--;//每张卡片数量减少1 
			x /= 10;
		}
	}
	return 0;
}

 思路因为1是排在最前面的,即1是最先进行消耗完毕的,所以我们只要记录下来1最后用尽的那一数是多少就是要求的结果 

#include <iostream>
using namespace std;
 
int main()
{
	int sum = 2021, ans = 0;
	for (int i = 1; i < 20210; i++) {
		int temp = i;
		while(temp != 0) {
			if(temp % 10 == 1 && sum > 0) {
				sum--;
			}
			temp /= 10;
		}
		if(sum == 0){
			ans = i;
			break;	
		} 
	} 
	cout << ans;
}

 1551: [蓝桥杯2021初赛] 直线

题目描述

在平面直角坐标系中,两点可以确定一条直线。
如果有多点在一条直线上,那么这些点中任意两点确定的直线是同一条。
给定平面上2 × 3 个整点{(x, y)|0 ≤ x < 2, 0 ≤ y < 3, x ∈ Z, y ∈ Z},
即横坐标是0 到1 (包含0 和1) 之间的整数、纵坐标是0 到2 (包含0 和2) 之间的整数的点。
这些点一共确定了11 条不同的直线。
给定平面上20 × 21 个整点{(x, y)|0 ≤ x < 20, 0 ≤ y < 21, x ∈ Z, y ∈ Z},
即横坐标是0 到19 (包含0 和19) 之间的整数、纵坐标是0 到20 (包含0 和20) 之间的整数的点。
请问这些点一共确定了多少条不同的直线。

答案:40257

思路:用set去重 找斜率和截距

#include <iostream>
#include <set>
using namespace std;

const int N = 500;

set<pair<double,double>> s;//存斜率和截距 去重

class Node {
public:
	double x, y;// i横坐标, j纵坐标
};

int main()
{
	Node p[N];
	int cnt = 0;
	int m = 20, n = 21;
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			p[cnt].x = i;
			p[cnt].y = j;
			cnt++;
		}
	}
	for (int i = 0; i < cnt; i++) {
		for (int j = 0; j < cnt; j++) {
			if (p[i].x == p[j].x || p[i].y == p[j].y) //x轴或者y轴
				continue;
			double k = (p[j].y - p[i].y) / (p[j].x - p[i].x);
			double b = (p[j].x * p[i].y - p[j].y * p[i].x) / (p[j].x - p[i].x);
            //double b = (p[i].y * (p[j].x - p[i].x) - p[i].x * (p[j].y - p[i].y)) / (p[j].x - p[i].x);
			s.insert(make_pair(k, b));
		}
	}
	cout << m + n + s.size() << endl;
	return 0;
}

 1552: [蓝桥杯2021初赛] 货物摆放

题目描述

小蓝有一个超大的仓库,可以摆放很多货物。
现在,小蓝有n 箱货物要摆放在仓库,每箱货物都是规则的正方体。
小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。
小蓝希望所有的货物最终摆成一个大的立方体。即在长、宽、高的方向上分别堆L、W、H 的货物,满足n = L × W × H。
给定n,请问有多少种堆放货物的方案满足要求。
例如,当n = 4 时,有以下6 种方案:1×1×4、1×2×2、1×4×1、2×1×2、2×2×1、4×1×1。
请问,当n = 2021041820210418 (注意有16 位数字)时,总共有多少种
方案?
提示:建议使用计算机编程解决问题。

答案:2430

思路:先求出它的所有因子,然后循环遍历即可

#include <iostream>
#include <vector>
using namespace std;

typedef long long ll;

int main()
{
    ll n = 2021041820210418;
    ll cnt = 0;
    vector<ll> v;
    for (ll i = 1; i <= n / i; i++) {
        if (n % i == 0) {
            v.push_back(i);
            if (i * i != n)
                v.push_back(n / i);
        }

    }
    for (ll i = 0; i < v.size(); i++) {
        for (ll j = 0; j < v.size(); j++) {
            for (ll k = 0; k < v.size(); k++) {
                if (v[i] * v[j] * v[k] == n)
                    cnt++;
            }
        }
    }
    cout << cnt;
    return 0;
}

 思路2

//核心:通过判断三个数出现的组合次数。
#include <iostream>
using namespace std;

typedef long long LL;

int main()
{
    LL n = 2021041820210418;
    LL i, j, k;
    int res = 0;
    for (i = 1; i * i * i <= n; i++)
        if (n % i == 0)
            for (j = i; i * j * j <= n; j++)
                if (n / i % j == 0)
                {
                    k = n / i / j;
                    if (i == j && i == k) res++;
                    if (i == j || i == k || j == k) res += 3;
                    else res += 6;
                }
    printf("%d", res);

    return 0;
}

1553: [蓝桥杯2021初赛] 路径

题目描述

小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图中的最短路径。
小蓝的图由2021 个结点组成,依次编号1 至2021。
对于两个不同的结点a, b,如果a 和b 的差的绝对值大于21,则两个结点之间没有边相连;
如果a 和b 的差的绝对值小于等于21,则两个点之间有一条长度为a 和b 的最小公倍数的无向边相连。
例如:结点1 和结点23 之间没有边相连;结点3 和结点24 之间有一条无向边,长度为24;
结点15 和结点25 之间有一条无向边,长度为75。
请计算,结点1 和结点2021 之间的最短路径长度是多少。
提示:建议使用计算机编程解决问题。

答案:10266837

思路:这是一道最短路的简化题 用floyd或者dijkstra都可,但因为是一道填空题 用floyd跑也可以,不过大概需要半分钟的时间

floyd算法

#include <iostream>
#include <cstring>
using namespace std;

const int MAXN = 2500;
int Graph[MAXN][MAXN];//邻接矩阵

int gcd(int a, int b)//最大公约数
{
	return b == 0 ? a : gcd(b, a % b);
}

void init()
{
	memset(Graph, 0x3f, sizeof(Graph));
	for (int i = 1; i <= 2021; i++) {
		for (int j = 1; j <= 2021; j++) {
			if (abs(i - j) <= 21) {
				Graph[i][j] = Graph[j][i] = (i * j) / gcd(i, j);
			}
		}
	}
}

void floyd()//时间复杂度比较大 要跑半分钟左右
{
	for (int k = 1; k <= 2021; k++) {
		for (int i = 1; i <= 2021; i++) {
			for (int j = 1; j <= 2021; j++) {
				Graph[i][j] = min(Graph[i][j], Graph[i][k] + Graph[k][j]);
			}
		}
	}
}
int main()
{
	init();

	floyd();

	cout << Graph[1][2021];
}

 dijkstra算法

#include <iostream>
#include <algorithm>
#include <cstring> 
using namespace std;

const int INF = 0x3f3f3f3f;
const int MAXN = 2500;
int Graph[MAXN][MAXN], dis[MAXN];
bool vis[MAXN];

int gcd(int a, int b)//最大公约数
{
	return b == 0 ? a : gcd(b, a % b);
}

void init()
{
	memset(Graph, 0x3f, sizeof(Graph));
	for (int i = 1; i <= 2021; i++) {
		for (int j = 1; j <= 2021; j++) {
			if (i == j)
				Graph[i][j] = 0;
			else if (abs(j - i) > 21)
				Graph[i][j] = Graph[j][i] = INF;
			else
				Graph[i][j] = Graph[j][i] = i * j / gcd(i, j);
		}
	}
}

void dijkstra()
{
	memset(dis, 0x3f, sizeof(dis));
	dis[1] = 0;
	for (int i = 1; i <= 2021; i++) {
		int t = -1;
		for (int j = 1; j <= 2021; j++) {
			if (!vis[j] && (t == -1 || dis[j] < dis[t]))
				t = j;
		}
		vis[t] = true;
		for (int j = 1; j <= 2021; j++) {
			if (!vis[j]) {
				dis[j] = min(dis[j], dis[t] + Graph[t][j]);
			}
		}
	}
}
int main()
{
	init();

	dijkstra();

	cout << dis[2021] << endl;

	return 0;
}

 1555: [蓝桥杯2021初赛] 空间

题目描述

小蓝准备用256MB 的内存空间开一个数组,数组的每个元素都是32 位二进制整数。
如果不考虑程序占用的空间和维护内存需要的辅助空间,请问256MB 的空间可以存储多少个32 位二进制整数?

根据换算关系:
B代表字节,b代表位,即32位4个字节

1MB=1024KB,  1KB=1024B, 1B(字节)=8b=8位
由题意知:
256MB=256×1024KB=256×1024×1024B=256×1024×1024×8b=256×1024×1024×8位
一个元素 = 32位
可以储存(个)=256×1024×1024×8/32(个)
 

答案:256 * 1024 * 1024 * 8 / 32 = 67108864

1563: [蓝桥杯2021初赛] 时间显示

题目描述

小蓝要和朋友合作开发一个时间显示的网站。

在服务器上,朋友已经获取了当前的时间,用一个整数表示,值为从 19701970 年 11 月 11 日 00:00:0000:00:00 到当前时刻经过的毫秒数。

现在,小蓝要在客户端显示出这个时间。小蓝不用显示出年月日,只需要显示出时分秒即可,毫秒也不用显示,直接舍去即可。

给定一个用整数表示的时间,请将这个时间对应的时分秒输出。

输入描述

输入一行包含一个整数,表示时间。

输出描述

输出时分秒表示的当前时间,格式形如 HH:MM:SS,其中 HH 表示时,值为 00​​​​ 到 2323​​​​,MM 表示分,值为 00​​​​ 到 5959​​​,SS 表示秒,值为 00​​ 到 5959​。时、分、秒 不足两位时补前导 00。

输入输出样例

输入样例1

46800999

输出样例 1

13:00:00

 输入样例2

1618708103123

输出样例2

01:08:23

 思路:模拟即可,需要注意的是1s = 1000ms

#include <iostream>
using namespace std;

typedef long long ll;

int main()
{
	ll time, hour, minute, seconds;
	cin >> time;
	time = time / 1000;//转化为秒
	hour = (time / 3600) % 24;
	minute = (time / 60) % 60;
	seconds = time % 60;
	printf("%02lld:%02lld:%02lld", hour, minute, seconds);
	return 0;
}

​​​​​​​

  • 11
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值