2025年第十六届蓝桥杯国赛C/C++大学B组个人题解

写在前面

今年国赛刚刚结束,忍不住抒发一下感想。主要就是一个重大失误和一个创造奇迹。

题解和代码(回忆版)

两道填空题一眼没思路,直接看编程题,后面也没时间再看了,扫了一眼感觉不好蒙,就空着了。

试题 C: 数字轮盘

我是在草稿纸上手动模拟来找规律,写了一页A4纸大小的草稿,花了一个半小时之久。可以发现,“操作”的作用就是将最后两个数字移到最前面。接着想办法把各种情况对应过去即可。注意,当 n 为偶数而  k 为奇数时,无法恢复原样。

#include <iostream>

using namespace std;

void solve()
{
	int n,k;
	cin>>n>>k;

	if(k%n==0)
	{
		cout<<0<<'\n';
		return;
	}

	if(n%2==1)
	{
		if(k%n%2==0) cout<<(2*n-k%n)/2;
		else cout<<(n-k%n)/2;
		cout<<'\n';
	}
	else
	{
		if(k%2==1)
		{
			cout<<-1<<'\n';
			return;
		}

		cout<<(n-k%n)/2<<'\n';
	}
}

int main()
{
    int t;
    cin>>t;
    while(t--)
	{
		solve();
	}
    return 0;
}


在洛谷跑的是满分,应该问题不大。

试题 D: 斐波那契字符串

这题思路还是挺简单的,看代码即可了解,是动态规划的思想。当然,我做的时候没想什么动态规划,当成思维题做了。

然而我犯了一个重大错误。代码如下。

#include <iostream>
#define int long long
using namespace std;

const int N = 1e9 + 7;

void solve()
{
    int n;
    cin >> n;
    int a_cnt0 = 1, a_cnt1 = 0, a_sum = 0;
    int b_cnt0 = 0, b_cnt1 = 1, b_sum = 0;
    int cnt0 = 0, cnt1 = 0, sum = 0;
    for (int i = 3; i <= n; ++i)
    {
        cnt0 = (a_cnt0 + b_cnt0) % N;
        cnt1 = (a_cnt1 + b_cnt1) % N;

        sum = (a_sum + b_sum + a_cnt1 * b_cnt0 % N) % N;

        a_cnt0 = b_cnt0;
        a_cnt1 = b_cnt1;
        a_sum = b_sum;

        b_cnt0 = cnt0;
        b_cnt1 = cnt1;
        b_sum = sum;
    }
    cout << sum << '\n';
}

signed main()
{
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

只拿到四分之一的分,其他都超时了。问题在于,我每个测试用例都跑了一遍循环,没有想到可以先把数据范围内的所有答案跑出来存起来,这样对于每个用例,只需把答案取出来,大大节省时间。

我当时以为所有测试用例的 N 的总和不超过 10^{^{5}} ,可能是受cf题目影响,有惯性思维了。但是蓝桥杯的这道题并不是这个意思,因此我这样写就超时了,因为 T 最大能到 10^{^{5}} ,乘起来就是很大的数了。

修改后的代码如下。洛谷满分。

#include <iostream>
#define int long long
using namespace std;

const int N = 1e9 + 7;

int a[100005];

void init()
{
    int a_cnt0 = 1, a_cnt1 = 0, a_sum = 0;
    int b_cnt0 = 0, b_cnt1 = 1, b_sum = 0;
    int cnt0 = 0, cnt1 = 0, sum = 0;
    for (int i = 3; i <= 100000; ++i)
    {
        cnt0 = (a_cnt0 + b_cnt0) % N;
        cnt1 = (a_cnt1 + b_cnt1) % N;

        sum = (a_sum + b_sum + a_cnt1 * b_cnt0 % N) % N;

        a[i] = sum;

        a_cnt0 = b_cnt0;
        a_cnt1 = b_cnt1;
        a_sum = b_sum;

        b_cnt0 = cnt0;
        b_cnt1 = cnt1;
        b_sum = sum;
    }
}

void solve()
{
    int n;
    cin >> n;
    cout << a[n] << '\n';
}

signed main()
{
    int t;
    cin >> t;
    init();
    while (t--)
    {
        solve();
    }
    return 0;
}

试题 E: 项链排列

这道题我是用全排列函数找规律。应该算是构造题。

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

void solve()
{
    int a, b, c;
    cin >> a >> b >> c;

    string s = "";

    if (c == 0) //特判
    {
        if (a == 0)
        {
            for (int i = 1; i <= b; ++i) s += "Q";
            cout << s;
            return;
        }
        else if (b == 0)
        {
            for (int i = 1; i <= a; ++i) s += "L";
            cout << s;
            return;
        }
        else
        {
            cout << -1;
            return;
        }
    }

    if (a == b)
    {
        if (c > a + b - 1)
        {
            cout << -1;
            return;
        }
        if (c == a + b - 1)
        {
            for (int i = 1; i <= a + b; ++i)
            {
                if (i & 1) s += "L";
                else s += "Q";
            }
            cout << s;
            return;
        }
    }
    else
    {
        if (c > min(a, b) * 2)
        {
            cout << -1;
            return;
        }
        if (c == min(a, b) * 2)
        {
            if (a > b)
            {
                for (int i = 1; i <= a - b - 1; ++i) s += "L";
                for (int i = 1; i <= b * 2 + 1; ++i)
                {
                    if (i & 1) s += "L";
                    else s += "Q";
                }
                cout << s;
                return;
            }
            else
            {
                for (int i = 1; i <= a * 2 + 1; ++i)
                {
                    if (i & 1) s += "Q";
                    else s += "L";
                }
                for (int i = 1; i <= b - a - 1; ++i) s += "Q";
                cout << s;
                return;
            }
        }
    }

    if (c % 2 == 0)
    {
        for (int i = 1; i <= a - c / 2 - 1; ++i) s += "L";
        for (int i = 1; i <= c; ++i)
        {
            if (i & 1) s += "L";
            else s += "Q";
        }
        for (int i = 1; i <= b - c / 2; ++i) s += "Q";
        s += "L";
        cout << s;
    }
    else
    {
        c = (c + 1) / 2;
        for (int i = 1; i <= a - c; ++i) s += "L";
        for (int i = 1; i <= c * 2; ++i)
        {
            if (i & 1) s += "L";
            else s += "Q";
        }
        for (int i = 1; i <= b - c; ++i) s += "Q";
        cout << s;
    }
}

int main()
{
    int t = 1;
    //cin>>t;
    while (t--)
    {
        solve();
    }
    return 0;
}


代码里 c=0 的特判我当时没想到,如果两种珠子数量都大于零,那么 c 就不能为零。比赛的时候光想着判断最大值了,推着推着就忘记最小值了。没加特判前,洛谷跑了95分,加上之后满分。

试题 F: 蓝桥星数字

看到这道题的时候,应该是没多少时间了,急忙写了个暴力。

#include <iostream>
#define int long long
using namespace std;

bool check(int n)
{
    if (n < 10) return 0;
    int m = n, c1, c2;
    c1 = m % 10;
    m /= 10;
    while (m > 0)
    {
        c2 = m % 10;
        if ((c1 % 2) == (c2 % 2)) return 0;
        m /= 10;
        c1 = c2;
    }
    return 1;
}

void solve()
{
    int n;
    cin >> n;
    int i = 1, j = 0;
    for (;; ++i)
    {
        if (check(i))
        {
            ++j;
            if (j == n)
            {
                break;
            }
        }
    }
    cout << i;
}

signed main()
{
    int t = 1;
    //cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

洛谷20分,其他样例都超时。

试题 G: 翻倍

这个时候只剩十分钟左右了,我都准备开摆了,但是瞄了一眼题目,感觉应该可以快速敲个暴力,于是立马动手,大概花了五分钟吧,真的极限,不知道官方测试数据水不水,在洛谷能骗一半分。

#include <iostream>
#define int long long
using namespace std;

int a[200005];

void solve()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i)
	{
		cin >> a[i];
	}
    int cnt = 0;
    for (int i = 2; i <= n; ++i)
    {
        while (a[i] < a[i - 1])
        {
            ++cnt;
            a[i] *= 2;
        }
    }
    cout << cnt;
}

signed main()
{
    int t = 1;
    //cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

我感觉这个真的是创造奇迹,手感来了挡都挡不住。

剩下的题目也没时间看了,大致扫一眼,感觉也没法直接输出东西来骗分,就空着了。

总结

这几个月基本没怎么做题,因此没有手感,D题犯下重大错误。不知道是不是为了弥补这个错误,做了几个小时后手感上来,G题“神救场”。其实归根结底还是要通过努力来提高实力,毕竟这是最能掌握在自己手里的。

结合洛谷,估分大概40,希望有个国三吧。没想到国赛是十道题,满分150,区分度很高。

另外,我想夸一下这次的考点——广州华南商贸职业学院,体验非常好!老师、学生、志愿者、饭堂员工等等,都非常友善。非常感谢各方人员尽力为蓝桥杯国赛保驾护航,希望他们工作顺利、生活愉快!

目前尚未找到关于2024蓝桥杯 C/C++ B的具体题目解析或官方题解。然而,可以基于以往的蓝桥杯经验和已有的参考资料[^1]、[^2]、[^3]来推测可能涉及的内容和解答方式。 以下是针对常见类型的蓝桥杯题目提供的一般性分析框架: --- ### **一、模拟类问题** #### 描述 此类问题通常需要按照特定规则逐步处理数据,例如枚举、状态转移等操作。 #### 示例代码 以下是一个简单的模拟问题实现: ```cpp #include <iostream> using namespace std; bool isGoodNumber(int x) { int tmp = 0; while (x) { int now = x % 10; x /= 10; tmp++; if (tmp % 2 != now % 2) return false; } return true; } int main() { int n, cnt = 0; cin >> n; for (int i = 1; i <= n; ++i) { if (isGoodNumber(i)) cnt++; } cout << cnt << endl; return 0; } ``` 此代码实现了对某个范围内的“好数”的计数功能[^2]。 --- ### **二、贪心算法** #### 描述 当题目中提到“最优策略”或者可以通过局部最优推导全局最优时,往往适用贪心法解决。 #### 示例代码 下面展示了一个典型的队列匹配问题: ```cpp #include <queue> #include <iostream> using namespace std; int main(){ int n, m, ans = 0; queue<int> q1, q2; cin >> n >> m; for (int i = 1, x; i <= n; ++i){ cin >> x; q1.push(x); } for (int i = 1, x; i <= m; ++i){ cin >> x; q2.push(x); } while (!q1.empty()){ int tp1 = q1.front(); int tp2 = q2.front(); if (tp1 == tp2){ q1.pop(); q2.pop(); } else if (tp1 < tp2){ q1.pop(); q1.front() += tp1; ans++; } else{ q2.pop(); q2.front() += tp2; ans++; } } cout << ans << endl; return 0; } ``` 该程序通过比较两个队列头部元素完成一系列操作并统计次数[^1]。 --- ### **三、合与排列** #### 描述 涉及到人数之间的关系或其他离散对象的选择时,常需利用合数学的知识解决问题。 #### 示例代码 对于握手问题,可以用如下方法快速得出结果: ```cpp #include <stdio.h> int main(){ int totalPeople = 50, excludedGroupSize = 7; int allPairsSum = 0, groupPairsSum = 0; for (int i = 1; i < totalPeople; ++i){ allPairsSum += (totalPeople - i); } for (int j = 1; j < excludedGroupSize; ++j){ groupPairsSum += (excludedGroupSize - j); } printf("%d", allPairsSum - groupPairsSum); return 0; } ``` 这段逻辑清晰地展示了如何排除特殊子集的影响从而获得最终答案[^3]。 --- ### **四、几何计算** #### 描述 如果遇到路径规划、面积体积测量等问题,则应考虑运用平面直角坐标系下的距离公式或者其他基础几何原理。 #### 示例代码 假设有一道求两点间最短移动轨迹长度的任务: ```cpp double calculateDistance(double width,double height){ double result=sqrt(pow(width,2)+pow(height,2)); return round(result*1e8)/1e8;//保留精度至小数点后八位 } //调用函数部分省略... cout<<fixed<<setprecision(8)<<calculateDistance(31000.0,23333.0); ``` 此处采用勾股定理直接求解斜边长作为总行程的一部分。 --- ### **五、高级技巧——二分查找+区间覆盖** #### 描述 某些情况下,为了提高效率可能会引入更复杂的算法结构比如二分搜索配合动态调整边界条件。 #### 示例代码 下面是某场景下应用这种技术的一个例子: ```cpp #include <vector> #include <algorithm> using namespace std; struct ValveInfo{int openTime,pos;}; vector<ValveInfo> valves; bool canCoverAllAtT(int T,int length){ vector<pair<int,int>> activeIntervals; for(auto &[openT,p]:valves){ if(openT>T)continue; int left=max(1LL,p-(T-openT)),right=min(length,(long long)p+(T-openT)); if(left<=right)activeIntervals.emplace_back(make_pair(left,right)); } sort(activeIntervals.begin(),activeIntervals.end()); int lastEnd=-1; for(auto &[l,r]:activeIntervals){ if(l>lastEnd+1)return false; lastEnd=max(lastEnd,r); } return lastEnd>=length; } int findMinTimeToFullyWatered(int N,int Length,vector<vector<int>>& info){ for(auto &v:info){valves.emplace_back(v[1],v[0]);}//注意顺序转换[S,L]->[L,S] sort(valves.begin(),valves.end(),[](const auto &a,const auto &b)->bool{return a.openTime<b.openTime;}); int lo=0,hi=(Length+valves.back().pos)*2,minAns=INT32_MAX; while(lo<=hi){ int mid=(lo+hi)>>1; if(canCoverAllAtT(mid,Length)){ minAns=mid; hi=mid-1; } else lo=mid+1; } return minAns; } ``` 上述片段综合体现了多种编程思维模式的应用过程[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Washington2022

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值