C. Sake or Water
先将数组 \(A\) 做降序排序
显然容量最大的 \(N-K\) 杯液体必选,然后清酒也可能出现在后 \(K\) 个杯子里,我们可以对这后 \(k\) 杯液体从前往后贪心地选择,直到喝到的容量达到 \(X\) 毫升为止。
代码实现
#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, k; ll x;
cin >> n >> k >> x;
vector<ll> a(n);
rep(i, n) cin >> a[i];
sort(a.begin(), a.end(), greater<>());
ll sum = 0;
for (int i = n-k; i < n; ++i) {
sum += a[i];
if (sum >= x) {
cout << i+1 << '\n';
return 0;
}
}
puts("-1");
return 0;
}
D. Paid Walk
注意到每个点的出度最多 \(4\),而 \(O(4^L) \leqslant 1e6\),所以直接爆搜即可
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
int main() {
int n, m, l, s, t;
cin >> n >> m >> l >> s >> t;
vector<vector<P>> g(n);
rep(i, m) {
int a, b, c;
cin >> a >> b >> c;
--a; --b;
g[a].emplace_back(b, c);
}
vector<bool> ans(n);
auto f = [&](auto& f, int v, int rem, int sum) -> void {
if (rem == 0) {
if (s <= sum and sum <= t) ans[v] = true;
return;
}
for (auto [u, w] : g[v]) {
f(f, u, rem-1, sum+w);
}
};
f(f, 0, l, 0);
rep(i, n) if (ans[i]) cout << i+1 << ' ';
return 0;
}
E. A > B substring
考虑生成一个整数序列 \(a\),将 A 记为 \(1\),\(B\) 记为 \(-1\),\(C\) 记为 \(0\)
记 \(S_i = a_1 + a_2 + \cdots + a_i\)
区间 \([l, r]\) 里 \(A\) 的个数大于 \(B\) 的个数,等价于 \(S_r-S_{l-1} > 0 \Leftrightarrow S_r > S_{l-1}\)
那么现在的问题就变成了统计 \(l < r\) 且 \(S_r > S_{l-1}\) 的经典二维数点问题
直接上树状数组即可
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n;
string s;
cin >> n >> s;
vector<int> d(n+1);
d[0] = n;
rep(i, n) {
d[i+1] = d[i];
if (s[i] == 'A') d[i+1]++;
if (s[i] == 'B') d[i+1]--;
}
fenwick_tree<int> t(n*2+1);
ll ans = 0;
rep(i, n+1) {
ans += t.sum(0, d[i]);
t.add(d[i], 1);
}
cout << ans << '\n';
return 0;
}
F. Must Buy
两种做法
经典做法是预处理出从左到右和从右到左的 \(01\) 背包 \(dp\),然后将两个拼起来
另外一种做法是考虑分治,如果断开的点在左半部分,那么就对右半部分正常跑 \(01\) 背包;如果断开的点在右半部分,那么就对左半部分正常跑 \(01\) 背包。时间复杂度为 \(\mathcal{O}(MN\log N)\)
代码实现1
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
inline void chmax(ll& a, ll b) { if (a < b) a = b; }
int main() {
int n, m;
cin >> n >> m;
vector<int> p(n), v(n);
rep(i, n) cin >> p[i] >> v[i];
auto calcDP = [&]() {
vector dp(n+1, vector<ll>(m+1));
rep(i, n) {
dp[i+1] = dp[i];
rep(j, m+1-p[i]) chmax(dp[i+1][j+p[i]], dp[i][j]+v[i]);
}
return dp;
};
auto dpl = calcDP();
reverse(p.begin(), p.end());
reverse(v.begin(), v.end());
auto dpr = calcDP();
reverse(p.begin(), p.end());
reverse(v.begin(), v.end());
reverse(dpr.begin(), dpr.end());
auto getMax = [&](vector<ll>& dl, vector<ll> dr, int mx) {
ll res = 0;
rep(i, mx+1) chmax(res, dl[i]+dr[mx-i]);
return res;
};
string ans;
rep(i, n) {
ll a = getMax(dpl[i], dpr[i+1], m-p[i]) + v[i];
ll c = getMax(dpl[i], dpr[i+1], m);
if (a == c) ans += 'B';
else if (a > c) ans += 'A';
else ans += 'C';
}
cout << ans << '\n';
return 0;
}
代码实现2
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
inline void chmax(ll& a, ll b) { if (a < b) a = b; }
int main() {
int n, m;
cin >> n >> m;
vector<int> p(n), v(n);
rep(i, n) cin >> p[i] >> v[i];
string ans;
auto add = [&](vector<ll>& dp, int i) {
for (int j = m-p[i]; j >= 0; --j) {
chmax(dp[j+p[i]], dp[j]+v[i]);
}
};
auto f = [&](auto& f, int l, int r, vector<ll> dp) -> void {
if (r-l == 1) {
ll a = dp[m-p[l]]+v[l];
ll c = dp[m];
if (a == c) ans += 'B';
else if (a > c) ans += 'A';
else ans += 'C';
return;
}
int c = (l+r)/2;
{
auto nd = dp;
for (int i = c; i < r; ++i) add(nd, i);
f(f, l, c, nd);
}
{
auto nd = dp;
for (int i = l; i < c; ++i) add(nd, i);
f(f, c, r, nd);
}
};
f(f, 0, n, vector<ll>(m+1));
cout << ans << '\n';
return 0;
}
G. Takoyaki and Flip
延迟线段树的板子
对于半群信息,需要维护:
- 最大值
- 面朝上的盘子数
- 面朝下的盘子数
对于作用信息,需要维护:
- 待增加的值
- 翻转次数
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
struct S {
ll mx; int up, down;
};
struct F {
ll add; int flip;
};
S op(S a, S b) {
return S(max(a.mx, b.mx), a.up+b.up, a.down+b.down);
}
S e() { return S(0, 0, 0); }
S mapping(F f, S x) {
if (f.flip) {
x.mx = 0;
if (f.flip%2) swap(x.up, x.down);
}
if (x.up) x.mx += f.add;
return x;
}
F composition(F f, F g) {
if (f.flip == 0) f.add += g.add;
f.flip += g.flip;
return f;
}
F id() { return F(0, 0); }
int main() {
int n, q;
cin >> n >> q;
lazy_segtree<S, op, e, F, mapping, composition, id> t(vector<S>(n, S(0, 1, 0)));
rep(qi, q) {
int type, l, r;
cin >> type >> l >> r;
--l;
if (type == 1) {
int x;
cin >> x;
t.apply(l, r, F(x, 0));
}
if (type == 2) {
t.apply(l, r, F(0, 1));
}
if (type == 3) {
ll ans = t.prod(l, r).mx;
cout << ans << '\n';
}
}
return 0;
}
浙公网安备 33010602011771号