蓝桥杯2024年第十五届省赛真题

一、好数

题目描述

一个整数如果按从低位到高位的顺序,奇数位(个位、百位、万位 · · · )上的数字是奇数,偶数位(十位、千位、十万位 · · · )上的数字是偶数,我们就称之为“好数”。给定一个正整数 N,请计算从 1 到 N 一共有多少个好数。

输入格式

一个整数 N。

输出格式

一个整数代表答案。

样例输入

复制

24

样例输出

复制

7

提示

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

最终代码: 

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


//1 3 5 7 9 - >5
//2 4 6 8 0 - >5

//10->5  35 0->5 + 2->5 355 ->300,1*5*5 3  +3*5 + 5 3
//25+15

int main(){
	int N;
	cin>>N;
	string odd = "13579";
	string even = "02468";
	int res = 0;
	for(int i=0;i<=N;i++){
		//TODO
		string s = to_string(i);
		bool flag = true;
		for(int i=s.size()-1,j=s.size()-2;i>=0;i-=2,j-=2){
			if((odd.find(s[i])==string::npos&&i>=0)||(even.find(s[j])==string::npos&&j>=0)){
				flag = false;
				break;
			}
			else{
				continue;
				
			}
				
		}
		if(flag){
			res++;
		}
	}
	cout<<res;
	
	
	return 0;
}

二、R 格式 

题目描述

小蓝最近在研究一种浮点数的表示方法:R 格式。对于一个大于 0 的浮点数 d,可以用 R 格式的整数来表示。给定一个转换参数 n,将浮点数转换为 R格式整数的做法是:

1. 将浮点数乘以 2n;

2. 四舍五入到最接近的整数。

输入格式

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

输出格式

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

样例输入

复制

2 3.14

样例输出

复制

13

提示

【样例说明】

3.14 × 22 = 12.56,四舍五入后为 13。

【评测用例规模与约定】

对于 50% 的评测用例:1 ≤ n ≤ 10,1 ≤ 将 d 视为字符串时的长度 ≤ 15。

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

最终代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>

using namespace std;

int n;
string str;

vector<int> add(vector<int> A, vector<int> B)
{
	vector<int> C;
	for (int i = 0, t = 0; i < A.size() || i < B.size() || t; ++ i )
	{
		if (i < A.size())
			t += A[i];
		if (i < B.size())
			t += B[i];
		C.push_back(t % 10);
		t /= 10;
	}
	
	return C;
}

int main()
{
	cin >> n >> str;
	
	int k = str.size() - 1;
	while (str[k] != '.')
		k --;
	str.erase(k, 1);
	
	k = str.size() - k;
	
	vector<int> A;
	for (int i = str.size() - 1; i >= 0; -- i )
		A.push_back(str[i] - '0');
	
	while (n -- )
		A = add(A, A);
	
	int p = A[k - 1];
	reverse(A.begin(), A.end());
	while (k -- )
		A.pop_back();
	reverse(A.begin(), A.end());
	
	if (p >= 5)
		A = add(A, {1});
	
	for (int i = A.size() - 1; i >= 0; -- i )
		cout << A[i];
	
	return 0;
}

三、宝石组合 

题目描述

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

蓝桥杯2024年第十五届省赛真题-宝石组合

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

输入格式

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

输出格式

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

样例输入

复制

5
1 2 3 4 9

样例输出

复制

1 2 3

提示

【评测用例规模与约定】

对于 30% 的评测用例:3 ≤ N ≤ 100,1 ≤ Hi ≤ 1000。

对于 60% 的评测用例:3 ≤ N ≤ 2000。

对于 100% 的评测用例:3 ≤ N ≤ 105,1 ≤ Hi ≤ 105。

最初33分的代码:

#include <bits/stdc++.h>

using namespace std;

using ll = long long;

int gcd(ll a,ll b)
{
	return b?gcd(b,a%b):a;
}



int gcd3(int a, int b, int c)
{
	return gcd(gcd(a, b), c);
}

int main()
{
	ios::sync_with_stdio(false);
	cout.tie(nullptr);
	ll n;
	cin >> n;
	ll ar[100001],b[100001];
	for(int i=0;i<n;i++){
		cin>>ar[i];
		
	}
	sort(ar,ar+n);
	ll ans = 0;
	for (int i = 0; i < n; i++)
	{
		for (int j = i + 1; j < n; j++)
		{
			for (int k = j + 1; k < n; k++)
			{
				int s = gcd3(ar[i], ar[j], ar[k]);
				if (s > ans)
				{
					ans = s;
					b[0] = ar[i];
					b[1] = ar[j];
					b[2] = ar[k];
				}
			}
		}
	}

	cout<<b[0]<<" "<<b[1]<<" "<<b[2];
	return 0;
}

上面实际上是过不了1e5的,肯定会超时,用逆向做就可以了

#include <bits/stdc++.h>
using namespace std;
const int h = 1e5;
int main()
{
	// m记录宝石个数
	int n, m[h + 1] = {}, t, max = 0;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		// 亮度为t的宝石个数
		cin >> t;
		m[t]++;
		// 精美程度一定小于等于最大的亮度
		if (t > max)
			max = t;
	}
	// 假设精美程度为i,从大到小遍历i的所有可能值
	for (int i = max; i >= 1; i--)
	{
		int ans = 0, cnt = 0, num[3] = {};
		for (int j = i; j <= max; j += i)
		{
			// 若m[j]有值,则找到m[j]个j的宝石
			ans += m[j];
			// 统计找到的宝石,直到三枚
			for (int k = 0; k < m[j] && cnt < 3; k++)
				num[cnt++] = j;
			// 找到了三枚宝石,输出
			if (ans >= 3)
			{
				cout << num[0] << " " << num[1] << " " << num[2];
				return 0;
			}
		}
	}
	return 0;
}

 四、数字接龙

题目描述 

小蓝最近迷上了一款名为《数字接龙》的迷宫游戏,游戏在一个大小为N × 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。

蓝桥杯2024年第十五届省赛真题-数字接龙

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

输入格式

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

输出格式

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

样例输入

复制

3 3
0 2 0
1 1 1
2 0 2

样例输出

复制

41255214

提示

【样例说明】行进路径如图 1 所示。
【评测用例规模与约定】对于 80% 的评测用例:1 ≤ N ≤ 5。对于 100% 的评测用例:1 ≤ N ≤ 10,1 ≤ K ≤ 10。

最终代码: 

#include<bits/stdc++.h> // 引入整个标准库和C++ STL库
using namespace std; // 使用标准命名空间

int g[11][11]; // 棋盘,存储每个格子的数字
int d[11][11]; // 访问标记,表示当前格子是否已访问
int st[11][11]; // 状态数组,存储到达每个格子的方向
vector<int> path; // 存储最终的路径

// 移动方向的偏移量,dx 和 dy 分别表示 x 和 y 轴上的偏移
int dx[] = {-1, -1, 0, 1, 1, 1, 0, -1};
int dy[] = {0, 1, 1, 1, 0, -1, -1, -1};

int n, k; // n 是棋盘的大小,k 是棋盘上数字的最大值

bool dfs(int x, int y, int cnt) { // 深度优先搜索函数
    if (x == n - 1 && y == n - 1 && cnt == n * n) // 如果到达棋盘底部的最后一个格子,并且格子数量符合,返回 true
        return true;
    for (int i = 0; i < 8; i++) { // 遍历所有八个方向
        int tx = x + dx[i]; // 计算目标x坐标
        int ty = y + dy[i]; // 计算目标y坐标
        // 检查目标位置是否在棋盘内,未被访问,并且满足数字序列条件
        if (tx >= 0 && tx < n && ty >= 0 && ty < n && d[tx][ty] == 0 &&
            ((g[x][y] == k - 1 && g[tx][ty] == 0) || g[tx][ty] == g[x][y] + 1)) {
            // 检查当前方向是否会导致路径交叉
            if (i == 1 && (st[x - 1][y] == 3 || st[x][y + 1] == 7))
                continue; // 从当前格子向右移动,检查是否与之前的路径交叉
            if (i == 3 && (st[x + 1][y] == 1 || st[x][y + 1] == 5))
                continue; // 从当前格子向下移动,检查是否与之前的路径交叉
            if (i == 5 && (st[x][y - 1] == 3 || st[x + 1][y] == 7))
                continue; // 从当前格子向左下移动,检查是否与之前的路径交叉
            if (i == 7 && (st[x][y - 1] == 1 || st[x - 1][y] == 5))
                continue; // 从当前格子向左上移动,检查是否与之前的路径交叉
            st[x][y] = i; // 记录当前格子的方向
            d[tx][ty] = 1; // 标记目标格子为已访问
            path.push_back(i); // 将方向编号添加到路径中
            if (dfs(tx, ty, cnt + 1)) // 递归搜索下一个位置
                return true; // 如果找到路径,则返回 true
            path.pop_back(); // 回溯,移除路径中的最后一个方向编号
            d[tx][ty] = 0; // 回溯,重置目标格子的访问标记
            st[x][y] = -1; // 回溯,重置当前格子的方向
        }
    }
    return false; // 如果所有方向都不是解决方案,则返回 false
}

int main() {
    cin >> n >> k; // 读取棋盘大小和数字的最大值
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> g[i][j]; // 填充棋盘
        }
    }
    // 检查棋盘右下角的数字是否为 k-1,如果不是,则无法形成合法路径,输出-1
    if (g[n - 1][n - 1] != k - 1) {
        cout << -1;
        return 0;
    }
    memset(st, -1, sizeof st); // 初始化状态数组,所有值设为 -1
    d[0][0] = 1; // 标记起始格子为已访问
    if (dfs(0, 0, 1)) { // 从(0, 0)开始深度优先搜索
        for (auto i : path) // 输出找到的路径
            cout << i;
    } else {
        cout << -1; // 如果没有找到路径,输出-1
    }
    return 0;
}

五、爬山 

题目描述

小明这天在参加公司团建,团建项目是爬山。在 x 轴上从左到右一共有 n座山,第 i 座山的高度为 hi。他们需要从左到右依次爬过所有的山,需要花费的体力值为 S = Σni=1hi。

然而小明偷偷学了魔法,可以降低一些山的高度。他掌握两种魔法,第一种魔法可以将高度为 H 的山的高度变为 ⌊√H⌋,可以使用 P 次;第二种魔法可以将高度为 H 的山的高度变为 ⌊H/2⌋,可以使用 Q 次。并且对于每座山可以按任意顺序多次释放这两种魔法。

小明想合理规划在哪些山使用魔法,使得爬山花费的体力值最少。请问最优情况下需要花费的体力值是多少?

输入格式

输入共两行。

第一行为三个整数 n,P,Q。

第二行为 n 个整数 h1,h2,. . . ,hn。

输出格式

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

样例输入

复制

4 1 1
4 5 6 49

样例输出

复制

18

提示

【样例说明】将第四座山变为 ⌊√49⌋ = 7,然后再将第四座山变为 ⌊7/2⌋ = 3。体力值为 4 + 5 + 6 + 3 = 18。

【评测用例规模与约定】

对于 20% 的评测用例,保证 n ≤ 8,P = 0。

对于 100% 的评测用例,保证 n ≤ 100000,0 ≤ P ≤ n,0 ≤ Q ≤ n,0 ≤ hi ≤ 100000。

 最终代码:

纯贪心,这样能拿92分,其实知道是哪种问题了导致过不了了,但是会超时 

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

int main()
{
    int n, P, Q;
    long long ans = 0;
    priority_queue<int> h;
    cin >> n >> P >> Q;
    for (int i = 0; i < n; i++)
    {
        int hi;
        cin >> hi;
        h.push(hi);
    }
    while (P || Q)
    {
        //取出第一个数
        int first = h.top();
        h.pop();
        //对最高的山进行两种操作,哪种更矮就用哪种
        if (P && Q)
        {
            if (sqrt(first) <= first / 2)
            {
                h.push(sqrt(first));
                P--;
            }
            else
            {
                h.push(first / 2);
                Q--;
            }
        }
        //如果只剩一种魔法了,就直接用
        else if (P)
        {
            h.push(sqrt(first));
            P--;
        }
        else if (Q)
        {
            h.push(first / 2);
            Q--;
        }
    }
    while (!h.empty())
    {
        ans += h.top();
        h.pop();
    }
    cout << ans;
    return 0;
}

 

 六、拔河

题目描述

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

为了保证比赛的双方实力尽可能相近,需要在这 n 名同学中挑选出两个队伍,队伍内的同学编号连续:{al1, al1+1, ..., ar1−1, ar1} 和 {al2, al2+1, ..., ar2−1, ar2},其中 l1 ≤ r1 < l2 ≤ r2。

两个队伍的人数不必相同,但是需要让队伍内的同学们的力量值之和尽可能相近。请计算出力量值之和差距最小的挑选队伍的方式。

输入格式

输入共两行。

第一行为一个正整数 n。

第二行为 n 个正整数 ai。

输出格式

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

样例输入

复制

5
10 9 8 12 14

样例输出

复制

1

提示

【样例说明】

其中一种最优选择方式:队伍 1:{a1, a2, a3},队伍 2:{a4, a5},力量值和分别为 10 + 9 + 8 = 27,12 + 14 = 26,差距为 |27 − 26| = 1。

【评测用例规模与约定】

对于 20% 的评测用例,保证 n ≤ 50。

对于 100% 的评测用例,保证 n ≤ 103,ai ≤ 109。

 

最终代码: 

 



#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int n=1e6;
int a,b[n],c; 
signed main()
{
	cin>>a;
	for(int i=1;i<=a;i++)
	{
		cin>>b[i];
	}
	set<int>t;
	int an=1e18;
	for(int i=a;i>=1;i--)
	{
		int v=0;
		for(int j=i+1;j<=a;j++)
		{
			v+=b[j];
			t.insert(v);
		}
		v=0;
		for(int j=i;j>=1;j--)
		{
			v+=b[j];
			if(t.size()==0)
			{
				continue;
			}
			if(v>*t.rbegin())
            {
                an=min(an,v-*t.rbegin());
            }
            else if(v<=*t.begin())
            {
                an=min(an,*t.begin()-v);
        	}
			else
			{
				auto s=t.lower_bound(v);
				an=min(an,*s-v);
				s--;
				an=min(an,v-*s);
			}
		
		}
	}
	cout<<an<<endl;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

像污秽一样

谢谢谢谢谢谢谢谢谢谢谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值