A. Glutton Takahashi
模拟
代码实现
n = int(input())
sweet = False
cnt = 0
for i in range(n):
s = input()
cnt += 1
if s == 'sweet':
if sweet: break
sweet = True
else:
sweet = False
if cnt == n: print('Yes')
else: print('No')
B. Grid Walk
模拟
代码
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
const int di[] = {-1, 0, 1, 0};
const int dj[] = {0, 1, 0, -1};
int main() {
int h, w;
cin >> h >> w;
int si, sj;
cin >> si >> sj;
--si; --sj;
vector<string> c(h);
rep(i, h) cin >> c[i];
string x;
cin >> x;
map<char, int> mp;
rep(v, 4) mp["URDL"[v]] = v;
for (char dir : x) {
int v = mp[dir];
int ni = si+di[v], nj = sj+dj[v];
if (ni < 0 or nj < 0 or ni >= h or nj >= w) continue;
if (c[ni][nj] == '#') continue;
si = ni; sj = nj;
}
cout << si+1 << ' ' << sj+1 << '\n';
return 0;
}
C. Minimum Glutton
考虑对其中一个序列做降序排序,这个序列中第一个达到给定值的位置的前缀和就是待定的最小可能的操作次数
然后对两个序列得到的结果取最小值即可
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int f(vector<int> a, ll x) {
ranges::sort(a, greater<>());
rep(i, a.size()) {
x -= a[i];
if (x < 0) return i+1;
}
return a.size();
}
int main() {
int n; ll x, y;
cin >> n >> x >> y;
vector<int> a(n), b(n);
rep(i, n) cin >> a[i];
rep(i, n) cin >> b[i];
int ans = min(f(a, x), f(b, y));
cout << ans << '\n';
return 0;
}
D. K-th Nearest
二分答案
假设答案为 \(x\),考虑以b为圆心,\(x\) 为半径的圆,判断在 \([b-x, b+x]\) 这个范围内的点数是否 \(\geqslant k\)
对于区间内的点数可以用两个二分实现,也就是分别找到两个边界的左边的点数,然后二者作差即可
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n, q;
cin >> n >> q;
vector<int> a(n);
rep(i, n) cin >> a[i];
ranges::sort(a);
rep(qi, q) {
int b, k;
cin >> b >> k;
auto f = [&](int wj) -> bool {
int l = b-wj, r = b+wj;
int li = ranges::lower_bound(a, l) - a.begin();
int ri = ranges::lower_bound(a, r+1) - a.begin();
return ri-li >= k;
};
int wa = -1, ac = 2e8;
while (ac-wa > 1) {
int wj = (ac+wa)/2;
if (f(wj)) ac = wj; else wa = wj;
}
cout << ac << '\n';
}
return 0;
}
E. Maximum Glutton
考虑dp出不超过 \(X\) 和 \(Y\) 时能吃的菜的最大值,最后答案就是在它基础上+1即可
记 dp[i][j][k]
表示从前 \(i\) 道菜中选择若干道菜满足甜度总和为 \(j\) 且咸度总和为 \(k\) 时的最大个数
状态数就是 \(80 \times 10^4 \times 10^4 = 8 \times 10^9\),显然要寄
考虑将个数和咸度总和交换位置
重新定义dp:
记 dp[i][j][k]
表示从前 \(i\) 道才中选 \(j\) 道菜满足甜度总和为 \(k\) 时的咸度总和的最小值
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
inline void chmin(int& a, int b) { if (a > b) a = b; }
int main() {
int n, x, y;
cin >> n >> x >> y;
const int INF = 1001001001;
vector dp(n+1, vector<int>(x+1, INF));
dp[0][0] = 0;
rep(i, n) {
int a, b;
cin >> a >> b;
vector old(n+1, vector<int>(x+1, INF));
swap(dp, old);
rep(j, n+1)rep(k, x+1) {
int now = old[j][k];
if (now == INF) continue;
chmin(dp[j][k], old[j][k]); // not use
if (k+a <= x) chmin(dp[j+1][k+a], now+b); // use
}
}
int ans = 0;
rep(j, n+1)rep(k, x+1) if (dp[j][k] <= y) {
ans = max(ans, j);
}
if (ans < n) ans++;
cout << ans << '\n';
return 0;
}
F. Range Connect MST
不妨假设在连续的相邻两个点之间有一条边,在区间 \([L_i, R_i]\) 中的每个点和 \(N+i\) 连一条边,这意味着,区间 \([L_i, R_i]\) 中的每条边都变成了无用边,可以删除,容易发现只要把 \(N\) 个点中的 \(N-1\) 条边删除自然就能得到生成树。
然后用 std::set
来模拟这个过程即可。
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n, q;
cin >> n >> q;
set<int> cut;
rep(i, n-1) cut.insert(i);
vector<tuple<int, int, int>> qs;
rep(qi, q) {
int l, r, c;
cin >> l >> r >> c;
--l; --r;
qs.emplace_back(c, l, r);
}
ranges::sort(qs);
ll ans = 0;
for (auto [c, l, r] : qs) {
ans += c;
auto it = cut.lower_bound(l);
while (it != cut.end() and *it < r) {
cut.erase(it++);
ans += c;
}
}
if (cut.size() != 0) ans = -1;
cout << ans << '\n';
return 0;
}
G. Last Major City
最小斯坦纳树的板题