第十七届蓝桥杯C/C++A组省赛

前几天,蓝桥杯国赛的成绩出了,拿了国三,有点小遗憾但也在预料之内吧

不过成绩出了不代表都结束了,还是要复盘,就从省赛开始吧,省赛我拿了是省一,但是回过头来才发现其实还是有不少不会的地方,所以来总结一下吧,这次就不发截图了,直接给洛谷上的链接吧

A题:均衡数

由于 2026202620262026 的二进制有 51 位,且一个均衡数的二进制长度必须是偶数,故我们只需要构造二进制为 50 位的最大的均衡数,以及二进制为 52 位最小的均衡数。

想要最大我们就要让尽量让高位是 1,低位是 0。想要最小我们就要让尽量让高位是 0,低位是 1。但最高位不能为 0。所以我们只要让最高位是 1,后面跟 26 个 0,最后再跟 25 个 1 就行。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
	cout<<2251799847239679<<endl;
	return 0;
}

C题:拦截系统

这个也比较简单,签到题吧

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL l,t,v;
int main()
{
	int n;
	cin>>n;
	while(n--)
	{
		cin>>l>>t>>v;
		LL s=t*v*2;
		l-=s;
		cout<<l/2+l%2<<endl;
	}
	return 0;
}

D题:切割木材

这个就是比较经典的二分嘛

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
typedef long long LL;
LL a[N];
LL n,k;
bool check(int x)
{
	LL res=0;
	for(int i=1;i<=n;i++)
	{
		res+=a[i]/x-1+(a[i]%x!=0);
	}
	return res<=k;
}
int main()
{
	cin>>n>>k;
	LL l=0,r=0;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		r=max(r,a[i]);
	}
	LL ans=-1;
	while(l<=r)
	{
		//cout<<l<<' '<<r<<endl;
		LL mid=l+r>>1;
		if(!check(mid))
		{
			l=mid+1;
		}
		else
		{
			ans=mid;
			r=mid-1;
		}
	}
	cout<<ans<<endl;
	return 0;
}

E题:读取指令

这个题,我一开始以为挺简单,以为就是个简单贪心,刚才做了一下才发现是比赛时做错了,这是一个数学问题

首先如果 w 不是 c 的倍数肯定 −1,否则令 x=cw​。

如果 1+2+⋯+n=2n(n+1)​<x,也是无解。

如果 w=0,答案是 0。(赛时代码好像没考虑这个,寄)

否则,下面证明答案最多是 2。

由于 2n(n+1)​≥x,因此一定存在一个 1≤m<n,使得:

  • 1+2+⋯+m=2m(m+1)≤x;
  • 1+2+⋯+(m+1)>x。

我们可以证明 y=1+2+⋯+(m+1)−x=(m+1)−x−(1+2+⋯m)≤(m+1),我们把 (m+1) 补上,再把 y 删去,最多两个区间。

所以答案不是 1 就是 2。开 map 记录一下前缀和,即可判断一个区间是否可行,可行则为 1,否则为 2。

cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T;
    cin >> T;
    while (T--) {
        int N, C;
        long long W;
        cin >> N >> C >> W;

        // 边界1:不需要读取
        if (W == 0) {
            cout << "0\n";
            continue;
        }
        // 边界2:无法整除C,无解
        if (W % C != 0) {
            cout << "-1\n";
            continue;
        }

        long long x = W / C;
        long long total = (long long)N * (N + 1) / 2;
        // 边界3:总和不足,无解
        if (x > total) {
            cout << "-1\n";
            continue;
        }

        // 双指针判断是否存在单个连续区间和为x
        long long sum = 0;
        int l = 1;
        bool found = false;
        for (int r = 1; r <= N; ++r) {
            sum += r;
            while (sum > x) {
                sum -= l;
                l++;
            }
            if (sum == x) {
                found = true;
                break;
            }
        }

        cout << (found ? 1 : 2) << '\n';
    }
    return 0;
}

F题:外卖配送

考虑使用动态规划。

  • 状态定义: fi 表示送 i 单所需的时间;
  • 状态转移: fi←fj+ci−j+x,其中 ci 表示单个交通工具送完 i 单所需的最短时间,j 是枚举的单数;
  • 最终答案:fn。
cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, m, x, f[5005], c[5005];
signed main() {
    memset(c, 0x3f, sizeof c);
    cin >> n >> m >> x;
    for (int i = 1, a, b; i <= m; ++i) {
        cin >> a >> b;
        for (int j = 1; j <= n; ++j) {
            c[j] = min(c[j], j * a + j * (j - 1) / 2 * b); // 预处理
        }
    }
    for (int i = 1; i <= n; ++i) {
        f[i] = c[i];
        for (int j = 1; j < i; ++j) {
            f[i] = min(f[i], f[j] + c[i - j] + x); // 状态转移
        }
    }
    cout << f[n];
    return 0;
}

好的,现在比赛中黄题难度及以下,以及我比赛时会的题目就已经说完了,这些题如果都拿下其实就能稳稳省一了,我现在回过头来发现,我当时应该就是A,C,D,F题做对了,G暴力得了一半分,拿了省一

相关推荐
Brilliantwxx1 小时前
【C++】 C++11 知识点梳理(上)
开发语言·c++
帅小伙―苏1 小时前
力扣76最小覆盖子串
算法·leetcode
RH2312112 小时前
2026.5.24 数据结构 KMP算法实现
数据结构·算法
江屿风2 小时前
C++图论基础单源最短路-常规版dijkstra算法/堆优化版dijkstra算法/bellman-ford 算法/spfa 算法流食般投喂
开发语言·c++·笔记·算法·图论
Molesidy2 小时前
【Linux】【C++】Linux下的C++编程以及基于GDB的VSCode的C++调试
开发语言·c++
浮芷.2 小时前
鸿蒙 6.1 新特性-60fps流畅人物跳跃功能算法深度解析-鸿蒙PC端正弦值计算法
算法·华为·harmonyos·鸿蒙·鸿蒙系统
程序猿编码2 小时前
子域猎手:一款高性能DNS枚举工具的设计与实现
linux·c++·python·c·dns
Mortalbreeze2 小时前
C++11类的新特性:移动语义、default、delete、override详解
开发语言·c++
Frank学习路上2 小时前
【C++】面试:面向对象与多态
c++·面试