C. Mixture
bfs

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
void solve() {
int n;
string s;
cin >> n >> s;
int n2 = 1<<n;
vector<bool> used(n2);
used[0] = true;
queue<int> q;
q.push(0);
while (q.size()) {
int t = q.front(); q.pop();
rep(i, n) {
int nt = t | 1<<i;
if (nt == t) continue;
if (s[nt-1] == '1') continue;
if (used[nt]) continue;
used[nt] = true;
q.push(nt);
}
}
if (used[n2-1]) puts("Yes");
else puts("No");
}
int main() {
int t;
cin >> t;
while (t--) solve();
return 0;
}
D. Get Many Stickers
本质上就是用 \(1\) 张贴纸兑换 \(A_i-B_i\) 个空瓶的问题!
因此只需按照 \(A_i-B_i\) 从小到大的顺序贪心兑换即可。
由于 \(N\) 很大,需要通过数学计算确定兑换次数(这里稍微需要一点算术技巧)。
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
using P = pair<ll, ll>;
int main() {
ll n; int m;
cin >> n >> m;
vector<P> ps;
rep(i, m) {
ll a, b;
cin >> a >> b;
ps.emplace_back(a-b, a);
}
ranges::sort(ps);
ll ans = 0;
for (auto [d, a] : ps) {
if (n < a) continue;
ll x = (n-a)/d+1;
ans += x;
n -= d*x;
}
cout << ans << '\n';
return 0;
}
E. Hungry Takahashi
一种做法是二分答案,然后用dp来判定
记 dp[i][j] 表示在到达格子 \((i, j)\) 时所持有的硬币的最大值
代码实现
#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 h, w;
cin >> h >> w;
vector a(h, vector<int>(w));
rep(i, h)rep(j, w) cin >> a[i][j];
int n = h+w-1;
vector<int> p(n);
rep(i, n) cin >> p[i];
const ll INF = 1e18;
auto judge = [&](ll x) {
vector dp(h, vector<ll>(w, -INF));
dp[0][0] = x;
rep(i, h)rep(j, w) {
dp[i][j] += a[i][j] - p[i+j];
if (dp[i][j] < 0) dp[i][j] = -INF;
if (i+1 < h) chmax(dp[i+1][j], dp[i][j]);
if (j+1 < w) chmax(dp[i][j+1], dp[i][j]);
}
return dp[h-1][w-1] >= 0;
};
ll ac = 1e15, wa = -1;
while (ac-wa > 1) {
ll wj = (ac+wa)/2;
if (judge(wj)) ac = wj; else wa = wj;
}
cout << ac << '\n';
return 0;
}
事实上不需要二分,可以考虑从后往前做dp
那么当前格子上的硬币就会从高桥手上回退到格子上,原本买食物花的硬币会回到高桥手上
代码实现
#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; }
inline void chmin(ll& a, ll b) { if (a > b) a = b; }
int main() {
int h, w;
cin >> h >> w;
vector a(h, vector<int>(w));
rep(i, h)rep(j, w) cin >> a[i][j];
int n = h+w-1;
vector<int> p(n);
rep(i, n) cin >> p[i];
const ll INF = 1e18;
vector dp(h, vector<ll>(w, INF));
dp[h-1][w-1] = 0;
for (int i = h-1; i >= 0; --i) {
for (int j = w-1; j >= 0; --j) {
dp[i][j] += p[i+j] - a[i][j];
chmax(dp[i][j], 0ll);
if (i) chmin(dp[i-1][j], dp[i][j]);
if (j) chmin(dp[i][j-1], dp[i][j]);
}
}
cout << dp[0][0] << '\n';
return 0;
}
F. Max Combo
线段树
需要对每个点维护以下信息:
- 答案
- 左端开始的极大同种字符长度
- 右端开始的极大同种字符长度
- 区间中的字符是否都相同
代码实现
#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;
inline void chmax(int& a, int b) { if (a < b) a = b; }
struct S {
int ans;
char lc; int l;
char rc; int r;
bool same;
};
S op(S a, S b) {
if (a.ans == 0) return b;
if (b.ans == 0) return a;
S res;
res.ans = max(a.ans, b.ans);
if (a.rc == b.lc) chmax(res.ans, a.r+b.l);
res.lc = a.lc; res.l = a.l;
res.rc = b.rc; res.r = b.r;
if (a.same and a.lc == b.lc) res.l += b.l;
if (b.same and a.rc == b.rc) res.r += a.r;
res.same = a.same and b.same and a.lc == b.lc;
return res;
}
S e() { return S(0, '?', 0, '?', 0, false); }
S newS(char c) { return S(1, c, 1, c, 1, true); }
int main() {
cin.tie(nullptr) -> sync_with_stdio(false);
int n, q;
string s;
cin >> n >> q >> s;
segtree<S, op, e> t(n);
rep(i, n) t.set(i, newS(s[i]));
rep(qi, q) {
int type;
cin >> type;
if (type == 1) {
int i; char x;
cin >> i >> x;
--i;
t.set(i, newS(x));
}
else {
int l, r;
cin >> l >> r;
--l;
cout << t.prod(l, r).ans << '\n';
}
}
return 0;
}
G. Get Many Cola
本质上是每消耗 \(A_i-B_i\) 个空瓶可兑换 \(B_i\) 瓶饮料,这实际上是一个背包问题的变种!
对于此类背包问题,当背包容量超过 \(O(\text{物品重量}^2)\) 时,优先装入价值/重量比最大的物品是最优策略。
因此,背包容量上限为 \(O(A^2)\),对每个 \(A_i\),只需保留 \(B_i\) 最大的有效物品,使物品种类降至 \(O(B)\)
最终时间复杂度为 \(O(A^2B)\)
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
template<class T>
inline void chmax(T& a, T b) { if (a < b) a = b; }
int main() {
ll n; int M;
cin >> n >> M;
int m = 300;
vector<int> b(m+1);
rep(i, M) {
int A, B;
cin >> A >> B;
chmax(b[A], B);
}
int x = 1;
for (int i = 1; i <= m; ++i) {
if (b[i]*(x-b[x]) > b[x]*(i-b[i])) x = i;
}
const ll INF = 1e18;
int mx = x*m+1;
vector<ll> dp(mx);
rep(s, mx) {
for (int i = 1; i <= m; ++i) {
if (s < i) continue;
chmax(dp[s], dp[s-i+b[i]]+b[i]);
}
}
ll ans = n;
if (n > mx) {
ll t = (n-mx)/(x-b[x])+1;
n -= (x-b[x])*t;
ans += b[x]*t;
}
ans += dp[n];
cout << ans << '\n';
return 0;
}
浙公网安备 33010602011771号