第十六届蓝桥杯C/C++B组省赛题解
| 题号 | A | B | C | D | E | F | G | H |
|---|---|---|---|---|---|---|---|---|
| 答案 | 1577 or 1576 | 781448427 | 统计非1的个数。 | 打表找规律,k = min(k, 100) 然后模拟就可以了。 | 排序+滑窗 | DP思维 | DP+bitset | 思维+前缀异或和+组合数学 |
| 正确性 | 洛谷测评1576可通过 | 洛谷测评通过 | 洛谷测评通过 | 洛谷测评通过 | 洛谷测评60分 | 洛谷测评通过 | 洛谷测评通过 | 洛谷测评通过 |
洛谷题库搜索蓝桥杯,筛选2025可看到题目,数据是洛谷造的,可能不准。
作者测试下来:\(5+5+10+10+5+15+20+20 = 90\),满分 \(100\),祝大家都能获得好成绩。
A: 移动距离
画个图可以发现肯定先走直线再走圆弧更优。
弧长公式忘记的话可以先想周长公式是 \(2 \pi r\),前面其实对应的弧度,所以弧长公式能推出来是\(theat \times r\)。
算出来是:1576.448789446070350。
四舍五入应该是:1577 or 1576(一个是不断四舍五入到整数,另一个是只看整数前一位)。
题目给的:“四舍五入到整数”不好评价是不断四舍五入还是只看一位。
#include<bits/stdc++.h>
using namespace std;
int main() {
// ios::sync_with_stdio(false);
// cin.tie(0); cout.tie(0);
double theat = atan(666.0 / 233.0);
// cout << theat << "\n";
double r = sqrt(666.0 * 666.0 + 233.0 * 233.0);
// cout << r << "\n";
printf("%.15lf\n", r + r * theat);// 1577
}
B: 客流量上限
也就是说 \(a_i \cdot a_j \le i \times j + 2025\)。
首先注意到一个可行解是:1、2、3、...、2025。
假设第二个解可以交换两个得到,设交换的两个数的下表为 \(i,j\) ,不失一般性,设 \(i < j\) ,任意取另外一个数 \(k\),显然有 \(i \times k + 2025 < j \times k + 2025\),所以在交换后,一定会存在一个位置 \(k\) ,违反题意,于是不能交换,所以大胆猜测答案只有一种可能性。
这里讨论错了,交换后的值确实是存在 \(i \times k + 2025 < j \times k + 2025\),但是实际要比较的是 \(j\times k\) 与 \(i\times k + 2025\) 的值,其实发现相邻数之间是可以发生交换的。
那就变成了\(1\) 可以与 \(2\) 交换,\(2\) 可以与 \(3\) 交换这样,最后答案是 \(2^{1012} \mod (10^9 + 7) = 781448427\)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN = 2e3 + 5;
const ll MOD = 1e9 + 7;
ll fastPow(ll a, ll b){
ll ret = 1;
while(b) {
if(b & 1) ret = ret * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return ret;
}
int main() {
cout << fastPow(2, 1012) << "\n";
}
C: 可分解的正整数
其实这个题观察一下可以发现,就是看一个数能不能拆成一个长度大于等于 \(3\) 的,公差为 \(1\) 的等差数列。
其实发现这个题就变简单了。
对于任意一个数 \(x\),其一定能被拆成 \(-(x - 1), -(x - 2),...,0,1,...,(x - 1),x\) 这样的等差数列。
然后发现只有当 \(x = 1\) 的时候,长度是小于等于 \(3\) 的,其余情况拆出来的等差数列均大于等于 \(3\)。
所以只需要统计非 \(1\) 数的个数就可以了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN = 2e5 + 5;
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
ll ans = 0, x = 0, n;
cin >> n;
for(int i = 1; i <= n; i ++) {
cin >> x;
ans += (x != 1);
}
cout << ans << "\n";
return 0;
}
D: 产值调整
貌似有规律,先打个表看看。
发现操作几次后,所有值就一样了,大胆最多执行 100 次终止就行了。
时间复杂度: \(O(100\cdot T) = O(10^7)\)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN = 2e5 + 5;
ll Tex, a, b, c, k;
void AC() {
cin >> a >> b >> c >> k;
k = min(k, 100ll);
while(k --) {
ll tmp1, tmp2, tmp3;
tmp1 = (b + c) / 2;
tmp2 = (a + c) / 2;
tmp3 = (a + b) / 2;
a = tmp1;
b = tmp2;
c = tmp3;
}
cout << a << " " << b << " " << c << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> Tex;
while(Tex --) AC();
return 0;
}
E: 画展布置
很容易观察到相邻的差值尽可能越小越好,所以排序+滑窗即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN = 2e5 + 5;
ll Tex = 1, n, m, a[MAXN];
void AC() {
cin >> n >> m;
for(int i = 1; i <= n; i ++) {
cin >> a[i];
}
sort(a + 1, a + n + 1);
ll ans = 0, tmp = 0;
for(int i = 2; i <= m; i ++) {
tmp += (a[i] * a[i] - a[i - 1] * a[i - 1]);
}
ans = tmp;
for(int i = m + 1; i <= n; i ++) {
tmp += (a[i] * a[i] - a[i - 1] * a[i - 1]);
tmp -= (a[i - m + 1] * a[i - m + 1] - a[i - m] * a[i - m]);
ans = min(ans, tmp);
}
cout << ans << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
// cin >> Tex;
while(Tex --) AC();
return 0;
}
F: 水质检测
DP即可,看当前这一个和上一个是否有联系。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN = 1e6 + 5;
ll Tex = 1, n;
string s[5];
void AC() {
ll ans = 0;
cin >> s[1] >> s[2];
n = s[1].size();
ll first = 0, last = 0, last_st1 = 0, last_st2 = 0;
for(int i = 0; i < n; i ++) {
if(!first) {
if(s[1][i] == '#' || s[2][i] == '#') first = 1;
else continue;
} else {
if(s[1][i] == '#' && s[1][i - 1] == '#') {
last = i;
last_st1 = (s[1][i] == '#');
last_st2 = (s[2][i] == '#');
} else if(s[2][i] == '#' && s[2][i - 1] == '#') {
last = i;
last_st1 = (s[1][i] == '#');
last_st2 = (s[2][i] == '#');
} else if(s[1][i] == '#') {
if(last_st1){
ans += (i - last - 1);
last = i;
last_st1 = (s[1][i] == '#');
last_st2 = (s[2][i] == '#');
}
else {
ans += (i - last);
last = i;
last_st1 = 1;
last_st2 = 1;
}
} else if(s[2][i] == '#') {
if(last_st2) {
ans += (i - last - 1);
last = i;
last_st1 = (s[1][i] == '#');
last_st2 = (s[2][i] == '#');
}
else {
ans += (i - last);
last = i;
last_st1 = 1;
last_st2 = 1;
}
} else continue;
}
}
cout << ans << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
// cin >> Tex;
while(Tex --) AC();
return 0;
}
G:生产车间
其实只有叶子节点能够像上传递材料,直接树上做存在性背包即可。
定义 \(f_{i,j}\) 表示节点 \(i\) 是否能向其父亲贡献 \(j\) 的材料,可以用bitset进行优化,需要注意的是不能超过 \(a[i]\) 的上线,所以得用一个 \(vis[i]\) 的 \(bitset\) 限制一下。
时间复杂度:\(O(\frac{n^3}{w})\), \(w = 32\) or \(64\)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN = 1e3 + 5;
ll Tex = 1, n, a[MAXN];
vector<ll> mp[MAXN];
bitset<MAXN> f[MAXN];
bitset<MAXN> vis[MAXN];
void dfs(ll x, ll fa){
bool is_leaf = 1;
for(auto it : mp[x]) {
if(it == fa) continue;
is_leaf = 0;
dfs(it, x);
}
f[x][0] = 1;
if(is_leaf){
f[x][a[x]] = 1;
return;
}
for(auto it : mp[x]) {
if(it == fa) continue;
for(int j = a[x]; j >= 0; j --) {
if(f[x][j]) f[x] = ((f[it] << j) | f[x]) & vis[x];
}
}
}
void AC() {
cin >> n;
for(int i = 1; i <= n; i ++) {
cin >> a[i];
for(int j = 0; j <= a[i]; j ++) {
vis[i][j] = 1;
}
}
for(int i = 1; i < n; i ++) {
ll x, y;
cin >> x >> y;
mp[x].push_back(y);
mp[y].push_back(x);
}
dfs(1, 0);
for(int i = a[1]; i >= 0; i --) {
if(f[1][i]) {
cout << i << "\n";
return;
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
// cin >> Tex;
while(Tex --) AC();
return 0;
}
H: 装修报价
观察到只有前缀异或和可以产生贡献,其余情况都会被 \(+ -\) 相互抵消掉。
那么前缀的贡献是多少呢?
枚举前缀的长度为 \(i\) ,\(i\) 与 \(i + 1\) 之间的符号一定是 \(+\) or \(-\) ,于是对于 \((i + 1)\) 之后的符号的个数为 \(n - i - 1\) 个,而每一个符号有 \(3\) 种可能性,于是对于 \(i\) 的前缀,其贡献次数是 \(2 \times 3^{n - i - 1}\),直接模拟即可。
当然最后还要加上所有数的异或和。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN = 2e5 + 5;
const ll MOD = 1e9 + 7;
ll Tex = 1, n, a[MAXN];
ll fastPow(ll a, ll b) {
ll ret = 1;
while(b) {
if(b & 1) ret = ret * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return ret;
}
void AC() {
cin >> n;
for(int i = 1; i <= n; i ++) {
cin >> a[i];
}
ll pre_xor_sum = 0, ans = 0;
for(int i = 1; i < n; i ++) {
pre_xor_sum ^= a[i];
ll cnt = 2 * fastPow(3, n - i - 1) % MOD;
ans = (ans + cnt * pre_xor_sum % MOD) % MOD;
}
pre_xor_sum ^= a[n];
ans = (ans + pre_xor_sum) % MOD;
cout << ans << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
// cin >> Tex;
while(Tex --) AC();
return 0;
}

浙公网安备 33010602011771号