第十六届蓝桥杯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;
}
posted @ 2025-04-12 17:02  XiaoMo247  阅读(2160)  评论(0)    收藏  举报