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";
}

浙公网安备 33010602011771号