HBCPC 2021 湖北省赛

F. Battery

题目大意

有n个电池的电量分别是\(a_i\),需要在m个地方拍摄长为\(b_i\)(全是2的幂)的视频,拍摄途中不可换电池,问最多可以拍摄多少个地点

解题思路

由于\(b_i\)全是2的幂,因此可以从这里入手,算出每一个电池在2的幂上分别能做多少贡献,之后再贪心维护各个指数即可

代码实现

/*
如下直接双指针贪心是错误做法,hack数据:
2 3
4 6
2 4 4
正确答案应该是3,下方代码输出2
*/
#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int n, m;
    std::cin >> n >> m;

    std::vector<int> a(n), b(m);
    for (int i = 0; i < n; i++) {
        std::cin >> a[i];
    }
    std::sort(a.begin(), a.end());

    for (int i = 0; i < m; i++) {
        std::cin >> b[i];
    }
    std::sort(b.begin(), b.end());

    i64 ans = 0, i = 0, j = 0;
    while (i < n && j < m) {
        if (a[i] >= b[j]) {
            a[i] -= b[j];
            ans++;
            j++;
        } else {
            i++;
        }
    }

    std::cout << ans << "\n";
}
#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int n, m, ans = 0;
    std::cin >> n >> m;

    std::vector<int> a(n), b(m), bit(31);
    for (int i = 0; i < n; i++) {
        std::cin >> a[i];
    }
    for (int i = 0; i < m; i++) {
        std::cin >> b[i];
    }
    std::sort(b.begin(), b.end());

    for (int i = 0; i < n; i++) {
        for (int j = 0; j <= 30; j++) {
            bit[j] += (a[i] >> j & 1);
        }
    }

    for (int i = 0; i < m; i++) {
        int cnt = __builtin_ctz(b[i]);
        for (int j = cnt; j <= 30; j++) {
            if (bit[j]) {
                ans++;
                bit[j]--;
                // 高位多余的要补充到低位去
                for (int k = cnt; k < j; k++) {
                    bit[k]++;
                }
                break;
            }
        }
    }

    std::cout << ans << "\n";
}

A. CRC Test

题目大意

CRC校验,给定数据和除数,求验证码

解题思路

按题意模拟,注意实现细节即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        std::string p, x, s = "", ans;
        std::cin >> p >> x;

        for (auto ch : x) {
            int cnt = 0;
            if ('A' <= ch && ch <= 'F') {
                cnt = 10 + ch - 'A';
            } else {
                cnt = ch - '0';
            }

            std::string s4;
            while (cnt) {
                s4 = (char)('0' + cnt % 2) + s4;
                cnt /= 2;
            }
            if (!s.empty()) {
                while (s4.size() < 4) {
                    s4 = '0' + s4;
                }
            }
            s += s4;
        }

        int n = s.size(), cnt = p.size();
        s += std::string(100, '0');
        ans = s.substr(0, cnt);

        while (n--) {
            if (ans[0] == '1') {
                for (int i = 0; i < p.size(); i++) {
                    ans[i] = '0' + (ans[i] != p[i]);
                }
            }
            ans.erase(ans.begin());
            ans += s[cnt++];
        }
        ans.pop_back();

        std::cout << ans << "\n";
    }
}

D. Fragmentation merging

题目大意

给你一个排列数组,请你选择两个子数组(可以有一个空集)合并为一个新数组,使得新数组内的max-min+1是数组元素数量

解题思路

首先记录每一个数字的位置,接着两层循环枚举连续的最大最小值,记录现在有多少联通的部分被标记,不超过2即满足条件,特判只有一个数字的情况

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int tt;
    std::cin >> tt;

    while (tt--) {
        i64 n, ans = 0;
        std::cin >> n;

        std::vector<int> a(n), pos(n + 1);
        for (int i = 0; i < n; i++) {
            std::cin >> a[i];
            pos[a[i]] = i + 1;
        }

        if (n == 1) {
            std::cout << 0 << "\n";
            continue;
        }

        for (int min = 1; min <= n; min++) {
            int cnt = 0;
            std::vector<int> vis(n + 2);
            for (int max = min; max <= n; max++) {
                vis[pos[max]] = 1;
                if (vis[pos[max] - 1] && vis[pos[max] + 1]) {
                    cnt--;
                }
                if (!vis[pos[max] - 1] && !vis[pos[max] + 1]) {
                    cnt++;
                }
                ans += cnt <= 2;
            }
        }

        std::cout << ans << "\n";
    }
}

I. Sequence

题目大意

给你一个n*n的全0矩阵,有m个位置ab被置为1,问矩阵中有多少个全0子矩阵

解题思路

对于某一个位置ij,求往上最多能连续多少个0,往左最多能连续多少个0,往右最多能连续多少个0即可,可以用单调栈来维护

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    i64 n, m, ans = 0;
    std::cin >> n >> m;

    std::vector<std::vector<int>> g(n + 1, std::vector<int>(n + 1));
    for (int i = 1; i <= m; i++) {
        int a, b;
        std::cin >> a >> b;
        g[a][b] = 1;
    }

    std::vector<i64> stk, h(n + 2), l(n + 1), r(n + 1);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (!g[i][j]) {
                h[j]++;
            } else {
                h[j] = 0;
            }
        }
        h[0] = h[n + 1] = -1;

        for (int j = 1; j <= n + 1; j++) {
            while (!stk.empty() && h[stk.back()] >= h[j]) {
                r[stk.back()] = j;
                stk.pop_back();
            }
            stk.push_back(j);
        }

        stk.clear();

        for (int j = n; j >= 0; j--) {
            while (!stk.empty() && h[stk.back()] > h[j]) {  // 避免重复计算
                l[stk.back()] = j;
                stk.pop_back();
            }
            stk.push_back(j);
        }

        for (int j = 1; j <= n; j++) {
            ans += (j - l[j]) * (r[j] - j) * h[j];
        }
    }

    std::cout << ans << "\n";
}
posted @ 2025-05-03 19:03  udiandianis  阅读(86)  评论(0)    收藏  举报