ICPC 2023 山东省赛
A. Orders
题目大意
n个订单,要求在\(a_i\)天的时候交付\(b_i\)个产品,每天能生产k个,问能否完成所有订单
解题思路
统计交付日期对应的产品数量,模拟计算剩余产品数量看中途是否会有无法交付的情况即可
代码实现
#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, k, cnt = 0, last = 0;
std::cin >> n >> k;
std::map<i64, i64> mp;
for (int i = 0; i < n; i++) {
i64 a, b;
std::cin >> a >> b;
mp[a] += b;
}
for (auto [a, b] : mp) {
cnt += (a - last) * k - b;
if (cnt < 0) {
std::cout << "No\n";
break;
}
last = a;
}
if (cnt >= 0) {
std::cout << "Yes\n";
}
}
}
I. Three Dice
题目大意
三个六面的筛子,红点数为1和4,剩余为黑点数,问能否投出红点数为a,黑点数为b的组合
解题思路
暴力枚举即可
代码实现
#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 a, b;
std::cin >> a >> b;
for (auto a1 : {0, 1, 4}) {
for (auto a2 : {0, 1, 4}) {
for (auto a3 : {0, 1, 4}) {
for (auto b1 : {0, 2, 3, 5, 6}) {
for (auto b2 : {0, 2, 3, 5, 6}) {
for (auto b3 : {0, 2, 3, 5, 6}) {
if ((int)(a1 == 0) + (int)(a2 == 0) + (int)(a3 == 0) + (int)(b1 == 0) + (int)(b2 == 0) + (int)(b3 == 0) == 3 && a1 + a2 + a3 == a && b1 + b2 + b3 == b) {
std::cout << "Yes\n";
return 0;
}
}
}
}
}
}
}
std::cout << "No\n";
}
G. Matching
题目大意
给定一个数组,如果\(i-j=a_i-a_j\)则对ij连边,边权为两数之和,找最大的边权和
解题思路
条件的意思就是所有的\(a_i-i\)联通,因为要取最大所以降序匹配最大的正数即可
代码实现
#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--) {
int n;
std::cin >> n;
std::map<i64, std::priority_queue<i64>> mp;
for (int i = 0; i < n; i++) {
i64 x;
std::cin >> x;
mp[x - i].emplace(x);
}
i64 ans = 0;
for (auto [x, y] : mp) {
while (y.size() >= 2) {
auto aa = y.top();
y.pop();
auto bb = y.top();
y.pop();
if (aa + bb > 0) {
ans += aa + bb;
} else {
break;
}
}
}
std::cout << ans << "\n";
}
}
D. Fast and Fat
题目大意
队伍有n个人,每个人有速度\(v_i\)和体重\(w_i\),每个人可以带上至多一个人行动,a如果带上b则两人的速度会都变为\(v_a - max(w_b - w_a, 0)\),被带上的人不能再带其他人行动,队伍中速度最慢的人就是整个队伍的速度,问最慢的速度最快是多少
解题思路
二分队伍的速度x,然后考虑check,如果第i个人的速度大于x,则他可以带上\(w_i+v_i-x\)的人,否则就需要被别人带,对速度降序贪心即可
代码实现
#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--) {
int n;
std::cin >> n;
std::vector<std::array<i64, 2>> vw(n);
for (int i = 0; i < n; i++) {
std::cin >> vw[i][0] >> vw[i][1];
}
std::sort(vw.begin(), vw.end(), std::greater<>());
auto check = [&](int x) -> bool {
std::multiset<i64> mst;
for (auto [v, w] : vw) {
if (v >= x) {
mst.insert(w + v - x);
} else {
auto pos = mst.lower_bound(w);
if (pos != mst.end()) {
mst.erase(pos);
} else {
return false;
}
}
}
return true;
};
int l = 1, r = 1e9 + 10;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid)) {
l = mid + 1;
} else {
r = mid - 1;
}
}
std::cout << r << "\n";
}
}
L. Puzzle: Sashigane
题目大意
给定n*n的矩阵,除了指定位置外都要用L型(图形的样子可以自定义)来填充,要求用不超过\(\frac{n^2-1}{3}\)个图形完成填充,输出填充方案
解题思路
根据指定的位置可以知道其上下左右要填充多少格,然后对于lr,ud方向取大填充对应长度即可
代码实现
#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, i, j;
std::cin >> n >> i >> j;
int l = j - 1, r = n - j, u = i - 1, d = n - i;
std::vector<std::array<int, 4>> ans;
while (std::max({l, r, u, d})) {
std::array<int, 4> p;
if (u >= d) {
p[0] = i - u;
p[2] = u + d;
u--;
} else {
p[0] = i + d;
p[2] = -(u + d);
d--;
}
if (l >= r) {
p[1] = j - l;
p[3] = l + r;
l--;
} else {
p[1] = j + r;
p[3] = -(l + r);
r--;
}
ans.push_back(p);
}
std::cout << "Yes\n";
std::cout << ans.size() << "\n";
for (auto [x, y, h, w] : ans) {
std::cout << x << " " << y << " " << h << " " << w << "\n";
}
}
E. Math Problem
题目大意
给定n和k,可以用a的代价将n变为\([kn,k(n+1))\),用b的代价将n变为\(\left\lfloor \frac{n}{k} \right\rfloor\),问让n变成m倍数的最小代价是多少
解题思路
显然一定先进行除法,然后再进行乘法,先预处理除法的代价,然后枚举乘法的代价,最大不会超过mk,然后检查枚举途中除m是否有变化,有则说明中间的某个值会恰好
代码实现
#include <bits/stdc++.h>
using i128 = __int128;
std::ostream &operator<<(std::ostream &out, i128 val) {
if (val == 0) {
return out << "0";
}
if (val < 0) {
out << '-', val = -val;
}
std::string s;
while (val > 0) {
s += '0' + val % 10;
val /= 10;
}
std::reverse(s.begin(), s.end());
return out << s;
}
std::istream &operator>>(std::istream &in, i128 &val) {
std::string s;
in >> s;
val = 0;
bool neg = (s[0] == '-');
for (int i = neg; i < s.size(); i++) {
val = val * 10 + (s[i] - '0');
}
if (neg) {
val = -val;
}
return in;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int tt;
std::cin >> tt;
while (tt--) {
i128 n, k, m, a, b, cnt = 0;
std::cin >> n >> k >> m >> a >> b;
if (k == 1) {
if (n % m == 0) {
std::cout << 0 << "\n";
} else {
std::cout << -1 << "\n";
}
} else {
i128 x = n, ans = LONG_LONG_MAX;
std::vector<std::array<i128, 2>> res;
while (x) {
res.push_back({x, cnt * b});
if (x % m == 0) {
ans = std::min(ans, cnt * b);
}
x /= k;
cnt++;
}
res.push_back({x, cnt * b});
ans = std::min(res.back()[1], ans);
if (n % m == 0) {
ans = 0;
}
std::vector<i128> K = {k};
for (int i = 2; i < 64; i++) {
i128 x = K.back() * k;
if (x > m * k) {
break;
}
K.push_back(x);
}
for (auto [p, q] : res) {
for (int i = 0; i < K.size(); i++) {
if (p * K[i] / m != (p * K[i] + K[i] - 1) / m || p * K[i] % m == 0 || (p * K[i] + K[i] - 1) % m == 0) {
ans = std::min(ans, q + (i + 1) * a);
}
}
}
std::cout << ans << "\n";
}
}
}