一题多解
目录
P1073 [NOIP 2009 提高组] 最优贸易
SCC
#include <bits/stdc++.h>
using i64 = long long;
struct SCC {
int n;
std::vector<std::vector<int>> adj;
std::vector<int> stk;
std::vector<int> dfn, low, bel;
int cur, cnt;
SCC() {}
SCC(int n) {
init(n);
}
void init(int n) {
this->n = n;
adj.assign(n, {});
dfn.assign(n, -1);
low.resize(n);
bel.assign(n, -1);
stk.clear();
cur = cnt = 0;
}
void addEdge(int u, int v) {
adj[u].push_back(v);
}
void dfs(int x) {
dfn[x] = low[x] = cur++;
stk.push_back(x);
for (auto y : adj[x]) {
if (dfn[y] == -1) {
dfs(y);
low[x] = std::min(low[x], low[y]);
} else if (bel[y] == -1) {
low[x] = std::min(low[x], dfn[y]);
}
}
if (dfn[x] == low[x]) {
int y;
do {
y = stk.back();
bel[y] = cnt;
stk.pop_back();
} while (y != x);
cnt++;
}
}
std::vector<int> work() {
// for (int i = 0; i < n; i++) {
// if (dfn[i] == -1) {
// dfs(i);
// }
// }
dfs(0);
return bel;
}
};
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, m;
std::cin >> n >> m;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
SCC g(n);
for (int i = 0, u, v, t; i < m; ++i) {
std::cin >> u >> v >> t;
--u, --v;
g.addEdge(u, v);
if (t == 2) {
g.addEdge(v, u);
}
}
g.work();
int N = g.cnt;
constexpr int inf = 1E9;
std::vector<int> f0(N, inf), f1(N);
for (int i = 0; i < n; ++i) {
int j = g.bel[i];
if (j == -1) {
continue;
}
f0[j] = std::min(f0[j], a[i]);
f1[j] = std::max(f1[j], a[i]);
}
std::vector<std::vector<int>> adj(N);
std::vector<int> d(N);
for (int i = 0; i < n; ++i) {
for (auto v : g.adj[i]) {
int x = g.bel[i], y = g.bel[v];
if (x == y || x == -1 || y == -1) {
continue;
}
adj[x].push_back(y);
++d[y];
}
}
std::vector<int> dp(N);
std::queue<int> q;
q.push(g.bel[0]);
int ans = 0;
while (!q.empty()) {
auto u = q.front();
q.pop();
dp[u] = std::max(dp[u], f1[u] - f0[u]);
for (auto v : adj[u]) {
f0[v] = std::min(f0[v], f0[u]);
dp[v] = std::max(dp[u], dp[v]);
if (--d[v] == 0) {
q.push(v);
}
}
}
std::cout << dp[g.bel[n - 1]] << "\n";
}
分层图

#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, m;
std::cin >> n >> m;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
std::vector<std::vector<std::pair<int, int>>> adj(3 * n);
auto addEdge = [&](int u, int v) {
adj[u].push_back({v, 0});
adj[u + n].push_back({v + n, 0});
adj[u + 2 * n].push_back({v + 2 * n, 0});
};
for (int i = 0, u, v, t; i < m; ++i) {
std::cin >> u >> v >> t;
--u, --v;
addEdge(u, v);
if (t == 2) {
addEdge(v, u);
}
}
for (int u = 0; u < n; ++u) {
adj[u].push_back({u + n, -a[u]});
adj[u + n].push_back({u + 2 * n, a[u]});
}
constexpr int inf = 1E9;
std::vector<int> dist(3 * n, -inf);
auto spfa = [&]() -> void {
std::vector<bool> st(3 * n);
std::queue<int> q;
q.push(0);
st[0] = true;
dist[0] = 0;
while (!q.empty()) {
auto u = q.front();
q.pop();
st[u] = false;
for (auto [v, w] : adj[u]) {
if (dist[v] >= dist[u] + w) {
continue;
}
dist[v] = dist[u] + w;
if (!st[v]) {
st[v] = true;
q.push(v);
}
}
}
};
spfa();
std::cout << std::max(dist.back(), 0) << "\n";
}s
反图
后面最大 - 前面最小
两次SPFA
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, m;
std::cin >> n >> m;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
std::vector<std::vector<int>> g(n), rg(n);
for (int i = 0, u, v, t; i < m; ++i) {
std::cin >> u >> v >> t;
--u, --v;
g[u].push_back(v);
rg[v].push_back(u);
if (t == 2) {
g[v].push_back(u);
rg[u].push_back(v);
}
}
constexpr int inf = 1E9;
std::vector<int> mn(n, inf);
{
std::queue<int> q;
std::vector<bool> inq(n, false);
mn[0] = a[0];
q.push(0);
inq[0] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
inq[u] = false;
for (int v : g[u]) {
if (mn[v] > std::min(mn[u], a[v])) {
mn[v] = std::min(mn[u], a[v]);
if (!inq[v]) {
inq[v] = true;
q.push(v);
}
}
}
}
}
std::vector<int> mx(n, -inf);
{
std::queue<int> q;
std::vector<bool> inq(n, false);
mx[n - 1] = a[n - 1];
q.push(n - 1);
inq[n - 1] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
inq[u] = false;
for (int v : rg[u]) {
if (mx[v] < std::max(mx[u], a[v])) {
mx[v] = std::max(mx[u], a[v]);
if (!inq[v]) {
inq[v] = true;
q.push(v);
}
}
}
}
}
int ans = 0;
for (int i = 0; i < n; ++i) {
if (mn[i] == inf || mx[i] == -inf) {
continue;
}
ans = std::max(ans, mx[i] - mn[i]);
}
std::cout << ans << '\n';
return 0;
}
XOR 问题
数组A全部xor 一个数,使得最大值最小
问题
Trie
#include <bits/stdc++.h>
using i64 = long long;
constexpr int N = 1E7;
int tot;
int trie[N][2];
int newNode() {
++tot;
trie[tot][0] = trie[tot][1] = 0;
return tot;
}
void insert(int x) {
int p = 1;
for (int i = 30; i >= 0; --i) {
int u = x >> i & 1;
if (!trie[p][u]) {
trie[p][u] = newNode();
}
p = trie[p][u];
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
tot = 0;
newNode();
for (int x : a) {
insert(x);
}
auto dfs = [&](this auto &&self, int p, int k) -> int {
if (p == 0) {
return 0;
}
if (trie[p][0] && trie[p][1]) {
return std::min(self(trie[p][0], k - 1), self(trie[p][1], k - 1)) | 1 << k;
}
return self(std::max(trie[p][0], trie[p][1]), k - 1);
};
std::cout << dfs(1, 30);
}
sort + partition_point
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int N;
std::cin >> N;
std::vector<int> a(N);
for (int i = 0; i < N; i++) {
std::cin >> a[i];
}
std::sort(a.begin(), a.end());
auto solve = [&](auto solve, int l, int r, int k) {
if (k == 0) return 0;
int m = std::partition_point(a.begin() + l, a.begin() + r, [&](int x) { return ~x >> (k - 1) & 1; }) - a.begin();
if (l == m || m == r) return solve(solve, l, r, k - 1);
return std::min(solve(solve, l, m, k - 1), solve(solve, m, r, k - 1)) | 1 << (k - 1);
};
std::cout << solve(solve, 0, N, 30) << "\n";
return 0;
}
数组中 $ A_i + A_j = C$ 的个数
二分
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, c;
std::cin >> n >> c;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
std::sort(a.begin(), a.end());
i64 ans = 0;
for (int i = 0; i < n; ++i) {
int x = a[i] - c;
ans += std::upper_bound(a.begin(), a.end(), x) - std::lower_bound(a.begin(), a.end(), x);
}
std::cout << ans << "\n";
}
双指针
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, c;
std::cin >> n >> c;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
std::sort(a.begin(), a.end());
i64 ans = 0;
for (int i = 0, l = 0, r = 0; i < n; ++i) {
int x = a[i] - c;
while (a[l] < x) {
++l;
}
while (a[r] <= x) {
++r;
}
ans += r - l;
}
std::cout << ans << "\n";
}
hash表
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
i64 n, c;
std::cin >> n >> c;
std::vector<i64> v(n);
for (int i = 0; i < n; ++i) {
std::cin >> v[i];
}
std::unordered_map<i64, int> h;
i64 re = 0;
for (i64 x : v) {
re += h[x - c] + h[c + x];
++h[x];
}
std::cout << re;
return 0; // 结束了罪恶的一生!
}
仓库选址
数轴上n个人的坐标,问走的一起的总路程最小是多少?
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
int m = n / 2;
std::sort(a.begin(), a.end());
i64 ans = 0;
for (int x : a) {
ans += std::abs(x - a[m]);
}
std::cout << ans << "\n";
}
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
std::sort(a.begin(), a.end());
i64 ans = 0;
for (int i = 0; i < n; ++i) {
ans += a[i] - a[i / 2];
}
std::cout << ans << "\n";
}
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
int m = n / 2;
std::nth_element(a.begin(), a.begin() + m, a.end());
i64 ans = 0;
for (int x : a) {
ans += std::abs(x - a[m]);
}
std::cout << ans << "\n";
}
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
constexpr int N = 4E4 + 5;
std::vector<int> cnt(N);
for (int i = 0, x; i < n; ++i) {
std::cin >> x;
++cnt[x];
}
i64 ans = 0;
for (int i = 0, s = 0; i < N; ++i) {
s += cnt[i];
ans += std::min(s, n - s);
}
std::cout << ans << "\n";
}
倍增可以 按位和二分查询
题目
l区间and >= k 的最右侧 r
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
int L = std::__lg(n);
std::vector val(L + 1, std::vector<int>(n));
val[0] = a;
for (int i = 0; i < L; ++i) {
for (int j = 0; j + (1 << i) < n; ++j) {
val[i + 1][j] = val[i][j] & val[i][j + (1 << i)];
}
}
auto qry = [&](int l, int r) -> int {
int len = std::__lg(r - l);
return val[len][l] & val[len][r - (1 << len)];
};
int q;
std::cin >> q;
for (int i = 0; i < q; ++i) {
int l, k;
std::cin >> l >> k;
--l;
int lo = l, hi = n;
while (lo < hi) {
auto mid = lo + (hi - lo + 1) / 2;
if (qry(l, mid) >= k) {
lo = mid;
} else {
hi = mid - 1;
}
}
std::cout << (lo == l ? -1 : lo) << " ";
// int x = (1 << 30) - 1;
// int p = l;
// for (int j = L; j >= 0 && p < n; --j) {
// if ((val[j][p] & x) >= k) {
// x &= val[j][p];
// p += 1 << j;
// }
// }
// std::cout << (p == l ? -1 : p) << " ";
}
std::cout << std::endl;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t;
std::cin >> t;
while (t--) {
solve();
}
}
二分图判断 DSU
博客有一场CF E题
Codeforces Round 805 (Div. 3)

浙公网安备 33010602011771号