第十二届蓝桥杯国赛 cb

文章目录

A: 带宽 25

B: 纯质数 1903

考场上用的欧拉筛,这里用埃氏筛。

#include <bits/stdc++.h>
using namespace std;

const int N = 20210606;
bool vis[N];
vector<int> primes;
void init()
{
    int i;
    for (i = 2; i < N; ++i) {
        if (!vis[i]) primes.push_back(i);
        for (int j = 0; i*primes[j] < N; ++j) {
            vis[i*primes[j]] = 1;
            if (i%primes[j] == 0) break;
        }
    }
}

int main()
{
    init();
    int ans = primes.size();
    for (auto x : primes) {
        while (x) {
            int t = x%10;
            if (t != 2 && t != 3 && t != 5 && t != 7) {
                --ans; break;
            }
            x /= 10;
        }
    }
    cout << ans; // 1903
    return 0;
}

C: 完全日期 977

不熟悉 p y t h o n python python 的日期类,怕用错,于是手动模拟日期变化。

#include <bits/stdc++.h>
using namespace std;

class Date
{
    int y, m, d;
public:
    Date(int y, int m, int d) : y(y), m(m), d(d) {}
    void add() {
        int nums[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
        if (y%400 == 0 || y%100 && y%4 == 0) ++nums[2];
        if (++d > nums[m]) {
            d = 1;
            if (++m > 12) m = 1, ++y;
        }
    }
    bool operator == (const Date &t) const {
        return y == t.y && m == t.m && d == t.d;
    }
    bool valid() {
        auto sum = [] (int x) {
            int ret = 0;
            while (x) ret += x%10, x /= 10;
            return ret;
        };
        int t = sum(y)+sum(m)+sum(d);
        int i = 0;
        while (i*i < t) ++i;
        return i*i == t;
    }
};

int main()
{
    Date s(2001, 1, 1), t(2022, 1, 1);
    int ans = 0;
    while (!(s == t)) {
        ans += s.valid();
        s.add();
    }
    cout << ans;  // 977
    return 0;
}

D: 最小权值 2653631372

题目直接给出状态转移方程,感觉 d p dp dp 的暗示还是蛮明显的。

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
LL dp[2022];
int main()
{
    for (int i = 1; i <= 2021; ++i) {
        dp[i] = LLONG_MAX;
        for (int j = 0; j < i; ++j) {
            dp[i] = min(dp[i], 1+2*dp[j]+3*dp[i-1-j]+j*j*(i-1-j));
        }
        // cout << dp[i] << ' ';
    }
    cout << dp[2021] << endl;  // 2653631372
    return 0;
}

E: 大写

国赛遇上这种题应该挺难得吧。

#include <bits/stdc++.h>
using namespace std;

int main()
{
    char c;
    while (cin >> c) cout << char((c | 0x20) ^ 0x20);
    return 0;
}

F: 123

这题公式其实蛮好推的。
只要知道 ∑ i = 1 n i = n ( n + 1 ) 2 ,   ∑ i = 1 n i 2 = n ( n + 1 ) ( 2 n + 1 ) 6 \sum_{i=1}^n i=\frac{n(n+1)}{2},\ \sum_{i=1}^n i^2=\frac{n(n+1)(2n+1)}{6} ∑i=1n​i=2n(n+1)​, ∑i=1n​i2=6n(n+1)(2n+1)​ 即可。

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

LL calc(LL j) { return (j*(j+1)*(2*j+1)/6 + j*(j+1)/2)/2; }

LL solve(LL n)  // 计算 1...n 项和
{
    LL j = (sqrt(8*n+1)-1)/2;
    LL res = n - j*(j+1)/2;
    assert(res <= j);
    return calc(j) + res*(res+1)/2;
}

int main()
{
    LL T;
    cin >> T;
    while (T--) {
        LL l, r;
        cin >> l >> r;
        cout << solve(r) - solve(l-1) << endl;
    }
    return 0;
}

/*
3
1 1
1 3
5 8
*/

G: 异或变换(候补)

没找到规律,只做了 40% 的子任务。

H: 二进制问题

这是很裸的数位 d p dp dp 吧。

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

LL dp[100][2][100];  // 长度为i 首位为j 二进制中含k个1  dp代表满足条件的个数

void init()
{
    dp[1][0][0] = dp[1][1][1] = 1;
    for (int i = 2; i < 80; ++i) {
        for (int k = 0; k <= i; ++k) {
            dp[i][0][k] = dp[i-1][0][k] + dp[i-1][1][k];
            if (k > 0) dp[i][1][k] = dp[i-1][0][k-1] + dp[i-1][1][k-1];
            // cout << dp[i][0][k] << ',' << dp[i][1][k] << ' ';
        }
        // cout << endl;
    }
}

int digit[100];
int len = 0;
LL calc(LL n, LL k)  // 1..n中有多少个满足条件的数
{
    LL t = n;
    while (t) {
        digit[++len] = t&1; t >>= 1;
    }

    LL ans = 0;
    for (int i = len; i >= 1; --i) {
        if (i == 1) {
            ans += dp[i][ digit[i] ][k];
        }
        if (digit[i]) {
            ans += dp[i][0][k];
            --k;
        }
    }
    return ans;
}

int main()
{
    init();
    LL n, k;
    cin >> n >> k;
    cout << calc(n, k);
}

I: 反转括号序列(候补)

很明显的线段树特征,不过还是没能想到怎么写,只做了 20% 的子任务。

J: 异或三角形(候补)

没想到思路,只做了 20% 的子任务。

总结

这是我本科第一次参加蓝桥杯,我想大概也是最后一次了。

感觉自己还是一如既往地菜,希望以后能不忘初心,继续学习。

如果研究生阶段还有机会参加蓝桥杯的话,希望到时候也可以向那些大佬一样骄傲地说出蓝桥杯 “有手就行、点击就送” 吧。

上一篇:CheckBox复选框


下一篇:ReportEase json详解