2025蓝桥杯C++B组题解(口胡版)

2025蓝桥杯C++B组题解(口胡版)

填空题

1. 求最短路径

题目大概意思: 小明有两个操作, 往x轴方向走任意距离, 或者以(0,0)为圆心, 以自身到原点距离为半径, 走一段圆弧, 问到 (233, 666) 点最少需要走多少距离, 四舍五入保留整数

最短路径就是先往右走到 sqrt(233 * 233 + 666 * 666) , 然后走圆弧

x = 233.0, y = 666.0
dis = sqrt(x * x + y * y)
ans = dis + atan(y / x) * dis
cout << (int) (ans + 0.5) 

答案好像是 157几

2. 2025排列

实验室大佬说:

1014后面的数字必须在自己的位置上, 前面的都可以偏移一个位置, 等价于用隔板法分隔 1013 个数字

答案是 2 1012 2^{1012} 21012 % mod

解答题

1. 特判题

题目大概意思: 称一个数 x x x (x >= 0)可以被构造, 为 x x x = sum(a, a+1, a+2 …),

sum(a, a+1, a+2 …)即一个公差为 1 的连续序列的和, a可以为任意整数, 该序列长度必须 >= 3

解题思路

除了1以外的所有数字都可以被构造出来

对于任意其他数字一定有 [-(x-1), -(x-2), … ,0, …, (x-2), (x-1), x ] 这样的序列使得使得sum = x 且序列长度 >= 3

int n; cin >> n;
int ans = 0;
for(int i = 1; i <= n; ++i) {
	int t; cin >> t;
	ans += (t != 1);
}

2. abck变变变

题目大概意思: 给三个数a,b,c 进行k次变换, 每次变换使 a = ⌊ b + c 2 ⌋ \lfloor \frac{b + c}{2} \rfloor 2b+c, b = ⌊ a + c 2 ⌋ \lfloor \frac{a + c}{2} \rfloor 2a+c c = ⌊ a + b 2 ⌋ \lfloor \frac{a + b}{2} \rfloor 2a+b

解题思路: k >= 100 以后a b c 一定会变成相同的数字, 将题目给的 k 和 100 取小以后暴力即可

int a, b, c, k;
cin >> a >> b >> c >> k; 
k = min(100, k)
...

3. 排序 + 双指针

题目大概意思: 有n个物品, 每个物品价值为 w i w_i wi, 要从中挑选 m 个物品, 使得 ∑ i = 2 m \sum_{i=2}^{m} i=2m ( w [ i ] 2 − w [ i − 1 ] 2 ) \left( w[i]^2 - w[i-1]^2 \right) (w[i]2w[i1]2)最小​

解题思路: 很明显, 对 n 个物品排序后, 选取的一定是某一个长度为 m 的连续序列, 那么直接双指针跑一边, 计算出所有长度为 m 的连续序列的值, 最后取小就行

int l = 0, r = 0, sum = 0;
int ans = 1e9 + 7;
while(l + m - 1 < n) {
	while (r < l + m - 1) {
		r += 1;
		sum += w[r] * w[r] - w[r - 1] * w[r - 1];
	}
	
	ans = min(ans, sum);
	l += 1
	sum -= w[l] * w[l] - w[l - 1] * w[l -1]
}

4. dp

题目大概意思:

给定一个两行的字符串形如: …#…#.

​ ##…

#代表一个净水器, 如果两个净水器在上下或者左右, 表示两个净水器联通, '.'可以理解成墙, 阻挡净水器联通, 如果净水器A和B联通, B和C联通, 则A和C联通
有一个操作可以将墙变成净水器, 问最少操作几次可以让所有净水器联通

解题思路:

  1. 首先形如
…##…
…##…

这种数据, 我们要把头尾上下都为 ‘.’ 的东西去掉, 得到有效区间[l, r], 比如上面的有效区间就是[4, 5] (下标从1开始)

  1. 然后对有效区间 [l, r] 进行 dp
    设 dp[0][i] 为第1个字符串的第i个字符为’#‘并且和前面联通, 最少需要几次操作
    同理 dp[1][i] 为第2个字符串的第i个字符为’#'并且和前面联通, 最少需要几次操作

    转移大概如下, 应该是对的吧QwQ
    dp[0][i] = dp[0][i - 1] + (s[0][i] == '.')
    dp[1][i] = dp[1][i - 1] + (s[1][i] == '.')
    
    ta = min(dp[0][i], dp[1][i] + (s[0][i] == '.'))
    tb = min(dp[1][i], dp[0][i] + (s[1][i] == '.'))
    
    dp[0][i] = ta
    dp[1][i] = tb
    
    最后答案就是
    min(dp[0][r], dp[1][r])
    

5. 树上背包

题目大概意思: 有一个 根节点为1, n 个节点的树, 每一个点有一个 w i w_i wi 的权值

节点wi代表的意义
单位时间可以 包装 多少货物
叶节点单位时间可以 提供 多少原材料
其他单位时间可以 改进 多少从上一个节点得到的东西

现在发现, 在原图上, 个别点单位时间得到的东西 > wi, 现在想删除一些点, 使得所有点 单位时间得到的东西 <= wi, 问最后单位时间, 根节点上最多能包装多少货物

n <= 1000, w <= 1000

解题思路: 假如只有根节点和若干叶子节点, 那么很明显是一个背包问题, 那么很容易类推到所有点, 对所有点跑书上背包即可

优化: 用 bitset 来存储dp状态, 转移更快, 空间更小

6. 异或和

题目大概意思:

给定一个序列 如 1 3 5 7 9, 在数字与数字之间插入 ^, +, 或 - 运算符, ^优先计算, ±其次,

问所有可能的情况的值的和是多少(对1e9 取模)

解题思路:

设 sum(l, r) 为 a l a_l al ^ a l + 1 a_{l+1} al+1^ … ^ a r a_r ar, 可以发现任何 l $\neq $ 1 的段, 对最终的答案没有贡献,

比如一定有 1 + (3 ^ 5 ^ 7 ^ 9) 和 1 - (3 ^ 5 ^ 7 ^ 9) 这种序列, 使得 (3 ^ 5 ^ 7 ^ 9) 对最终的答案贡献为零

那么只需要计算 l l l​ 为 1的所有前缀异或的贡献即可

贡献等于后面操作为 + -, 此外的操作任意, 比如 (1 ^ 3 ^ 5) (+ or -) 7 (+ or - or ^) 9

那么 (1 ^ 3 ^ 5) 的贡献就是 (1 ^ 3 ^ 5) * 2 * 3 1 3^1 31

// 大概是这样
// p3[i] 为 3^i 对mod的取模, pre[i] 为 1 ~ i 的前缀异或大小
ans = pre[n] // 1 - n
for(int i = 1; i < n; ++i) { // 1 - (n - 1)
	ans += pre[i] * 2 * p3[n - 1 - 1 - (r - 1)];
    ans = ans % mod;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值