C. Third Largest Number
维护前 \(3\) 大的数,比较好的实现是开一个大小为 \(3\) 的数组,每加入一个数,做一遍排序,然后弹出最小的数
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n;
cin >> n;
vector<int> d(3);
rep(i, n) {
int a;
cin >> a;
d.push_back(a);
ranges::sort(d, greater<>());
d.pop_back();
if (i >= 2) cout << d[2] << '\n';
}
return 0;
}
D. Automat
先尽可能多地(按价格从小到大)把能“仅用 \(K\) 钞”买下的饮料取出(这些饮料不会消耗 \(1\) 元票据),把它们当成普通商品和甜点合并在一起;
然后把所有剩下的商品(甜点 + 已取出的饮料)按价格从小到大买,使用总体的“货币总量”上限 \(x + y*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, m, k;
ll x, y;
cin >> n >> m >> k >> x >> y;
vector<int> a(n), b(m);
rep(i, n) cin >> a[i];
rep(i, m) cin >> b[i];
ranges::sort(b);
{
int r = 0;
ll used = 0;
while (r < m) {
used += (b[r]+k-1)/k;
if (used > y) break;
++r;
}
rep(i, r) a.push_back(b[i]);
}
ranges::sort(a);
int ans = 0;
ll tot = 0;
while (ans < a.size()) {
tot += a[ans];
if (tot > x+y*k) break;
ans++;
}
cout << ans << '\n';
return 0;
}
E. Min-Max Swap
开两颗线段树用来维护区间最小值和区间最大值,至于它们对应的位置可以用线段树二分
但考虑到 \(P\) 是一个排列,于是我们只需维护一个位置数组即可
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int min_(int a, int b) { return min(a, b); }
int max_(int a, int b) { return max(a, b); }
int e_min() { return 1e9; }
int e_max() { return 0; }
int main() {
int n, m;
cin >> n >> m;
vector<int> p(n);
rep(i, n) cin >> p[i];
segtree<int, min_, e_min> t_min(p);
segtree<int, max_, e_max> t_max(p);
vector<int> q(n+1);
rep(i, n) q[p[i]] = i;
rep(i, m) {
int l, r;
cin >> l >> r;
--l;
int a = t_min.prod(l, r);
int b = t_max.prod(l, r);
int ai = q[a], bi = q[b];
swap(p[ai], p[bi]);
swap(q[a], q[b]);
t_min.set(ai, p[ai]); t_min.set(bi, p[bi]);
t_max.set(ai, p[ai]); t_max.set(bi, p[bi]);
}
rep(i, n) cout << p[i] << " \n"[i == n-1];
return 0;
}
F. Chebyshev Cafe
原坐标系下的切比雪夫距离,等于坐标映射为 \((x+y, x-y)\) 后的曼哈顿距离的一半。
由于曼哈顿距离的 \(u\) 轴与 \(v\) 轴完全独立,问题降维为两个一维问题:
- 计算网格每点人数 \(C(i, j) = (A_i B_j) \bmod M\),并分别按 \(u = i+j\) 和 \(v = i-j\) 统计各轴上的总人数 \(S_u[u]\) 与 \(S_v[v]\)。
- 计算各轴上的一维总距离:
- \(T_u[u] = \sum S_u[u'] \cdot \vert{}u - u'\vert{}\)
- \(T_v[v] = \sum S_v[v'] \cdot \vert{}v - v'\vert{}\)
- 点 \((i, j)\) 的总花费即为 \(f(i, j) = \frac{T_u[i+j] + T_v[i-j]}{2}\),遍历累加 \(f(i,j) + (i-1)N + (j-1)\) 的异或和即可。
代码实现
#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, m;
cin >> n >> m;
vector<ll> a(n), b(n);
rep(i, n) cin >> a[i];
rep(i, n) cin >> b[i];
vector c(n, vector<int>(n));
rep(i, n)rep(j, n) {
c[i][j] = a[i]*b[j]%m;
}
vector d(n, vector<ll>(n));
rep(ri, 2) {
vector<ll> s(n*2);
rep(i, n)rep(j, n) s[i+j] += c[i][j];
vector<ll> t(n*2);
rep(i, n*2)rep(j, n*2) t[i] += s[j]*abs(i-j);
rep(i, n)rep(j, n) d[i][j] += t[i+j];
ranges::reverse(c);
ranges::reverse(d);
}
rep(i, n)rep(j, n) d[i][j] /= 2;
ll ans = 0;
rep(i, n)rep(j, n) {
ans ^= d[i][j] + n*i + j;
}
cout << ans << '\n';
return 0;
}
G. Increasing Popcount
先把原题变成 \(\text{popcount}\) 序列的 \(\text{LNIS}\),再把区间拆成二进制对齐块;每个块内部用 \(\text{Sperner}\) 定理说明最优方案只需选一个 \(\text{popcount}\) 层,而层大小就是 \(\binom{k}{r}\),最后对“上一层的 \(\text{popcount} \geqslant\) 当前层”做 \(61\) 个状态的 \(\text{dp}\) 。
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
const int B = 60;
ll comb[B+1][B+1];
void init() {
comb[0][0] = 1;
rep(i, B)rep(j, i+1) {
comb[i+1][j] += comb[i][j];
comb[i+1][j+1] += comb[i][j];
}
}
void solve() {
ll l, r;
cin >> l >> r;
vector<ll> dp(B+1);
ll x = l;
while (x <= r) {
int k = __builtin_ctzll(x);
ll len = 1ll<<k;
while (x+len-1 > r) {
len >>= 1;
--k;
}
int d = __builtin_popcountll(x>>k);
vector<ll> suf(B+2);
for (int i = B; i >= 0; --i) {
suf[i] = max(suf[i+1], dp[i]);
}
auto old = dp;
rep(j, k+1) {
int i = d+j;
dp[i] = max(dp[i], suf[i]+comb[k][j]);
}
x += len;
}
ll ans = ranges::max(dp);
cout << ans << '\n';
}
int main() {
init();
int t;
cin >> t;
while (t--) solve();
return 0;
}
浙公网安备 33010602011771号