第十四届蓝桥杯大赛软件赛省赛C/C++ 大学 A 组真题

文章目录

:只为拿分 部分优化思路没有更新

1 幸运数

题目描述:

小蓝认为如果一个数含有偶数个数位,并且前面一半的数位之和等于后面一半的数位之和,则这个数是他的幸运数字。例如 2314 是一个幸运数字, 因为它有 44 个数位, 并且 2+3=1+4 。现在请你帮他计算从 1 至 100000000 之间共有多少个不同的幸运数字。

比较简单,直接附上我的暴力题解:

答案:4430091
代码:
cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
string to_str(int x) {
    string res;
    while(x) {
        res = res + (char)(x % 10 + '0');
//        cout<<res<<endl;
        x /= 10;
    }
    reverse(res.begin(), res.end());
    return res;
}
int main() {
    int ans = 0;
    for(int i = 10; i <= 100000000; i++) {
        string str = to_str(i);
//        cout<<str;
        int len = str.size();
        bool flag = true;
        int left = 0, right = 0;
        if(len % 2 == 0) {
            for(int j = 0; j < len / 2; j++) {
                left += (int)str[j];
                right +=(int)str[len-j-1];
            }
            if(left==right) ans++;
        }
    }
    cout << ans;
    return 0;
}

2 有奖问答

题目描述:

小蓝正在参与一个现场问答的节目。活动中一共有 30 道题目, 每题只有答对和答错两种情况, 每答对一题得 10 分,答错一题分数归零。

小蓝可以在任意时刻结束答题并获得目前分数对应的奖项,之后不能再答任何题目。最高奖项需要100 分, 所以到达 100 分时小蓝会直接停止答题。请注意小蓝也可能在不到 100 分时停止答题。

已知小蓝最终实际获得了 70 分对应的奖项, 请问小蓝所有可能的答题情况有多少种?

重点:

答错一题,分数全部归零,一开始看错题了,直接用的组合数+循环。。。

答案:8335366
代码:

附上dfs暴力求解:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
int ans = 0;
void dfs(int score, int n) {
	//答题情况+1 
    if(score == 70) ans += 1;
    //答完所有的题或达到100分 停止递归 
    if(n == 30 || score == 100) return;
    dfs(score + 10, n + 1);
    //答错score归零 
    dfs(0, n + 1);
}

int main(){
	dfs(0,0);
	cout<<ans;
	return 0;
}

3 平方差

题目描述:

输入两个整数,输出 A 2 − B 2 的值 输入两个整数,输出A^2-B^2的值 输入两个整数,输出A2−B2的值

貌似真题不是这个,为什么官网给的上面这道题。。。
给定 L , R ,问 L ≤ x ≤ R 中有多少个数 x 满足存在整数 y , z 使得 x 2 = y 2 − z 2 给定 L,R,问 L≤x≤R 中有多少个数 x 满足存在整数 y,z 使得 x^2=y^2−z^2 给定L,R,问L≤x≤R中有多少个数x满足存在整数y,z使得x2=y2−z2

我们按下面这道题来

思路:数学+找规律

发现x 只要满足是奇数或者4的倍数就是一种答案,因为x的组合形式只能是奇×奇 或者 偶×偶 两个偶数相乘,结果一定是4的倍数。

  • x/2上取整可以获得[1,x]奇数个数: ⌈9 / 2⌉ = 5(1,3,5,7,9为[1,x]的奇数)
  • x/4下取整可以获得[1,x]4的倍数的个数⌊5 / 4⌋ = 1(只有4一个为4的倍数)
  • 再加一个前缀和思想求区间内满足的个数
代码:
cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
int calc(int x) {
    return (x + 1) / 2 + x / 4;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int L, R;
    cin >> L >> R;
    cout << calc(R) - calc(L - 1) << endl;

    return 0;
}

不是我说,这谁能在考场上做出这么大的假设并证明。。。

4 更小的数

题目描述:

0更小的数 - 蓝桥云课 (lanqiao.cn)

小蓝想要将选出的子串进行反转后再放入原位置处得到的新的数字 numnew 满足条件 numnew<num,请你帮他计算下一共有多少种不同的子串选择方案,只要两个子串在 num 中的位置不完全相同我们就视作是不同的方案。

就是一个双指针,不断判断区间左端点和右端点的数字大小即可,附上我的题解:

代码:
cpp 复制代码
#include <iostream>  
#include <vector>  
#include <string>  
using namespace std;  
using ll = long long;  

bool is_smaller(int l, int r, const vector<char>& num) {  
    while (l < r && num[l] == num[r]) {  
        l++;  
        r--;  
    }  
    return num[l] > num[r]; 
}  

int main() {  
    string input;  
    getline(cin, input);     
    vector<char> num;  
    for (char c : input) {  
        if (c != ' ') {    
            num.push_back(c);  
        }  
    }  
    ll ans = 0;  
    for (int i = 0; i < num.size(); i++) {  
        for (int j = i; j < num.size(); j++) {  
            if (is_smaller(i, j, num)) {  
                ans++;  
            }  
        }  
    }  
    cout << ans;  
    return 0;  
}

5 颜色平衡树

题目描述:

1.颜色平衡树 - 蓝桥云课 (lanqiao.cn)

给定一棵树,结点由 1 至 n 编号,其中结点 1 是树根。树的每个点有一个颜色 Ci。

如果一棵树中存在的每种颜色的结点个数都相同,则我们称它是一棵颜色平衡树。求出这棵树中有多少个子树是颜色平衡树。

思路:启发式合并

颜色数量最小=颜色数量最大,说明是颜色平衡树

代码:
cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 8;
//vector<pair<int,int>> g[N];
//int col[200000];
map<int, int>col[N], num[N];
vector<int> g[N];
int ans;

void dfs(int x, int fa) {
    //递归处理其所有子节点y
    for(auto & y : g[x]) {
        dfs(y, x);
        //比较x和y的col大小,总是将小的合并到大的中
        if(col[x].size() < col[y].size()) {
            swap(col[x], col[y]);
            swap(num[x], num[y]);
        }
        //遍历子节点y的颜色统计
        for(auto it : col[y]) {
            int y_col = it.first, y_num = it.second;
            //如果颜色在x中已存在:合并数量,并更新num统计
            if(col[x].count(y_col)) {
                int x_num = col[x][y_col];
                num[x][x_num]--;
                if(num[x][x_num] == 0) num[x].erase(x_num);
                num[x][x_num + y_num]++;
            } 
            //如果颜色在x中不存在:直接添加
            else num[x][y_num]++;
            col[x][y_col] += y_num;
        }
        //清空子节点y的统计信息(释放内存)
        map<int, int>tmp1, tmp2;
        col[y].swap(tmp1);
        num[y].swap(tmp2);
    }
    //x的子树中所有颜色出现的次数都相同
    if(num[x].size() == 1) ans++;

}

int main() {
    int n;
    cin >> n;
    for(int i = 1; i <= n; i++) {
        int c, fa;
        cin >> c >> fa;
        //1号节点没有father 即fa=0
        g[fa].push_back(i);
        col[i][c]++;//i节点 颜色为c的数量
        num[i][1]++; //i点有颜色数量为1的一个颜色
    }
    dfs(1, 0);

	cout<<ans;
    return 0;
}

大佬啊,我不会反正

6 买瓜

题目描述:

1.买瓜 - 蓝桥云课 (lanqiao.cn)

小蓝正在一个瓜摊上买瓜。瓜摊上共有 n 个瓜,每个瓜的重量为 Ai。小蓝刀功了得,他可以把任何瓜劈成完全等重的两份,不过每个瓜只能劈一刀。小蓝希望买到的瓜的重量的和恰好为 m

请问小蓝至少要劈多少个瓜才能买到重量恰好为 m 的瓜。如果无论怎样小蓝都无法得到总重恰好为 m 的瓜,请输出 −1。

思路:dfs+剪枝(只能通过45%)

每个瓜只可能存在三种情况:

  1. 选择整一个瓜
  2. 被切后选择一半
  3. 不选择该瓜

dfs暴力求解之后剪枝优化:

  1. 当前方案切的刀数大于等于之前已知方案的最优解
  2. 如果该路径上包括未选择的瓜的重量总和不够m
  3. 当前已有的重量超过m,则当前方案非法
  4. 贪心trick:按瓜的重量从大到小排序

从上面的思路得出我们的数据结构:

  • 后缀和数组 s[i]
  • 传参:当前判断第u个瓜,目前已有的重量w,切的刀数cnt
代码:
cpp 复制代码
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int N = 33;
int a[N], s[N];
int ans=INF;
int m, n;
void dfs(int u, double w, int cnt) {
    //当前方案有效
    if(w == m) {
        ans = min(ans, cnt);
        return;
    }
    //已经遍历完成
    if(u > n) return;
    //当前方案不优
    if(cnt > ans) return;
    if(w + s[u] < m) return;

    //选择列表
    dfs(u + 1, w + a[u], cnt);//选整个瓜
    dfs(u + 1, w + a[u] / 2.0, cnt + 1);//切且选半个瓜
    dfs(u + 1, w, cnt);//不选该瓜
}
bool cmp(int x, int y) {
    return x > y;
}
int main() {
    cin >> n >> m;
    for(int i = 1; i <= n; i++) cin >> a[i];
    sort(a + 1, a + n + 1, cmp);
    //记录后缀和
    for(int i = n; i >= 1; i--) s[i] = s[i + 1] + a[i];
    dfs(1, 0.0, 0);
    cout << (ans==INF? -1 : ans);
    return 0;
}

标答给的动态规划。。。

7 异或和之和

题目描述:

0异或和之和 - 蓝桥云课 (lanqiao.cn)

给定一个数组 Ai ,分别求其每个子段的异或和,并求出它们的和。或者说,对于每组满足 1 ≤ L ≤ R ≤ n 的 L , R ,求出数组中第 L 至第 R 个元素的异或和。然后输出每组 L, R 得到的结果加起来的值。

代码:

没有位运算优化,直接附上我的暴力代码,可以过90%

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 9;
using ll = long long;
ll a[N];
int main() {
    int n;
    cin >> n;
    ll ans=0;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= n; i++) {
    	ll sum=0;
        for(int j = i; j <= n; j++) {
			sum^=a[j];
			ans+=sum;
        }
    }
    cout<<ans;
    return 0;
}

之后再更新完善吧,孩子没时间了。。。

8 网络稳定性

题目描述:

0网络稳定性 - 蓝桥云课 (lanqiao.cn)

有一个局域网,由 n 个设备和 m 条物理连接组成,第 i 条连接的稳定性为w i 。对于从设备 A 到设备 B 的一条经过了若干个物理连接的路径,我们记这条路径的稳定性为其经过所有连接中稳定性最低的那个。

我们记设备 A 到设备 B 之间通信的稳定性为 A 至 B 的所有可行路径的稳定性中最高的那一条。

给定局域网中的设备的物理连接情况,求出若干组设备 x i 和 y i 之间的通信稳定性。如果两台设备之间不存在任何路径,请输出 −1 。

孩子先不想看了,这种图论的题太吃基础了。。。可以直接看题解

9 像素放置

小蓝最近迷上了一款名为《像素放置》的游戏,游戏在一个 n × m 的网格棋盘上进行,棋盘含有 n 行,每行包含 m 个方格。

玩家的任务就是需要对这n × m 个方格进行像素填充,填充颜色只有黑色或白色两种。有些方格中会出现一个整数数字 x(0 ≤ x ≤ 9),这表示当前方格加上周围八个方向上相邻的方格(分别是上方、下方、左方、右方、左上方、右上方、左下方、右下方)共九个方格内有且仅有 x 个方格需要用黑色填充

玩家需要在满足所有数字约束下对网格进行像素填充,请你帮助小蓝来完成。题目保证所有数据都有解并且解是唯一的。

思路:dfs+判断合法
代码:
cpp 复制代码
#include <iostream>
using namespace std;
int n, m;
char d[12][12];//原始数组 
int f[12][12];//填充后的数组 

//检查是否合法 
bool check(int x, int y) {
    if(d[x][y] == '_') return true;
    int cnt = 0;
    for(int i = -1; i <= 1; i++) {
        for(int j = -1; j <= 1; j++) cnt += f[x + i][y + j];
    }
    // 如果周围1(黑棋)数量等于 d[x][y] 对应的数字,返回true,否则返回false
    if(cnt == d[x][y] - '0') return true;
    return false;
}
//深搜试探,从左往右,从上往下
void dfs(int x, int y) {
    //检查是否符合最后一行
    if(x == n + 1) {
        for(int j = 1; j <= m; j++) {
            if(!check(n, j)) return;
        }
        //找到答案,直接输出,结束
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                cout << f[i][j];
            }
            cout << endl;
        }
        return;
    }
    //到该行的最后一列 准备换行
    if(y == m) {
    	//尝试0 
        f[x][y] = 0;
        if(x == 1 || (y == 1 && check(x - 1, y)) || (check(x - 1, y - 1) && check(x - 1, y))) {
            dfs(x + 1, 1);
        }
        //尝试1 
        f[x][y] = 1;
        if(x == 1 || (y == 1 && check(x - 1, y)) || (check(x - 1, y - 1) && check(x - 1, y))) {
            dfs(x + 1, 1); //换行
        }
    }
    //没到换行,遍历该行下一列
    else {
        f[x][y] = 0;
        if(x == 1 || y == 1 || (check(x - 1, y - 1)))
            dfs(x, y + 1);

        f[x][y] = 1;
        if(x == 1 || y == 1 || check(x - 1, y - 1))
            dfs(x, y + 1);
    }
}

int main() {
    cin >> n >> m;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            cin >> d[i][j];
        }
    }
    dfs(1, 1);
    return 0;
}

10 翻转硬币

0翻转硬币 - 蓝桥云课 (lanqiao.cn)

这个的难度也是不想再吐槽了。。。直接借鉴的别人的50%的暴力:

思路:

转一个i位置不会影响到小于i的位置,所以暴力得从小到大,确保前面每个位置都已经被修改,那么久根据题意从2开始,遇到一个i位置是0,就开始把i的倍数的位置翻转即可。用一个tot记录需要翻转的位置数,根据翻转的情况来更改tot,如果某次执行后tot为0那么久代表已经全部为1,统计翻转次数即可。

代码:
cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
bitset<200000001>t;
int main() {
    int n;
    cin >> n;
    int ans = 1;
    t[1] = 1;
    int tot = n - 1;
    for(int i = 2; i <= n; i++) {
        if(t[i]) continue;
        int j = i;
        ans++;
        while(j <= n) {
            t[j] = !t[j];
            if(t[j]) tot--;
            else tot++;
            j += i;
        }
        if(!tot) break;
    }
    cout << ans;
    return 0;
}

自己模拟根本没时间看这道题。。。

相关推荐
callJJ2 分钟前
从零开始的图论讲解(1)——图的概念,图的存储,图的遍历与图的拓扑排序
java·数据结构·算法·深度优先·图论·广度优先·图搜索算法
脱脱克克1 小时前
2025.4.9 华为机考 第1题-补丁版本升级
python·算法·华为
liuluyang5304 小时前
C语言C11支持的结构体嵌套的用法
c语言·开发语言·算法·编译·c11
明飞19875 小时前
C_内存 内存地址概念
c语言·开发语言
勤劳的进取家5 小时前
贪心算法之最小生成树问题
数据结构·python·算法·贪心算法·排序算法·动态规划
SuperW5 小时前
蓝桥杯嵌入式十五届模拟二(串口DMA,占空比的另一种测量方式)
单片机·职场和发展·蓝桥杯
亓才孓5 小时前
[leetcode]stack的基本操作的回顾
算法
小美爱刷题5 小时前
力扣DAY46-50 | 热100 | 二叉树:展开为链表、pre+inorder构建、路径总和、最近公共祖先、最大路径和
算法·leetcode·链表
Fanxt_Ja6 小时前
【数据结构】红黑树超详解 ---一篇通关红黑树原理(含源码解析+动态构建红黑树)
java·数据结构·算法·红黑树