2024 蓝桥杯模拟赛 2

P8840 [传智杯 #4 初赛] 报告赋分

#include<bits/stdc++.h>

using namespace std;

#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;

const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;

const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int t;
    cin >> t;
    for (int a, p; t; t--) {
        cin >> a >> p;
        if (p < 16) a -= 10;
        else if (p > 20) a -= p - 20;
        cout << max(0ll, a) << "\n";
    }
    return 0;
}

P8822 [传智杯 #3 初赛] 课程报名

#include<bits/stdc++.h>

using namespace std;

#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;

const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;

const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, v, m, a;
    cin >> n >> v >> m >> a;
    int res = 0;
    for (int i = 1; i <= n; i++) {
        res += v;
        if (i % m == 0) v += a;
    }
    cout << res << "\n";
    return 0;
}

P8845 [传智杯 #4 初赛] 小卡和质数

异或和为1,必定一个奇数一个偶数,偶质数只有2,因此只有2、3一对

#include<bits/stdc++.h>

using namespace std;

#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;

const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;

const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int t;
    cin >> t;
    for( int x , y ; t ; t -- ){
        cin >> x >> y;
        if( x > y ) swap( x , y);
        if( x == 1 and y == 2 ) cout << "Yes\n";
        else cout << "No\n";
    }
    return 0;
}

P8605 [蓝桥杯 2013 国 AC] 网络寻路

枚举中间的边,然后两端点所连点的乘积,就是这条边作为中间边的方案数

#include<bits/stdc++.h>

using namespace std;

#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;

const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;

const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    vi cnt(n + 1);
    vector<pii> e(m);
    for (auto &[x, y]: e)
        cin >> x >> y, cnt[x]++, cnt[y]++;
    int res = 0;
    for (const auto &[x, y]: e)
        res += (cnt[x] - 1) * (cnt[y] - 1) * 2;
    cout << res << "\n";
    return 0;
}

P8662 [蓝桥杯 2018 省 AB] 全球变暖

直接搜就行,给每个岛染色,然后再看剩下点有哪些颜色

#include<bits/stdc++.h>

using namespace std;

#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;

const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;

const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n;
    cin >> n;
    vector<string> e(n);
    for (auto &i: e) cin >> i;
    vector g(n, vector(n, 0));
    queue<pii> q;
    int res = 0;
    for (int x = 0; x < n; x++)
        for (int y = 0; y < n; y++) {
            if (e[x][y] == '.') continue;
            else g[x][y] = 1;
        }
    vector col(n, vi(n));
    for (int x = 0; x < n; x++)
        for (int y = 0; y < n; y++) {
            if (g[x][y] == 0) continue;
            col[x][y] = x * n + y, res++;
            q.emplace(x, y);
            while (not q.empty()) {
                auto [gx, gy] = q.front();
                q.pop();
                if (g[gx][gy] == 0) continue;
                g[gx][gy] = 0, col[gx][gy] = col[x][y];
                for (int i = 0, fx, fy; i < 4; i++) {
                    fx = gx + dx[i], fy = gy + dy[i];
                    if (fx < 0 or fy < 0 or fx >= n or fy >= n) continue;
                    if (g[fx][fy]) q.emplace(fx, fy);
                }
            }
        }
    for (int x = 0; x < n; x++)
        for (int y = 0; y < n; y++) {
            if (e[x][y] == '.') continue;
            else {
                g[x][y] = 1;
                for (int fx, fy, i = 0; i < 4; i++) {
                    fx = x + dx[i], fy = y + dy[i];
                    if (fx < 0 or fy < 0 or fx >= n or fy >= n) continue;
                    if (e[fx][fy] == '.') {
                        g[x][y] = 0;
                        break;
                    }
                }
            }
        }
    set<int> cnt;
    for (int x = 0; x < n; x++)
        for (int y = 0; y < n; y++)
            if (g[x][y]) cnt.insert(col[x][y]);
    cout << res - cnt.size() << "\n";
    return 0;
}

P8802 [蓝桥杯 2022 国 B] 出差

把点权也加到边权上,这样就是一个有向图,在有向图上求一下最短路就行

#include<bits/stdc++.h>

using namespace std;

#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;

const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;


i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    vi c(n + 1);
    for (int i = 1; i <= n; i++) cin >> c[i];
    vector<vii> e(n + 1);
    for (int u, v, w; m; m--)
        cin >> u >> v >> w, e[u].emplace_back(v, w + c[v]), e[v].emplace_back(u, w + c[u]);
    vi dis(n + 1, inf);
    dis[1] = 0;
    priority_queue<pii, vii, greater<pii>> q;
    q.emplace(0, 1);
    vi vis(n + 1);
    while (not q.empty()) {
        auto [d, x] = q.top();
        q.pop();
        if (vis[x]) continue;
        vis[x] = 1;
        for (auto &[y, w]: e[x]) {
            if (vis[y] or d + w >= dis[y]) continue;
            dis[y] = d + w, q.emplace(dis[y], y);
        }
    }
    cout << dis[n] - c[n] << "\n";
    return 0;
}

P8806 [蓝桥杯 2022 国 B] 搬砖

20分做法就是直接搜索就可以了

#include<bits/stdc++.h>

using namespace std;

#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;

const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;


vii a;
int n, res = 0;
vi vis;

void dfs(int cnt, int ans) {
    res = max(res, ans);
    for (int i = 0; i < n; i++) {
        if (vis[i]) continue;
        if (a[i].first > cnt) continue;
        vis[i] = 1;
        dfs(min(cnt - a[i].first, a[i].second), ans + a[i].second);
        vis[i] = 0;
    }
}

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    cin >> n;
    a.resize(n), vis.resize(n);
    for (auto &[w, v]: a) cin >> w >> v;
    dfs(inf, 0);
    cout << res << "\n";
    return 0;
}

贪心的想法肯定是把大的砖放在下面

有两块砖\(i,j\)\(i\)必须在\(j\)的下面,\(i,j\)上面的砖总重量\(W\)

\[v_i \ge W+w_j \Rightarrow v_i-w_j\ge W\\ v_j < W+w_i \Rightarrow W >v_j-w_i\\ v_i-w_j\ge W >v_j-w_i \Rightarrow v_i-w_j>v_j-w_i\Rightarrow v_i+w_i>v_j+w_j \]

所以可以按照\(v_i+w_i\)从大到小排序,然后就是01背包就行。但是如果是从下到上进行dp,不仅需要记录当前重量以及价值,还需要额外记录限制,并且要记录最强的限制。

所以我们可以从上到下进行dp,这样只用记录前缀重量和价值,但转移的是否判断一下转移是否合法也就是能否满足当前限制即可。

#include<bits/stdc++.h>

using namespace std;

#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;

const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;


i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, m;
    cin >> n;
    vector<pii> a(n);
    for (auto &[w, v]: a) cin >> w >> v, m += w;
    sort(a.begin(), a.end(), [](pii p1, pii p2) {
        return p1.first + p1.second < p2.first + p2.second;
    });

    vi f(m + 1);
    for (const auto &[w, v]: a)
        for (int i = min(w + v, m); i >= w; i--)
            f[i] = max(f[i], f[i - w] + v);
    cout << *max_element(f.begin(), f.end()) << "\n";
    return 0;
}

P8612 [蓝桥杯 2014 省 AB] 地宫取宝

数据范围太小了,直接做dp就可以

\(f[i][j][cnt][v]\)表示走到\((i,j)\)时拿了\(cnt\)个宝物且最大值是\(v\)的方案数。

然后直接\(n^4\)的枚举状态,判断转移就行,转移有两种一种取当前物品另一种是不取,实际上就是就是一个略微复杂的01背包

#include<bits/stdc++.h>

using namespace std;

#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;

const int inf = 1e9, INF = 1e18;
const int mod = 1e9 + 7;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, m, k;
    cin >> n >> m >> k;
    vector a(n + 1, vi(m + 1));
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            cin >> a[i][j], a[i][j]++;
    vector f(n + 1, vector(m + 1, vector(k + 1, vi(14))));
    f[1][1][0][0] = f[1][1][1][a[1][1]] = 1;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            if (i == 1 and j == 1) continue;
            for (int cnt = 0; cnt <= k; cnt++) {
                for (int v = 0; v <= 13; v++) {
                    if (i - 1 >= 1) (f[i][j][cnt][v] += f[i - 1][j][cnt][v]) %= mod;
                    if (j - 1 >= 1) (f[i][j][cnt][v] += f[i][j - 1][cnt][v]) %= mod;
                    if (cnt >= k or v >= a[i][j]) continue;
                    if (i - 1 >= 1) (f[i][j][cnt + 1][a[i][j]] += f[i - 1][j][cnt][v]) %= mod;
                    if (j - 1 >= 1) (f[i][j][cnt + 1][a[i][j]] += f[i][j - 1][cnt][v]) %= mod;
                }
            }
        }
    int res = 0;
    for( int v = 1 ; v <= 13 ; v ++ )
        (res += f[n][m][k][v] ) %= mod;
    cout << res << "\n";
    return 0;
}

P8773 [蓝桥杯 2022 省 A] 选数异或

普通的线性dp

\(f[i]\)表示右端点是\(i\),一个合法区间的左端点最大是多少。\(lst[x]\)是截止目前\(x\)出现最晚的地方。所以转移就是

\[f[i] = \max(f[i-1],lst[a[i]\oplus x]) \]

#include<bits/stdc++.h>

using namespace std;

#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;

const int inf = 1e9, INF = 1e18;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, m, x;
    cin >> n >> m >> x;
    vi f(n + 1), lst((1 << 20) + 1, -1);
    for (int i = 1, a; i <= n; i++) {
        cin >> a;
        f[i] = max(f[i - 1], lst[a ^ x]);
        lst[a] = i;
    }
    for( int i = 1 , l , r ; i <= m ; i ++ ){
        cin >> l >> r;
        if( f[r] < l ) cout << "no\n";
        else cout << "yes\n";
    }
    return 0;
}
posted @ 2024-01-29 19:17  PHarr  阅读(113)  评论(0编辑  收藏  举报