2026年苯环杯蓝桥模拟赛补题()

B 矩阵染色

image

暴力,当时没想出来要这么暴力()
先把所以符合条件的小块都存起来,然后三重循环开始遍历,确保三者不相等,然后检查两两中的坐标不重复,就计入答案。

#include <bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define int long long
#define pii array<int, 2>
#define endl "\n"
int a[6][6] = {
    {11, 8, 3, 27, 24, 1},  {2, 21, 16, 35, 17, 4},   {9, 29, 20, 30, 5, 
10},
    {36, 33, 13, 6, 23, 7}, {31, 14, 15, 28, 12, 25}, {34, 19, 18, 37, 22, 
39},
};
void solve() {
    vector<array<pii, 2>> vt;
    for (int x1 = 0; x1 < 6; x1++) {
        for (int y1 = 0; y1 < 6; y1++) {
            if (x1 != 5 && (a[x1][y1]+a[x1+1][y1])%2) {
                vt.push_back({{{{x1, y1}}, {{x1+1, y1}}}});
            }
            if (y1 != 5 && (a[x1][y1]+a[x1][y1+1])%2) {
                vt.push_back({{{{x1, y1}}, {{x1, y1+1}}}});
            }
        }
    }
    auto check = [&](array<pii, 2> X, array<pii, 2> Y) {
        for (auto x : X) {
            for (auto y : Y) if (x == y) return 1;
        }
        return 0;
    };
    int ans = 0;
    int n = vt.size();
    for (int i = 0; i < n; i++) {
        for (int j = i+1; j < n; j++) {
            if (check(vt[i], vt[j])) continue;
            for (int k = j+1; k < n; k++) {
                if (check(vt[i], vt[k])) continue;
                if (check(vt[j], vt[k])) continue;
                ans++;
            }
        }
    }
    cout << ans << endl;
}

F 好段计数

image

我们很容易得出他的暴力解法(),
同时可以注意到如果知道这个数左右第一个比他大的值,就可以用O(1) 的时间复杂度解决当前数会不会对答案产生贡献的问题了。

可以使用单调栈,如果当前值比栈顶大,那么一直弹出直到栈顶的值大于这个数,记录L[i]=这个数的下标;反之,将这个值入栈。
这样维护出任意一个值左边的第一个大值,同理右边的第一个大值也是一样的。
那么正向遍历这个数组,看看这个区间长度是否等于这个值就可以了。

难点:知道单调栈是啥,单调栈就是从栈顶到栈底一直递增的(或者递减)。

code

void solve()
{
    cin >> n;
    vi a(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    vi L(n + 1, 0), R(n + 1, n + 1);
    stack<int> p;
    for (int i = 1; i <= n; i++)
    {
        while (p.size() && a[i] > a[p.top()])
        {
            p.pop();
        }
        if (!p.empty())
        {
            L[i] = p.top();
        }
        p.push(i);
    }
    while (p.size())
    {
        p.pop();
    }
    for (int i = n; i >= 1; i--)
    {
        while (p.size() && a[i] > a[p.top()])
        {
            p.pop();
        }
        if (!p.empty())
        {
            R[i] = p.top();
        }
        p.push(i);
    }
    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        int now = R[i] - L[i] - 1;
        if (now == a[i])
        {
            ans++;
        }
    }
    cout << ans << endl;
}

H 双机器人

image

你可以手模试一下,贪心显然不对的。

所以就可以考虑dp了,又因为n的数据范围也不大,支持O(n^2)的操作

dp先要找一下状态,发现也就俩状态,就是两个机器人的位置,然后发现如果遍历所有任务点,总会有一个机器人在i-1处,所以只要枚举另一个机器人的位置就行了,所以需要维护两个状态,dp[i][j],表示处理完第i个任务,一个机器人在i,一个在j。

code

void solve()
{
    cin >> n;
    vi a(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    a[0] = 0;
    vvi dp(n + 1, vi(n + 1, 1e18));//求最小值,初始化为极大值
    dp[1][0] = abs(a[1]);//显而易见

    for (int i = 2; i <= n; i++)//因为i=1的情况已经预处理了,所以从i=2开始遍历
    {
        for (int j = 0; j < i - 1; j++)//j要小于i-1
        {
            //这个就表示一个机器人在i-1,一个机器人在j,使得i-1的机器人来到i,枚举j的位置
            dp[i][j] = min(dp[i][j], dp[i - 1][j] + abs(a[i - 1] - a[i]));
            //这个就表示一个机器人在i-1,一个机器人在j,让在j的机器人来到i,枚举j的位置
            dp[i][i - 1] = min(dp[i][i - 1], dp[i - 1][j] + abs(a[i] - a[j]));
        }
    }
    int mx = 1e18;
    for (int i = 0; i < n; i++)
    {
        //到最后所有任务都结束了,一定是某一个在n点,另一个不知道在哪,所以枚举
        mx = min(mx, dp[n][i]);
    }
    cout << mx << endl;
}

还没补完…………

posted @ 2026-04-01 12:17  Lambda_L  阅读(15)  评论(0)    收藏  举报