重新把蓝书刷一遍(不定期更新)
算法竞赛进阶指南
基本算法
位运算
a^b
ll a, b, p;
ll qpow(ll a, ll b) {
ll ans = 1 % p;
for (; b; b >>= 1, a = a * a % p) if (b & 1) ans = ans * a % p;
return ans;
}
int main() {
cin >> a >> b >> p;
cout << qpow(a, b);
return 0;
}
a*b
ll a, b, p;
ll qmul(ll a, ll b) {
ll ans = 0;
for (; b; b >>= 1, a = a * 2 % p) if (b & 1) ans = (ans + a) % p;
return ans;
}
int main() {
cin >> a >> b >> p;
cout << qmul(a, b);
return 0;
}
⭐最短Hamilton路径
状压已经走过的点, d[k][i] 表示状态以i结尾的最小花费
要求 1 到 n 的最短Hamiton路径, 起始 d[1][0] = 0, 要求 d[(1 << n) - 1][n - 1]
转移的时候切记 0 不能作为转移之后的结束点, 0 只能做 d[1][0] 的结束点
d[7][0] 由于 d[6][1 or 2] 本身达不到, 故不存在 d[7][0] = d[6][1 or 2] + mp[1 or 2][0],
所以我们不用考虑中间态的结束点为 0, 只要注意转义的状态不以 0 结束即可
int mp[20][20], n, d[1 << 21][20];
int main() {
cin >> n; memset(d, 0x3f, sizeof d); d[1][0] = 0;
for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) cin >> mp[i][j];
for (int k = 1; k < (1 << n); ++k)
for (int i = 0; i < n; ++i) if (k != i && (k >> i & 1))
for (int j = 0; j < n; ++j) if (k >> j & 1 && j && j != i)
d[k][j] = min(d[k][j], d[k ^ (1 << j)][i] + mp[i][j]);
cout << d[(1 << n) - 1][n - 1];
return 0;
}
起床困难综合征
int n, m, _, a = (1 << 30) - 1, b = 0;
char s[5];
int main() {
cin >> n >> m; int ;
while (cin >> s >> _)
switch (s[0]) {
case 'X' : a ^= _, b ^= _; break;
case 'O' : a |= _, b |= _; break;
case 'A' : a &= _, b &= _; break;
}
int res = 0, ans = 0;
for (int i = 29; ~i; --i) if (res ^ (1 << i) <= m)
if (b >> i & 1) ans ^= 1 << i;
else if (a >> i & 1) res ^= 1 << i, ans ^= 1 << i;
cout << ans;
return 0;
}
递推与递归
递归实现指数型枚举
int n, a[15];
void work(int x, int k) {
if (k > n) return; work(x, k + 1); a[x - 1] = k;
for (int i = 0; i < x; ++i) cout << a[i] << ' '; cout << '\n';
work(x + 1, k + 1);
}
int main() {
cin >> n; cout << '\n'; work(1, 1);
return 0;
}
递归实现组合型枚举
int n, m, a[25];
void work(int x, int k) {
if (x > m) { for (int i = 0; i < m; ++i) cout << a[i] << ' '; cout << '\n'; return; }
if (k > n) return;
a[x - 1] = k; work(x + 1, k + 1); work(x, k + 1);
}
int main() {
cin >> n >> m; work(1, 1);
return 0;
}
递归实现排列型枚举
int n, a[9];
int main() {
cin >> n; for (int i = 0; i < n; ++i) a[i] = i + 1, cout << i + 1 << ' ';
for (cout << '\n';next_permutation(a, a + n); cout << '\n')
for (int i = 0; i < n; ++i) cout << a[i] << ' ';
return 0;
}
费解的开关
int a[25][25], _, b[25][25], cnt, cur;
void work(int x, int y) {
if (x) b[x - 1][y] ^= 1;
if (x < 4) b[x + 1][y] ^= 1;
if (y) b[x][y - 1] ^= 1;
if (y < 4) b[x][y + 1] ^= 1;
b[x][y] ^= 1; ++cur;
}
int main() {
for (cin >> _, cnt = 7; _; --_, cnt = 7) {
for (int i = 0; i < 5; ++i) for (int j = 0; j < 5; ++j) scanf("%1d", a[i] + j);
for (int i = 0; i < (1 << 5); ++i) {
memcpy(b, a, sizeof a); cur = 0;
for (int j = 0; j < 5; ++j) if (i >> j & 1) work(0, j);
for (int j = 0; j < 4; ++j) for (int k = 0; k < 5; ++k) if (!b[j][k]) work(j + 1, k);
for (int j = 0; j < 5; ++j) if (!b[4][j]) { cur = 7; break; }
cnt = min(cnt, cur);
}
cout << (cnt == 7 ? -1 : cnt) << '\n';
}
return 0;
}
⭐奇怪的汉诺塔
-
要将n个盘子移到 d, 就要先把 x 个盘子从 a 借助 b, c, d 移到b(c)上
-
再把剩下的(n - x)个盘子, 从 a 借助 c(b), d 移动到 d 上
-
再把 x 个盘子 从 b(c) 借助 a, c(b), d 移动到 d 上
第2步, 就是最普通的汉诺塔
int d[13], f[13];
int main() {
for (int i = 1; i < 13; ++i) {
d[i] = (d[i - 1] << 1) + 1; f[i] = 0x3f3f;
for (int j = 0; j < i; ++j) f[i] = min(f[i], (f[j] << 1) + d[i - j]);
cout << f[i] << '\n';
}
return 0;
}
⭐约数之和
用公式 \(\frac {a(q^n-1)} {q - 1}\) 主要考虑 (q - 1) % mod == 0的问题
设 q = k * mod + 1, 则
\(\frac {q^n-1} {q - 1}\) % mod = \(\frac {(kmod + 1)^n-1} {kmod - 1 + 1}\) % mod
\(= \frac {(kmod)^n + C_n^{n - 1}(kmod)^{n - 1} + ... + C_n^1(kmod) + 1 - 1} {k * mod}\) % mod
\(= [(kmod)^{n - 1} + C_n^{n - 1}(kmod)^{n - 2} + .. + C_n^1]\) % mod
\(= C_n^1\) % mod = n % mod
然后分情况讨论即可
ll a, b, ans = 1;
ll qpow(ll a, ll b) {
ll ans = 1;
for (; b; b >>= 1, a = a * a % mod) if (b & 1) ans = ans * a % mod;
return ans;
}
int main() {
cin >> a >> b; if (!a) return cout << 0, 0;
for (int i = 2; i <= a; ++i) if (a % i == 0) {
int cnt = 0; for (; a % i == 0; a /= i, cnt += b); ++cnt;
if ((i - 1) % mod == 0) ans = ans * (cnt % mod) % mod;
else ans = (qpow(i, cnt) - 1 + mod) % mod * ans % mod * qpow(i - 1, mod - 2) % mod;
}
cout << ans;
return 0;
}
⭐分型之城
写过单独的题解, 就不细说了, 能搜到
就像2019的蓝桥国赛A组, 一道题填空, 一道大题都是类似这道题的
PLL work(ll id, int k) {
if (!k) return { 1, 1 };
ll len = 1 << k - 1, sz = len * len;
auto cur = work(id % sz, k - 1);
switch (id / sz) {
case 0 : return { cur.se, cur.fi };
case 1 : return { cur.fi + len, cur.se };
case 2 : return { cur.fi + len, cur.se + len };
}
return { len + 1 - cur.se, (len << 1) + 1 - cur.fi };
}
int main() {
for (cin >> _; _; --_) {
ll a, b; cin >> n >> a >> b; --a, --b;
PLL x = work(a, n), y = work(b, n);
cout << (ll)round(sqrt(sqr(x.fi - y.fi) + sqr(x.se - y.se)) * 10) << '\n';
}
return 0;
}
前缀和与差分
激光炸弹
注意卡空间, 不开ll就行了
int s[5002][5002], ans;
int main() {
cin >> n >> m;
for (int i = 0; i < n; ++i) {
int x, y, z; cin >> x >> y >> z;
s[x + 1][y + 1] += z;
}
for (int i = 1; i <= 5001; ++i) for (int j = 1; j <= 5001; ++j) {
s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
if (i >= m && j >= m) ans = max(ans, s[i][j] - s[i - m][j] - s[i][j - m] + s[i - m][j - m]);
else if (i >= m) ans = max(ans, s[i][j] - s[i - m][j]);
else if (j >= m) ans = max(ans, s[i][j] - s[i][j - m]);
else ans = max(ans, s[i][j]);
}
cout << ans;
return 0;
}
IncDec序列
long long n, a[100000], x, y;
int main() {
cin >> n; for (int i = 0; i < n; ++i) cin >> a[i];
for (int i = n - 1; i; --i) { a[i] -= a[i - 1]; if (a[i] > 0) x += a[i]; else y -= a[i]; }
cout << min(x, y) + abs(x - y) << '\n' << abs(y - x) + 1;
return 0;
}
最高的牛
int n, p, h, m, s[10001];
int main() {
cin >> n >> p >> s[0] >> m; set<pair<int, int>> v;
for (int i = 0; i < m; ++i) {
int a, b; cin >> a >> b; if (a > b) swap(a, b);
if (a == b || v.count({ a, b })) continue;
v.insert({ a, b }); --s[a + 1], ++s[b];
}
for (int i = 1; i <= n; ++i) cout << (s[i] += s[i - 1]) << '\n';
return 0;
}
二分
最佳牛围栏
这样check是不对的, 不存在尺取和贪心, nlogn 就行了没必要再画蛇添足
bool check(ll mid) {
for (int i = 1, j = m; i + m - 1 <= n; j = ++i + m - 1) {
ll cur = s[j] - s[i - 1];
while (j < n && cur <= a[j + 1] * (j - i + 1)) cur += a[++j];
if (cur >= mid * (j - i + 1)) return 1;
}
return 0;
}
ll a[100001], b[100001];
bool check(ll mid) {
for (int i = 1; i < m; ++i) b[i] = a[i] - mid + b[i - 1];
for (ll i = m, mi = 0; i <= n; ++i) {
mi = min(mi, b[i - m]); b[i] = a[i] - mid + b[i - 1];
if (b[i] - mi >= 0) return 1;
}
return 0;
}
int main () {
cin >> n >> m; for (int i = 1; i <= n; ++i) cin >> a[i], a[i] *= 1000;
ll l = 1, r = 2000000;
while (l < r) {
ll mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
cout << l;
return 0;
}+
⭐特殊排序
比较不好想二分, 我们保证 a[l - 1] < i && a[r + 1] > i, 然后不断缩小 l~r 就好了
最后是 r = l - 1, 及 a[r + 1] -> a[l] > i, a[l - 1] = a[r] > i 所以 i 插在 r 和 l 之间
class Solution {
public:
vector<int> specialSort(int N) {
vector<int> res(1, 1);
for (int i = 2; i <= N; ++ i) {
int l = 0, r = res.size() - 1;
while (l <= r) {
int mid = (l + r) >> 1;
if (compare(res[mid], i)) l = mid + 1;
else r = mid - 1;
}
res.insert(l + res.begin(), i);
}
return res;
}
};
排序
电影
int n, x, y, ans, _, a[200001];
unordered_map<int, int> st;
int main() {
for (cin >> _; _; --_) cin >> ans, ++st[ans];
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 1; i <= n; ++i) {
int cur; cin >> cur;
if (st[a[i]] > x) ans = i, x = st[a[i]], y = st[cur];
else if (st[a[i]] == x && st[cur] > y) ans = i, y = st[cur];
}
cout << ans;
return 0;
}
仓货选址
ll n, a[100000], ans;
int main() {
cin >> n; for (int i = 0; i < n; ++i) cin >> a[i]; sort(a, a + n);
for (int i = 0; i < n; ++i) ans += abs(a[i] - a[n - 1 >> 1]);
cout << ans;
return 0;
}
⭐七夕祭
单独写过题解, 就不解释了, 环形均摊纸牌 + 仓货选址
ll work(int a[], int n) {
for (int i = 0; i < n; ++i) s[i] = s[i - 1] + a[i] - k / n;
sort(s, s + n); ll ans = 0;
for (int i = 0; i < n; ++i) ans += abs(s[i] - s[n >> 1]);
return ans;
}
int main() {
cin >> n >> m >> k;
for (int i = 0; i < k; ++i) {
int a, b; cin >> a >> b;
++c[--b], ++r[--a];
}
if (k % n + k % m == 0) cout << "both " << work(c, m) + work(r, n);
else if (k % n == 0) cout << "row " << work(r, n);
else if (k % m == 0) cout << "column " << work(c, m);
else cout << "impossible";
return 0;
}
动态中位数(对顶堆)
int main() {
for (cin >> _; _; --_) {
int id; cin >> id >> n; cout << id << ' ' << (n + 1 >> 1);
priority_queue<int> x, y;
for (int i = 1; i <= n; ++i) {
int a; cin >> a;
if (x.size() <= y.size())
if (!y.empty() && -y.top() < a) x.push(-y.top()), y.pop(), y.push(-a);
else x.push(a);
else
if (x.top() > a) y.push(-x.top()), x.pop(), x.push(a);
else y.push(-a);
if (i % 20 == 1) cout << '\n';
if (i & 1) cout << x.top() << ' ';
}
cout << '\n';
}
return 0;
}
超快速排序
找逆序对
int n, _, a[500001], c[500001];
void add(int x, int k) { for (; x <= n; x += -x & x) c[x] += k; }
int ask(int x) { int ans = 0; for (; x; x -= -x & x) ans += c[x]; return ans; }
int main() {
while (cin >> n, n) {
vector<int> c(n + 1, -1); ll ans = 0;
for (int i = 1; i <= n; ++i) cin >> a[i], c[i] = a[i];
sort(all(c)); c.erase(unique(all(c)), c.end());
for (int i = 1; i <= n; add(a[i++], 1))
ans += ask(n) - ask(a[i] = lower_bound(all(c), a[i]) - c.begin());
for (int i = 1; i <= n; add(a[i++], -1));
cout << ans << '\n';
}
return 0;
}
奇数码问题
int n, _, a[250000], c[250000];
void add(int x, int k) { for (; x && x < n * n; x += -x & x) c[x] += k; }
int ask(int x) { int ans = 0; for (; x; x -= -x & x) ans += c[x]; return ans; }
int main() {
while (cin >> n) {
int x = 0;
for (int i = 0; i < n * n; add(a[i++], 1)) {
cin >> a[i]; if (!a[i]) continue;
x += ask(n * n - 1) - ask(a[i]);
}
for (int i = 0; i < n * n; add(a[i++], -1));
for (int i = 0; i < n * n; add(a[i++], 1)) {
cin >> a[i]; if (!a[i]) continue;
x -= ask(n * n - 1) - ask(a[i]);
}
for (int i = 0; i < n * n; add(a[i++], -1));
cout << (x & 1 ? "NIE\n" : "TAK\n");
}
return 0;
}
倍增
⭐天才ACM
书上复杂度, 我是没理解, 怎么算也是 \(nlog^2n\), 排序复杂度的上线是死的, 除非用桶排,计数才能降到 \(Nlogn\),
但是注意到倍增每次sort的是倍增的一端, sort排序的很少, 达不到上界\(nlog^2n\)
N是数据范围, 还不如sort...
int n, _, m, a[N], b[N], c[N];
ll t;
bool check(int l, int mid, int r) {
memcpy(b + mid + 1, a + mid + 1, (r - mid) * sizeof(int)); sort(b + mid + 1, b + r + 1);
ll ans = 0; int i = l, j = mid + 1, k = l;
while (i <= mid && j <= r) c[k++] = b[i] <= b[j] ? b[i++] : b[j++];
while (i <= mid) c[k++] = b[i++];
while (j <= r) c[k++] = b[j++];
for (int i = 0; i < m && 2 * i < r - l; ++i) ans += sqr((ll)c[r - i] - c[l + i]);
return ans <= t ? memcpy(b + l, c + l, (r - l + 1) * sizeof(int)), 1 : 0;
}
int main() {
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
for (cin >> _; _; --_) {
cin >> n >> m >> t;
for (int i = 1; i <= n; ++i) cin >> a[i], b[i] = a[i];
int l = 1, r = 1, cnt = 0, len = 1;
while (l <= n) {
while (len && r < n) {
if (check(l, r, min(r + len, n))) r += len, len <<= 1;
else if (r + len > n)len = 1;
else len >>= 1;
}
++cnt; l = ++r; len = 1;
}
cout << cnt << '\n';
}
return 0;
}
贪心
⭐防晒
贪心的题, 硬生生被我做成了最大匹配
按minSPF降序排列, 按顺序每头牛选能用的SPF最大的防晒霜
要以后某头牛i能用它前面牛j用的防晒霜, 那前面那头也找不到能用的了,
毕竟 minSPF[i] <= minSPF[j], minSPF[i] ~ useSPF[j] 之间没有防晒霜能用了
也就是 minSPF[j] ~ usePSF[j] 之间没有让 j 用的(除了它将要用的那瓶, 毕竟 useSPF[j] ~ maxSPF[j] 之间没有能用的, 不然 useSPF[j] 就选错了)
int main() {
cin >> n >> m;
for (int i = 0; i < n; ++i) cin >> a[i].fi >> a[i].se;
for (int i = 0; i < m; ++i) { int x, c; cin >> x >> c; b[x] += c; }
sort(a, a + n, greater<pair<int, int>>());
for (int i = 0; i < n; ++i)
for (int j = a[i].se; j >= a[i].fi; --j) if (b[j] > 0) {++ans, --b[j]; break; }
cout << ans;
return 0;
}
畜栏预定
int n, rk[50000];
pair<int, int> a[50000];
int main() {
cin >> n; for (int i = 0; i < n; ++i) cin >> a[i].se >> a[i].fi, rk[i] = i;
sort(rk, rk + n, [&](int x, int y) { return a[x].fi < a[y].fi; });
set<pair<int, int>> st; st.insert({ 0, 1 });
for (int i = 0; i < n; ++i)
if (st.begin()->fi >= a[rk[i]].se) st.insert({ a[rk[i]].fi, a[rk[i]].se = st.size() + 1 });
else {
auto it = st.lower_bound({ a[rk[i]].se, 0}); --it;
a[rk[i]].se = it->se; st.erase(it); st.insert(a[rk[i]]);
}
cout << st.size() << '\n';
for (int i = 0; i < n; ++i) cout << a[i].se << '\n';
return 0;
}
⭐雷达设备
很经典的题
int n, m, sq, ans;
pair<double, double> s[1005];
double cur = -1e10;
int main(){
cin >> n >> m; sq = m * m;
for (int i = 0; i < n; ++i) {
int a, b; cin >> a >> b;
if (b > m) return cout << -1, 0;
double d = sqrt(sq - b * b);
s[i] = { a + d, a - d };
}
sort(s, s + n);
for (int i = 0; i < n; ++i) if (cur < s[i].second) ++ans, cur = s[i].first;
return cout << ans, 0;
}
国王游戏
卡高精是真的恶心
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef pair<int, int> PII;
const int N = 1010;
int n;
PII p[N];
vector<int> mul(vector<int>a, int b){
vector<int> c; int t = 0;
for (int i = 0; i < a.size(); ++i) t += a[i] * b, c.push_back(t % 10), t /= 10;
while (t) c.push_back(t % 10), t /= 10;
return c;
}
vector<int> div(vector<int>a, int b) {
vector<int> c; bool is_first = true;
for (int i = a.size() - 1, t = 0; i >= 0; --i, t %= b){
t = t * 10 + a[i]; int x = t / b;
if (!is_first || x) is_first = false, c.push_back(x);
}
reverse(c.begin(), c.end());
return c;
}
vector<int> max_vec(vector<int> a, vector<int> b){
if (a.size() > b.size()) return a;
if (a.size() < b.size()) return b;
if (vector<int>(a.rbegin(), a.rend()) > vector<int>(b.rbegin(), b.rend())) return a;
return b;
}
int main(){
cin >> n;
for (int i = 0; i <= n; ++i){
int a, b; cin >> a >> b;
p[i] = {a * b, a};
}
sort(p + 1, p + n + 1);
vector<int> product(1, 1), res(1, 0);
for (int i = 0; i <= n; ++i){
if (i) res = max_vec(res, div(product, p[i].first / p[i].second));
product = mul(product, p[i].second);
}
for (int i = res.size() - 1; ~i; --i) cout << res[i];
return 0;
}
⭐给树染色
对于非根节点(a->b, c)
- 先染色a,b 再染色 c : a + 2b + 3c
- 先染色c 再染色 a,b : c + 2a + 3b
同时分别+(c-b),再除以2 则
- \(\frac{a+b}{2} + 2 * c\)
- \(c + 2 * \frac{a+b}{2}\)
进一步推广,如果有两组点:\(a1,a2,…an\) 和 \(b1,b2,…bm\),组内的点在染色时是相邻的一段。我们现在来考虑何时应该先染第一组点:
- 如果先染\(ai\),则分值是 \(S_{ab}=∑^n_{i=1}a_i∗i+∑^{n+m}_{i=n+1}b_{i-n}∗i\);
- 如果先染\(bi\),则分值是 \(S_{ba}=∑^m_{i=1}b_i∗i+∑^{n+m}_{i=m+1}a_{i-m}∗i\);
则\(S_{ab}−S_{ba}=n∗∑^m_{i=1}b_i−m∗∑^n_{i=1}a_i\),所以\(S_{ab}−S_{ba}<0⟺\frac{∑^n_{i=1}a_i}{n}<\frac{∑^m_{i=1}b_i}{m}\)。
所以我们在考虑剩余点的染色顺序时,可以将这两组点分别当成两个点,其权值分别是两组内所有点权值的平均值。
然后不断取当前点集的最大权值染色并合并父亲即可。
vector<int> z[1005];
struct di { int d, p, v; double ave; } tr[1005];
int find() {
int w; double ans = -1;
for (int i = 1; i <= n; ++i) if (tr[i].d > -1 && i != m)
if (tr[i].ave > ans) ans = tr[i].ave, w = i;
return w;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> tr[i].v, tr[i].d = 1, ans += tr[i].v, tr[i].ave = tr[i].v;
for (int i = 1, a, b; i < n; ++i) cin >> a >> b, tr[b].p = a, z[a].emplace_back(b);
for (int i = 1; i < n; ++i) {
int k = find(), p = tr[k].p;
ans += tr[p].d * tr[k].v;
for (int j = 0; j < z[k].size(); ++j) tr[z[k][j]].p = p, z[p].emplace_back(z[k][j]);
z[k].resize(0); tr[p].d += tr[k].d; tr[p].v += tr[k].v;
tr[p].ave = (double)tr[p].v / tr[p].d; tr[k].d = -1;
}
cout << ans;
return 0;
}
总结与练习
飞行员兄弟
int read() { char c = 'a'; while (c != '-' && c != '+') c = getchar(); return c == '-'; }
void move(int x, int y) { for (int i = x, j = y; i < 16; i += 4) b[i] ^= 1, b[j++] ^= 1; }
int main() {
for (int i = 0; i < 16; ++i) a[i] = read();
for (int i = 1; i < (1 << 16); ++i) {
int cnt = 0; memcpy(b, a, sizeof a);
for (int j = 0; j < 16; ++j) if (i >> j & 1) b[j] ^= 1, move(j % 4, j / 4 * 4), ++cnt;
for (int j = 0; j < 16; ++j) if (!b[j]) { cnt = 17; break; }
if (cnt < ans) ans = cnt, res = i;
}
printf("%d", ans);
for (int j = 0; j < 16; ++j) if (res >> j & 1) printf("\n%d %d", j / 4 + 1, j % 4 + 1);
return 0;
}
占卜DIY
inline int read() {
char c = getchar(); int x = 0;
while (!isdigit(c) && c != 'K' && c != 'J' && c != 'Q' && c != 'A') c = getchar();
switch (c) {
case 'K' : return 13;
case 'Q' : return 12;
case 'J' : return 11;
case 'A' : return 1;
case '0' : return 10;
default : return c ^ '0';
}
}
int main() {
for (int i = 1; i <= 13; ++i) for (int j = 1; j <= 4; ++j) a[i][j] = read();
for (; life; s == 0) {
while ((s == 13 || !s) && life) {
for (int i = 1; i <= 4; ++i) if (a[13][i]) { ++b[s = a[13][i]], a[13][i] = 0; break; }
if (s == 13) --life;
}
while (s != 13 && life) {
for (int i = 4, kk; i && s != 13 && life; --i) if (a[s][i]) {
kk = s; s = a[s][i]; a[kk][i] = 0; ++b[s]; break;
}
if (s == 13) --life;
}
}
for (int i = 1; i <= 12; ++i) if (b[i] == 4) ++ans;
return printf("%d", ans), 0;
}
分形
int n, inc[7] = {1}, s[730][730];
void work(int k, int x, int y) {
if (k == 1) { s[x][y] = 1; return; }
work(k - 1, x, y); work(k - 1, x, y + (inc[k - 2] << 1));
work(k - 1, x + inc[k - 2], y + inc[k - 2]);
work(k - 1, x + (inc[k - 2] << 1), y);
work(k - 1, x + (inc[k - 2] << 1), y + (inc[k - 2] << 1));
}
int main() {
for (int i = 1; i < 7; ++i) inc[i] = inc[i - 1] * 3;
work(7, 0, 0);
while (cin >> n, n > 0) {
for (int i = 0; i < inc[n - 1]; ++i, cout << '\n')
for (int j = 0; j < inc[n - 1]; ++j) cout << (s[i][j] ? 'X' : ' ');
cout << "-\n";
}
return 0;
}
⭐袭击(二维最近点对)
struct node {
double x, y; bool k;
double dist(const node& a) { return k == a.k ? 2e9 : sqrt(sqr(x - a.x) + sqr(y - a.y)); }
} a[200005], b[200005];
double work(int l, int r) {
if (r - l <= 1) return 2e9;
int mid = l + r >> 1, x = a[mid].x;
double cur = min(work(l, mid), work(mid, r));
int i = l, j = mid, k = l;
while (i < mid && j < r) b[k++] = a[i].y <= a[j].y ? a[i++] : a[j++];
while (i < mid) b[k++] = a[i++];
while (j < r) b[k++] = a[j++];
for (i = l, k = 0; i < r; a[i] = b[i], ++i)
if (a[i].x > x - cur && a[i].x < x + cur) b[k++] = a[i];
for (i = 0; i < k; ++i) for (j = i - 1; j >= 0 && b[i].y - b[j].y < cur; --j)
cur = min(cur, b[i].dist(b[j]));
return cur;
}
int main() {
for (cin >> _; _; --_) {
cin >> n;
for (int i = 0; i < n; ++i) cin >> a[i].x >> a[i].y, a[i].k = 1;
for (int i = 0; i < n; ++i) cin >> a[i + n].x >> a[i + n].y;
sort(a, a + (n << 1), [&](node& x, node& y) { return x.x < y.x; });
cout << setiosflags(ios::fixed) << setprecision(3) << work(0, n << 1) << '\n';
}
return 0;
}
防线
int check(int mid) {
int f = 0;
for (int i = 0; i < n; ++i) if (mid >= s[i])
f += (min(mid, e[i]) - s[i]) / d[i] + 1;
return f;
}
int main() {
for (scanf("%d", &_); _; --_) {
scanf("%d", &n);
for (int i = 0; i < n; ++i) scanf("%d%d%d", s + i, e + i, d + i);
long long l = 0, r = (long long)1 << 31;
while (l < r) {
long long mid = l + r >> 1;
if (check(mid) & 1) r = mid;
else l = mid + 1;
}
if (l < (long long)1 << 31) printf("%d %d\n", l, check(l) - check(l - 1));
else puts("There's no weakness.");
}
return 0;
}
赶牛入圈
想着下标从1开始加个最小值, 结果因为找到了这个最小值越界了...
int n, c, a[501][501];
pair<int, int> p[501];
vector<int> x(1, -1), y(1, -1);
int find(vector<int>& x, int a) { return lower_bound(all(x), a) - x.begin(); }
bool check(int mid) {
per(x2, x.size() - 1, 1)
per(y2, y.size() - 1, 1) {
int y1 = max(find(y, y[y2] - mid + 1), 1), x1 = max(1, find(x, x[x2] - mid + 1));
if (a[x2][y2] + a[x1 - 1][y1 - 1] - a[x1 - 1][y2] - a[x2][y1 - 1] >= c) return 1;
}
return 0;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> c >> n;
rep(i, 1, n) cin >> p[i].fi >> p[i].se, x.push_back(p[i].fi), y.push_back(p[i].se);
sort(all(x)); x.erase(unique(all(x)), x.end());
sort(all(y)); y.erase(unique(all(y)), y.end());
rep(i, 1, n) ++a[p[i].fi = find(x, p[i].fi)][p[i].se = find(y, p[i].se)];
rep(i, 1, x.size() - 1) rep(j, 1, y.size() - 1)
a[i][j] += a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];
int l = 1, r = 10000;
while (l < r) {
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
cout << r;
return 0;
}
糖果传递
int main() {
cin >> n; for (int i = 1; i <= n; ++i) cin >> s[i], a += s[i];
a /= n; for (int i = 1; i <= n; ++i) s[i] += s[i - 1] - a;
sort(s + 1, s + 1 + n); a = 0;
for (int i = 1; i <= n; ++i) a += abs(s[i] - s[n >> 1]);
cout << a;
return 0;
}
⭐士兵
均摊纸牌, 但是对于x轴, 是移动后相邻
对x排序, 假设最后最右边位置mx(\(mx >= max_x\)), 则\(x_i相对x_n少走i-1步\), 即x[i] -= i - 1
在对x排序做均摊纸牌
int main() {
cin >> n; for (int i = 0; i < n; ++i) cin >> x[i] >> y[i];
sort(x, x + n); sort(y, y + n);
for (int i = 0; i < n; ++i) x[i] -= i; sort(x, x + n);
for (int i = 0; i < n; ++i) ans += abs(y[i] - y[n >> 1]) + abs(x[i] - x[n >> 1]);
cout << ans;
return 0;
}
⭐数的进制转换
int _, n, m;
string s;
void work(int a, int b, string& s) {
int len = int(s.size()), k; vector<int> cur(len), ans;
per (i, len - 1, 0) cur[len - i - 1] = s[i] - (s[i] < 58 ? 48 : s[i] < 97 ? 55 : 61);
while(len) {
per (i, len - 2, 0) cur[i] += cur[i + 1] % b * a, cur[i + 1] /= b;
ans.push_back(cur[0] % b); cur[0] /= b;
while (len && !cur[len - 1]) --len;
}
string(ans.size(), ' ').swap(s);
rep (i, 0, ans.size() - 1)
s[ans.size() - 1 - i] = char(ans[i] + (ans[i] <= 9 ? 48 : ans[i] <= 35 ? 64 - 9 : 96 - 35));
}
int main() {
for (cin >> _; _; --_) {
cin >> n >> m >> s; cout << n << ' ' << s << '\n';
work(n, m, s); cout << m << ' ' << s << '\n' << '\n';
}
return 0;
}
耍杂技的牛
int main() {
cin >> n; for (int i = 0; i < n; ++i) cin >> a[i].fi >> a[i].se, a[i].fi += a[i].se;
sort(a, a + n); for (int i = 0; i < n; ++i) ans = max(ans, s - a[i].se), s += a[i].fi - a[i].se;
cout << ans;
return 0;
}
最大的和
int main() {
cin >> n;
rep (i, 1, n) rep (j, 1, n) cin >> h[i][j], ans = max(ans, h[i][j]), h[i][j] += h[i][j - 1];
rep (i, 0, n - 1) for (int j = i + 1, res = 0; j <= n; ++j, res = 0) rep (k, 1, n)
if (h[k][i] - h[k][j] >= res) res = 0;
else ans = max(ans, res += h[k][j] - h[k][i]);
return cout << ans, 0;
}
任务
multiset<int> st[101];
int main() {
cin >> n >> m;
for (int i = 0; i < n; ++i) cin >> a[0].fi >> a[0].se, st[a[0].se].insert(a[0].fi);
for (int i = 0; i < m; ++i) cin >> a[i].fi >> a[i].se; sort(a, a + m);
for (int i = m - 1; ~i; --i) {
for (int j = a[i].se; j < 101; ++j) {
auto it = st[j].lower_bound(a[i].fi);
if (it == st[j].end()) continue;
ans += a[i].fi * 500 + a[i].se * 2; ++cnt;
st[j].erase(it); break;
}
}
cout << cnt << ' ' << ans;
return 0;
}
基本数据结构
栈
包含min函数的栈
class MinStack {
public:
stack<int> st;
vector<int> mi;
void push(int x) {
st.push(x);
if (mi.empty()) mi.push_back(x);
else mi.push_back(min(x, mi.back()));
}
void pop() { st.pop(); mi.pop_back(); }
int top() { return st.top(); }
int getMin() { return mi.back(); }
};
编辑器
vector<pair<int, pair<int,int>>> st;
stack<int> qu;
void work(int a) {
int b = st.empty() ? 0 : a + st.back().se.se;
if (st.empty()) st.pb({a, {a, a}});
else st.pb({a, {max(st.back().se.fi, b), b}});
}
int main(){
for (cin >> _; _; --_) {
char c; cin >> c;
switch (c) {
case 'I' : cin >> n; work(n); break;
case 'D' : if (!st.empty()) st.pop_back(); break;
case 'L' : if (!st.empty()) qu.push(st.back().fi), st.pop_back(); break;
case 'R' : if (!qu.empty()) work(qu.top()), qu.pop(); break;
default : cin >> n; cout << st[n - 1].se.fi << '\n';
}
}
}
火车进栈
卡特兰数的高精
vector<long long> a(1, 1);
void getprime(int n, int k) {
for (int i = 2; i <= n / i; ++i)
while (n % i == 0) c[i] += k, n /= i;
c[n] += k;
}
void mul(int n) {
for (auto &i : a) i *= n;
for (int i = 0; i < a.size() - 1; ++i) a[i + 1] += a[i] / mod, a[i] %= mod;
if (a.back() >= mod) a.push_back(a.back() / mod), a[a.size() - 2] %= mod;
}
int main() {
cin >> n; getprime(2, 1);
for (int i = n + 2; i < n << 1; ++i) getprime(i, 1);
for (int i = 2; i < n; ++i) getprime(i, -1);
for (int i = 2; i < n << 1; ++i) for (int j = 0; j < c[i]; ++j) mul(i);
cout << a.back(); cout.fill('0');
for (int i = a.size() - 2; ~i; --i) cout << setw(9) << a[i];
return 0;
}
直方图中最大的矩形
int main() {
while (cin >> n, n) {
stack<pair<int, int>> st; st.push({ans = 0, h[n + 1] = 0});
for (int i = 1, w = 1; i <= n + 1; st.push({w, i++}), w = 1) {
if (i <= n) cin >> h[i];
for (auto p = st.top(); h[i] < h[p.second]; st.pop(), p = st.top()) {
ans = max(ans, 1ll * (p.first + i - p.second - 1) * h[p.second]);
w += p.first;
}
}
cout << ans << '\n';
}
return 0;
}
队列
小组队列
vector<queue<int>> q;
int t, n, a, f[1000010], cas;
char op[10];
int main() {
while (cin >> t, t) {
vector<queue<int>>(t + 1).swap(q); cout << "Scenario #" << ++cas << '\n';
for (int i = 0; i < t; ++i) for (cin >> n; n; --n) cin >> a, f[a] = i;
while (cin >> op, op[0] != 'S')
switch (op[0]) {
case 'E' : cin >> a; q[f[a]].push(a);
if (q[f[a]].size() == 1) q[t].push(f[a]); break;
case 'D' : a = q[t].front(); cout << q[a].front() << '\n'; q[a].pop();
if (q[a].empty()) q[t].pop(); break;
}
puts("");
}
}
蚯蚓
优先队列复杂度炸掉, 考虑贪心
对于两条相邻切割的蚯蚓长度为\(x_1, x_2(x_1 >= x_2)\)
切割完\(x_2\)后, 生成的四条蚯蚓的长度为
\(l_1 = \left \lfloor x_1 * p \right \rfloor + q, r_1 = x_1 - l_1 + q\)
\(l_2 = \left \lfloor (x_2 + q) * p \right \rfloor, r_2 = x_2 + q - l_2\)
因为 \(x_1 >= x_2, 0 < p < 1\) 故 \(l_1 > l_2\)
\(r_1 - r_2 = (x_1 - l_1) - (x_2 - l_2)\)
\(= \left \lceil x_1 - x_1 * p \right \rceil - \left \lceil x_2 - l_2 * p \right \rceil\)
\(= \left \lceil x_1 * (1 - p) \right \rceil - \left \lceil x_2 * (1 - p) \right \rceil >= 0 (x_1 >= x_2)\)
所以存在\(x_1 >= x_2\) 必存在 \(l_1 > l_2, r_1 >= r_2\)
所以分3个队列, 存x, l, r, 每次从3个队列取最大值, 切割分别放入l, r的队尾
queue<int> x, l, r;
int calc(int t) {
int d = -2e9, a = -2e9, b = -2e9, c = -2e9;
if (!x.empty()) d = max(d, a = x.front());
if (!l.empty()) d = max(d, b = l.front());
if (!r.empty()) d = max(d, c = r.front());
if (d == a) x.pop();
else if (d == b) l.pop();
else r.pop();
return d + t * q;
}
int main() {
cin >> n >> m >> q >> u >> v >> t;
for (int i = 0; i < n; ++i) cin >> a[i]; sort(a, a + n);
for (int i = n - 1; ~i; --i) x.push(a[i]);
for (int i = 1; i <= m; ++i) {
int x = calc(i - 1), y = x * (long long) u / v, c = i * q;
if (!(i % t)) cout << x << " ";
l.push(y - c); r.push(x - y - c);
}
cout << endl;
for (int i = 1; i <= n + m; ++i) {
int x = calc(m);
if (i % t == 0) cout << x <<" ";
}
}
⭐双端队列
int main() {
int n, m = 1; cin >> n; vector<int> a(n);
unordered_map<int, pair<int, int>> st;
for (int i = 0; i < n; ++i) {
cin >> a[i];
if (st.count(a[i])) st[a[i]].second = i;
else st[a[i]] = {i, i};
}
sort(a.begin(), a.end()); a.erase(unique(a.begin(), a.end()), a.end());
for (int i = 1, j = -st[a[0]].first; i < a.size(); ++i)
if (j < 0 && st[a[i]].second < -j) j = -st[a[i]].first;
else if (j < 0 || j < st[a[i]].first) j = st[a[i]].second;
else ++m, j = -st[a[i]].first;
cout << m;
return 0;
}
⭐最大子序和
int main() {
int n, m; cin >> n >> m; vector<long long> a(n + 1);
for (int i = 1; i <= n; ++i) cin >> a[i], a[i] += a[i - 1];
long long ans = -2e18; deque<pair<long long, int>> q; q.push_back({0, 0});
for (int i = 1; i <= n; ++i) {
while (q.front().second + m < i) q.pop_front();
ans = max(ans, a[i] - q.front().first);
while (!q.empty() && q.back().first >= a[i]) q.pop_back();
q.push_back({a[i], i});
}
cout << ans;
return 0;
}
链表与邻接表
临值查找
int main() {
int n, m; cin >> n >> m; set<pair<int, int>> st; st.insert({m, 1});
for (int i = 2; i <= n; st.insert({m, i++})) {
cin >> m; auto it = st.lower_bound({m, 0});
if (it == st.end()) --it, cout << abs(it->first - m) << ' ' << it->second << '\n';
else if (it == st.begin()) cout << abs(it->first - m) << ' ' << it->second << '\n';
else {
auto p = *it; --it;
if (abs(it->first - m) <= abs(p.first - m)) cout << abs(it->first - m) << ' ' << it->second << '\n';
else cout << abs(p.first - m) << ' ' << p.second << '\n';
}
}
return 0;
}
Hash
雪花雪花雪花
const int p[2] = { 131, 13331 };
int n, a[6], b[6];
bool f = 1;
set<pair<ull, ull>> st;
void findmx() {
memcpy(b, a, sizeof a);
int i = 0, j = 1, k = 0;
while (i < 6 && j < 6 && k < 6)
if (b[(i + k) % 6] == b[(j + k) % 6]) ++k;
else {
if (b[(i + k) % 6] < b[(j + k) % 6]) j += k + 1;
else i += k + 1;
if (i == j) ++j; k = 0;
}
j = min(i, j);
for (int i = 0; i < 6; ++i) a[i] = b[(i + j) % 6];
}
void work() {
if (!f) return; ull cur[2] = { 0, 0 };
for (int j = 0; j < 6; ++j) for (int j = 0; j < 2; ++j) cur[j] = cur[j] * p[j] + a[j];
f = !st.count({ cur[0], cur[1] }); st.insert({ cur[0], cur[1] });
}
int main() {
cin >> n;
for (int i = 0; f && i < n; ++i) {
for (int j = 0; j < 6; ++j) cin >> a[j];
findmx(); work(); reverse(a, a + 6);
findmx(); work();
}
cout << (f ? "No two snowflakes are alike." : "Twin snowflakes found.");
return 0;
}
兔子与兔子
ull a[2][N], b[2][N] = {{1}, {1}};
char s[N];
pair<ull, ull> find(int l, int r) {
return {a[0][r] - a[0][l] * b[0][r - l], a[1][r] - a[1][l] * b[1][r - l]};
}
int main() {
cin >> s + 1;
for (int i = 1; s[i]; ++i) for (int j = 0; j < 2; ++j)
a[j][i] = a[j][i - 1] * p[j] + s[i], b[j][i] = b[j][i - 1] * p[j];
for (cin >> _; _; --_) {
int x, y, a, b; cin >> x >> y >> a >> b;
cout << (find(x - 1, y) == find(a - 1, b) ? "Yes\n" : "No\n");
}
return 0;
}
回文子串的最大长度
struct PAM {
static const int N = 1e6 + 5, M = 26, C = 'a';
struct Node { int ne[M], len, fail, cnt; } tr[N];
int sz, tot, last, mx;
char s[N];
int newNode(int l) {
memset(tr[++sz].ne, 0, sizeof(tr[0].ne)); tr[sz].len = l;
return mx = max(mx, l), tr[sz].fail = tr[sz].cnt = 0, sz;
}
void init() {
sz = -1; last = mx = 0; s[tot = 0] = '$';
newNode(0); newNode(-1); tr[0].fail = 1;
}
int getfail(int x) {
while (s[tot - tr[x].len - 1] != s[tot]) x = tr[x].fail;
return x;
}
void insert(char c) {
s[++tot] = c; int now = getfail(last), ch = c - C;
if (!tr[now].ne[ch]) {
int x = newNode(tr[now].len + 2);
tr[x].fail = tr[getfail(tr[now].fail)].ne[ch];
tr[now].ne[ch] = x;
}
++tr[last = tr[now].ne[ch]].cnt;
}
void build(string& s) {
for (int i = 0; i < s.size(); ++i) insert(s[i]);
per (i, sz, 0) tr[tr[i].fail].cnt += tr[i].cnt;
}
} pam;
string s;
int main() {
int cas = 0;
while (cin >> s, s != "END") {
pam.init(); pam.build(s);
cout << "Case " << ++cas << ": " << pam.mx << '\n';
}
return 0;
}
后缀数组
struct SA {
static const int N = 300000 + 9;
char str[N]; //sa[i]表示排名i的后缀起始下标,rk[i]表示起始下标i后缀的排名
int sa[N], rk[N], tp[N], tax[N], lcp[N], len, M;
inline void sort() {
memset(tax, 0, (M + 1) * sizeof(int));
rep (i, 1, len) ++tax[rk[i]];
rep (i, 1, M) tax[i] += tax[i - 1];
per (i, len, 1) sa[tax[rk[tp[i]]]--] = tp[i];
}
void getH() {
for (int i = 1, j, k = 0; i <= len; lcp[rk[i++]] = k) {
if (k) --k; j = sa[rk[i] - 1];
while (str[i + k] == str[j + k]) ++k;
}
}
void SuffixSort() { //字符串下标从1开始
M = 200; len = 1;
for (int& i = len; str[i]; ++i) rk[i] = str[i], tp[i] = i;
--len; sort();
for (int w = 1, p = 0; p < len; w <<= 1, M = p) {
p = 0;
rep (i, 1, w) tp[++p] = len - w + i;
rep (i, 1, len) if (sa[i] > w) tp[++p] = sa[i] - w;
sort(); swap(tp, rk); rk[sa[1]] = p = 1;
rep (i, 2, len)
rk[sa[i]] = (tp[sa[i - 1]] == tp[sa[i]]
&& tp[sa[i - 1] + w] == tp[sa[i] + w]) ? p : ++p;
} getH();
}
} sa;
int main() {
cin >> sa.str + 1; sa.SuffixSort();
rep (i, 1, sa.len) cout << sa.sa[i] - 1 << ' '; cout << '\n';
rep (i, 1, sa.len) cout << sa.lcp[i] << ' ';
return 0;
}
字符串
周期
struct KMP {
static const int N = 1e6 + 5;
int f[N];
void kmp(char *t) {
for (int i = 2, j = 0; t[i]; ++i) {
while (j && t[i] != t[j + 1]) j = f[j];
f[i] = t[i] == t[j + 1] ? ++j : j;
}
}
} K;
char s[1000005];
int main() {
int cas = 0, n;
while (cin >> n, n) {
cin >> s + 1; K.kmp(s); cout << "Test case #" << ++cas << "\n";
for (int i = 1; s[i]; ++i) if (!(i % (i - K.f[i])) && K.f[i])
cout << i << ' ' << i / (i - K.f[i]) << '\n';
cout << '\n';
}
return 0;
}
Trie
前缀统计
struct AC {
static const int N = 1e6 + 5, M = 26, C = 'a'; //字符串总长度, 字符范围
int trie[N][M], cnt[N], tot;
void init() { rep (i, 0, M - 1) trie[0][i] = 0; tot = 0; }
int newnode() {
cnt[++tot] = 0; memset(trie[tot], 0, sizeof trie[tot]);
return tot;
}
void insert(char* s, int id) {
int p = 0;
for (int i = 0, ch = s[i] - C; s[i]; p = trie[p][ch], ch = s[++i] - C)
if (!trie[p][ch]) trie[p][ch] = newnode();
++cnt[p];
}
int query(char* s) {
int res = 0;
for (int i = 0, p = trie[0][s[i] - C]; p && s[i]; p = trie[p][s[++i] - C]) res += cnt[p];
return res;
}
} ac;
char s[1000005];
int main() {
int n, m; cin >> n >> m; ac.init();
while (n--) cin >> s, ac.insert(s, n);
while (m--) cin >> s, cout << ac.query(s) << '\n';;
return 0;
}
最大异或对
struct AC {
static const int N = 1e5 * 30 + 5, M = 2;
int tr[N][M], tot;
int insert(int x) {
int ans = 0, p = 0, q = 0;
for (int i = 30; ~i; --i) {
bool ch = x >> i & 1;
p = tr[p][ch] ? tr[p][ch] : tr[p][ch] = ++tot;
q = tr[q][!ch] ? ans ^= (1 << i), tr[q][!ch] : tr[q][ch];
}
return ans;
}
} ac;
int main() {
int n, m, ans = 0; cin >> n;
for (int i = 0; i < n; ++i) cin >> m, ans = max(ans, ac.insert(m));
cout << ans;
return 0;
}
⭐最长异或值路径
先考虑简单的线性问题, 找到一段xor和最大
设x[i] 表示 1~i 的异或和, 则答按就变成了 "最大异或对"
那树上怎么办呢, x[i] 表示从 root~i 的异或和, 找最大异或对即可
struct AC {
static const int N = 1e5 * 30 + 5, M = 2;
int tr[N][M], tot;
int insert(int x) {
int ans = 0, p = 0, q = 0;
for (int i = 30; ~i; --i) {
bool ch = x >> i & 1;
p = tr[p][ch] ? tr[p][ch] : tr[p][ch] = ++tot;
q = tr[q][!ch] ? ans ^= (1 << i), tr[q][!ch] : tr[q][ch];
}
return ans;
}
} ac;
vector<pair<int, int>> h[100001];
int a[100001];
void dfs(int x, int f) {
for (auto &y : h[x]) if (y.first != f) a[y.first] = a[x] ^ y.second, dfs(y.first, x);
}
int main() {
int n, ans = 0; cin >> n;
for (int i = 1; i < n; ++i) {
int u, v, c; cin >> u >> v >> c;
h[u].push_back({v, c}); h[v].push_back({u, c});
}
dfs(0, -1);
for (int i = 0; i < n; ++i) ans = max(ans, ac.insert(a[i]));
cout << ans;
return 0;
}
二叉堆
超市
void add(int x, int k) { for (; x <= n; x += -x & x) c[x] += k; }
int ask(int x) {
int ans = 0;
for (; x; x -= -x & x) ans += c[x];
return ans;
}
int main() {
while (cin >> n) {
memset(c, 0, sizeof c);
for (int i = 0; i < n; ++i) cin >> a[i].first >> a[i].second;
sort(a, a + n, greater<pair<int, int>>());
int ans = 0;
for (int i = 0; i < n; ++i) {
int cur = ask(a[i].second);
if (cur == a[i].second) continue;
int l = 1, r = a[i].second + 1;
while (l < r) {
int mid = l + r >> 1;
int res = ask(mid);
if (cur - res == a[i].second - mid) r = mid;
else l = mid + 1;
}
ans += a[i].first; add(l, 1);
}
cout << ans << '\n';
}
return 0;
}
⭐序列
void work() {
priority_queue<pair<int, int>> qu;
for (int i = 0; i < n; i++) qu.push(make_pair(-a[0] - b[i],0));
for (int i = 0; i < n; i++) {
auto p = qu.top(); qu.pop(); c[i] = -p.first;
qu.push({ p.first - a[p.second + 1] + a[p.second], p.second + 1 });
}
memcpy(a, c, sizeof(int) * n);
}
int main() {
for (cin >> _; _; --_) {
cin >> m >> n;
for (int i = 0; i < n; i++) cin >> a[i]; sort(a, a + n);
for (int i = 1; i < m; i++, work())
for (int j = 0; j < n; j++) cin >> b[j], sort(b, b + n);
for (int i = 0; i < n; i++) cout << a[i] << ' '; cout << '\n';
}
return 0;
}
数据备份
int main() {
cin >> n >> k >> a[1]; priority_queue<pair<int, int>> q;
for (int i = 2; i <= n; ++i) cin >> a[i], a[i - 1] = a[i] - a[i-1];
a[0] = a[n] = 2e18;
for (int i = 1; i < n; ++i) q.push({-a[i], i}), pre[i] = i - 1, nxt[i] = i + 1;
while (k--) {
int x = q.top().second; q.pop();
while (del[x]) x = q.top().second, q.pop();
ans += a[x]; del[pre[x]] = del[nxt[x]] = 1;
a[x] = a[pre[x]] + a[nxt[x]] - a[x];
pre[x] = pre[pre[x]]; nxt[x] = nxt[nxt[x]];
nxt[pre[x]] = pre[nxt[x]] = x; q.push({-a[x], x});
}
cout << ans;
}
合并果子
int main() {
int n, m, sum = 0; cin >> n; priority_queue<int> q;
for (int i = 0; i < n; i++) cin >> m, q.push(-m);
for (int i = 1; i < n; i++) {
int x = q.top(); q.pop(); x += q.top(); q.pop();
q.push(x); sum += x;
}
cout << -sum;
return 0;
}
⭐荷马史诗
和合并果子一样, 都是k叉最小权值哈夫曼树
int main() {
long long n, k, a, ans = 0; cin >> n >> k; priority_queue<pair<long long, int>> q;
for (int i = 1; i <= n; ++i) cin >> a, q.push({-a, 0});
for (int i = (k - 1 - (n - 1) % (k - 1)) % (k - 1); i; --i) q.push({0, 0});
for (long long dep = 0, t = 0; q.size() > 1; dep = t = 0) {
for (int i = 1; i <= k; ++i) {
auto p = q.top(); q.pop();
t += p.first; dep = min(dep, (long long)p.second);
}
q.push({t, dep - 1}); ans += t;
}
return cout << -ans << '\n' << -q.top().second << '\n', 0;
}
总结与练习
括号画家
int main() {
int ans = 0; string s; cin >> s;
stack<int> st;
for (int i = 0; i < s.size(); ++i) {
if (!st.empty() && s[i] == ')' && s[st.top()] == ')') st.pop();
else if (!st.empty() && s[i] == ']' && s[st.top()] == ']') st.pop();
else if (!st.empty() && s[i] == '}' && s[st.top()] == '}') st.pop();
else st.push(i);
ans = max(ans, i - st.top());
}
cout << ans;
return 0;
}
⭐表达式计算
stack<int> nums;
stack<char> ops;
void cal() {
int a = nums.top(); nums.pop();
int b = nums.top(); nums.pop();
char c = ops.top(); ops.pop();
switch (c) {
case '+' : nums.push(b + a); break;
case '-' : nums.push(b - a); break;
case '*' : nums.push(b * a); break;
case '/' : nums.push(b / a); break;
default : nums.push(pow(b, a));
}
}
void read(int &i, string& s) {
int t = 0;
for (; isdigit(s[i]); ++i) t = t * 10 + s[i] - '0';
nums.push(t); --i;
}
int main() {
string s; cin >> s;
if (s[0] == '-') s = '0' + s; s = '(' + s + ')';
for (int i = 0; i < s.size(); ++i)
if (isdigit(s[i])) read(i, s);
else
switch (s[i]) {
case '(' : ops.push('('); break;
case '+' : case '-' : {
if (s[i] == '-' && s[i - 1] == '(') {
if (s[i + 1] == '(') nums.push(-1), ops.push('*');
else read(++i, s), nums.top() = -nums.top();
} else {
while (ops.top() != '(') cal();
ops.push(s[i]);
}
} break;
case '*' : case '/' :
while (ops.top() == '*' || ops.top() == '/' || ops.top() == '^') cal();
ops.push(s[i]); break;
case '^' : while (ops.top() == '^') cal(); ops.push(s[i]); break;
case ')' : while (!ops.empty() && ops.top() != '(') cal();
if (!ops.empty()) ops.pop(); break;
default : cout << "invalid operator!\n";
}
cout << nums.top() << endl;
return 0;
}
⭐城市游戏
int main() {
cin >> n >> m;
for (int i = 1; i <= m; ++i) r[0][i] = m + 1;
for (int i = 1, ml = 0, mr = m + 1; i <= n; ++i, ml = 0, mr = m + 1) {
for (int j = 1; j <= m; ++j) {
char c; cin >> c; a[i][j] = c == 'R';
if (a[i][j]) ml = j, l[i][j] = h[i][j] = 0;
else l[i][j] = max(l[i - 1][j], ml), h[i][j] = h[i - 1][j] + 1;
}
for (int j = m; j; --j)
if (a[i][j]) mr = j, r[i][j] = m + 1;
else r[i][j] = min(r[i - 1][j], mr), ans = max(ans, h[i][j] * (r[i][j] - l[i][j] - 1));
}
cout << ans * 3;
return 0;
}
双栈排序
int a[1005], f[1005];
bool v[1005];
int main() {
string s; int n, k = 1; cin >> n; stack<int> x, y; x.push(1e9); y.push(1e9);
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = n, j = a[i] - 1; i; v[a[i]] = 1, j = a[--i] - 1) {
if (!v[j]) f[j + 1] = 0;
else {
bool g = 0; f[j + 1] = f[j];
for (int k = i + 1; a[k] != j; ++k) f[j + 1] = max(f[j + 1], max(f[a[k]], a[k]));
}
}
for (int i = 1, c = a[1]; i <= n; c = a[++i]) {
while (x.top() == k) ++k, s += 'b', x.pop();
if (x.top() > c && f[c] < y.top()) s += 'a', x.push(c);
else {
while (y.top() == k) s += 'd', ++k, y.pop();
if (y.top() > c) s += 'c', y.push(c);
else { s = ""; break; }
}
}
if (s.empty()) return cout << 0, 0;
while (x.top() == k || y.top() == k)
if (x.top() == k) ++k, s += 'b', x.pop();
else ++k, s += 'd', y.pop();
for (auto c : s) cout << c << ' ';
return 0;
}
滑动窗口
int main() {
int n, k; cin >> n >> k; vector<int> a, b, c(n); multiset<int> st;
for (int i = 0; i < k; ++i) cin >> c[i], st.insert(c[i]);
a.push_back(*st.begin()); b.push_back(*st.rbegin());
for (int i = k; i < n; ++i) {
cin >> c[i]; st.erase(st.find(c[i - k])); st.insert(c[i]);
a.push_back(*st.begin()); b.push_back(*st.rbegin());
}
for (auto i : a) cout << i << ' '; cout << '\n';
for (auto i : b) cout << i << ' ';
return 0;
}
⭐内存分配
vector<PII> ve; queue<PII> qu;
priority_queue<PII, vector<PII>, greater<PII>> q;
int n, t, m, p, ans, cnt;
bool add(int t, int m, int p) {
for (auto jt = ve.begin(), it = jt++; jt != ve.end(); ++jt, ++it)
if (m <= jt->first - it->first - it->second) {
int start = it->first + it->second;
return ve.insert(jt, { start, m }), q.push({ t + p, start }), 1;
}
return 0;
}
void work(int t) {
while (!q.empty() && q.top().first <= t) {
ans = q.top().first;
while (!q.empty() && q.top().first == ans) {
auto p = q.top(); q.pop();
ve.erase(lower_bound(ve.begin(), ve.end(), PII{p.second, 0}));
}
while (!qu.empty() && add(ans, qu.front().first, qu.front().second)) qu.pop();
}
}
int main() {
cin >> n; ve.push_back({ -1, 1 }), ve.push_back({ n, 1 });
while (cin >> t >> m >> p, t || m || p) {
work(t);
if (!add(t, m, p)) qu.push({ m, p }), ++cnt;
}
return work(2e9), cout << ans << '\n' <<cnt, 0;
}
矩阵
void init() {
cin >> n >> m >> a >> b;
for (int i = 1; i <= a * b; ++i) pi[i] = pi[i - 1] * p;
for (int i = 1; i <= n; ++i) {
cin >> s + 1;
for (int j = 1; j <= m; ++j) sumh[i][j] = sumh[i][j - 1] * p + s[j];
}
for (int j = b; j <= m; ++j) {
unsigned long long cur = 0;
for (int i = 1; i < a; ++i) cur = (cur - sumh[i][j - b]) * pi[b] + sumh[i][j];
for (int i = a; i <= n; ++i) {
cur = (cur - sumh[i][j - b]) * pi[b] - (sumh[i - a][j] -
sumh[i - a][j - b] * pi[b]) * pi[a * b] + sumh[i][j];
st.insert(cur);
}
}
}
int main() {
init();
for (cin >> _; _; --_) {
unsigned long long cur = 0;
for (int i = 1; i <= a; ++i) {
cin >> s + 1;
for (int j = 1; j <= b; ++j) cur = cur * p + s[j];
}
cout << ("01"[st.count(cur)]) << '\n';
}
return 0;
}
树形地铁系统
string dfs(string &seq, int &u) {
vector<string> seqs; string res;
while (seq[u] == '0') seqs.push_back(dfs(seq, ++u));
sort(seqs.begin(), seqs.end());
for (auto &s : seqs) res += s;
return ++u, '0' + res + '1';
}
int main() {
for (cin >> _; _; --_) {
string a, b; cin >> a >> b; x = y = 1;
a = '0' + a + '1'; b = '0' + b + '1';
if (dfs(a, x) == dfs(b, y)) puts("same");
else puts("different");
}
return 0;
}
项链
int getmin(char s[], int len) {
int i = 0, j = 1, k = 0;
while (i < len && j < len && k < len)
if (s[(i + k) % len] == s[(j + k) % len]) ++k;
else {
if (s[(i + k) % len] < s[(j + k) % len]) j += k + 1;
else i += k + 1;
if (i == j) ++j; k = 0;
}
return min(i, j);
}
int main() {
cin >> s >> t;
int len = strlen(s), a = getmin(s, len), b = getmin(t, len);
for (int i = 0; i < len; ++i)
if (s[(a + i) % len] != t[(b + i) % len]) { puts("No"); return; }
puts("Yes");
for (int i = 0; i < len; ++i) putchar(s[(a + i) % len]);
return 0;
}
奶牛矩阵
void kmp() {
f[1] = 0;
for (int i = 2, j = 0; i <= n; f[i++] = j) {
while (j && strcmp(s[i], s[j + 1])) j = f[j];
if (!strcmp(s[i], s[j + 1])) ++j;
}
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
cin >> s[i];
for (int j = 1; j <= m; ++j) if (!wid[j])
for (int k = j; k < m; ++k)
if (s[i][k] != s[i][k % j]) { wid[j] = 1; break; }
}
for (int i = 1; i <= m; ++i) if (!wid[i]) {
for (int j = 1; j <= n; ++j) s[j][i] = '\000';
kmp(); cout << i * (n - f[n]); break;
}
return 0;
}
匹配统计
int lens, lent, f[N], extend[N], sum[N], n, m, q;
char s[N], t[N];
void kmp(char* t, int lent) { //t从1开始
int j = 0, k = 2;
while (j + 2 <= lent && t[j + 1] == t[j + 2]) ++j;
f[2] = j; f[1] = lent;
for (int i = 3, p = k + f[k] - 1; i <= lent; ++i, p = k + f[k] - 1)
if (i + f[i - k + 1] - 1 < p) f[i] = f[i - k + 1];
else {
j = max(0, p - i + 1);
while (j + i <= lent && t[j + 1] == t[i + j]) ++j;
f[i] = j; k = i;
}
}
void ex_kmp(char *s, char *t, int lens, int lent) { //s, t下标都是从1开始
int j = 0, k = 1;
while (j + 1 <= min(lens, lent) && s[j + 1] == t[j + 1]) ++j;
extend[1] = j;
for (int i = 2, p = k + extend[k] - 1; i <= lens; ++i, p = k + extend[k] - 1)
if (i + f[i - k + 1] - 1 < p) extend[i] = f[i - k + 1];
else {
j = max(0, p - i + 1);
while (j + i <= lens && j + 1 <= lent && t[j + 1] == s[i + j]) ++j;
extend[i] = j; k = i;
}
}
int main() {
cin >> n >> m >> q >> s + 1 >> t + 1;
lent = strlen(t + 1); lens = strlen(s + 1);
kmp(t, lent); ex_kmp(s, t, lens, lent);
for (int i = 1; i <= lens; ++i) ++sum[extend[i]];
while (q--) {
int x; cin >> x;
cout << sum[x] << '\n';
}
return 0;
}
电话列表
bool insert(string& s) {
int p = 0; bool g = 0;
for (int i = 0; i < s.size(); ++i) {
int ch = s[i] - '0';
p = !tr[p][ch] ? tr[p][ch] = ++tot : tr[p][ch];
if (f[p]) g = 1;
}
++f[p];
return g;
}
int main() {
for (cin >> _; _; --_, tot = 0) {
cin >> n; memset(tr, 0, sizeof tr); memset(f, 0, sizeof f);
bool res = 1;
for (int i = 0; i < n; i ++ ) cin >> s[i];
sort(s, s + n, [](string& a, string& b){return a.size() < b.size();});
for (int i = 0; i < n; ++i) if (insert(s[i])) { res = 0; break; }
puts(res ? "YES" : "NO");
}
return 0;
}
黑盒子
int main() {
cin >> n >> m; priority_queue<int> q, qu;
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 1, j = 1; i <= m; ++i) {
for (cin >> b; j <= b;) {
qu.push(-a[j++]);
if (!q.empty() && q.top() > -qu.top()) {
qu.push(-q.top()); q.pop();
q.push(-qu.top()); qu.pop();
}
}
cout << -qu.top() << '\n'; q.push(-qu.top()); qu.pop();
}
return 0;
}
⭐生日礼物
选取k个不相邻的连续线段使和最小(元素大于等于0), 可以用双向链表加小根堆处理
现将所有元素插入小根堆中
ans+=堆顶,删除堆顶,插入堆顶元素左右两个元素的和减去堆顶元素,删除左右两个元素
本题可转化为类似的问题
将连续的正数和负数合并,因为连续的正数和负数一定一起选,0删去
先将所有正数都选上,和记为res, 有cnt个正数
如果正数段数小于M直接输出
要想减少段数有两种方式:
1.删除一段正数
2.将多段正数和连接他们的负数一起选上
第一种选法直接将res-=这个值
第二种则相当于减去其中负数段的绝对值(画图考虑);
进而将连续的负数记为绝对值
进而变成了选(减去)cnt-k连续段和最小, res减去这个值
void remove(int x) { l[r[x]] = l[x]; r[l[x]] = r[x]; vis[x] = 1; }
int main() {
cin >> n >> m >> a[++tot]; priority_queue<pair<int, int>> qu;
for (int i = 2; i <= n; ++i) {
cin >> a[i]; if(!a[i])continue;
if (a[i] * a[tot] > 0) a[tot] += a[i];
else {
if (a[tot] > 0) ans += a[tot], qu.push({-a[tot], tot}), ++cur;
else qu.push({a[tot], tot});
a[++tot] = a[i];
}
}
if (a[tot] > 0) ans += a[tot], qu.push({-a[tot], tot}), ++cur;
else qu.push({a[tot], tot});
if (cur > m) {
for (int i = 1; i <= tot; ++i) l[i] = i - 1, r[i] = i + 1;
while (cur - m) {
auto p = qu.top(); qu.pop();
if (vis[p.second]) continue;
if(a[p.second] < 0 && (l[p.second] == 0 || r[p.second] == tot + 1)) continue;
ans += p.first; --cur; vis[l[p.second]] = vis[r[p.second]] = 1;
a[p.second] += a[l[p.second]] + a[r[p.second]];
qu.push({-abs(a[p.second]), p.second}); remove(r[p.second]), remove(l[p.second]);
}
}
return cout << ans, 0;
}
搜索
树与图的遍历
可达性统计
vector<int> h[30001];
bitset<30001> a[30001];
int main() {
cin >> n >> m; queue<int> q;
for (int i = 0; i < m; ++i, ++deg[x]) cin >> x >> y, a[x][y] = 1, h[y].push_back(x);
for (int i = 1; i <= n; ++i) if (!deg[i]) q.push(i);
while (!q.empty()) {
int x = q.front(); q.pop();
for (auto y : h[x]) {
a[y] |= a[x], --deg[y];
if (!deg[y]) q.push(y);
}
}
for (int i = 1; i <= n; ++i) cout << a[i].count() + 1 << '\n';
return 0;
}
深度优先搜索
小猫爬山
void dfs(int now, int cnt) {
if (cnt >= ans) return;
if (now == n + 1) { ans = min(ans, cnt); return; }
for (int i = 1; i <= cnt; ++i) if (car[i] + a[now] <= w)
car[i] += a[now], dfs(now + 1, cnt), car[i] -= a[now];
car[cnt + 1] = a[now]; dfs(now + 1, cnt + 1); car[cnt + 1] = 0;
}
int main() {
cin >> n >> w; ans = n;
for (int i = 1; i <= n; ++i) cin >> a[i];
dfs(1, 0); cout << ans;
return 0;
}
数独
struct DLX {
static const int N = 1e5 + 5;
#define IT(i, A, x) for(int i=A[x];i^x;i=A[i])
int n, m, tot, first[N], siz[N], stk[N], ans;
int L[N], R[N], U[N], D[N], col[N], row[N];
void build(const int &r, const int &c) {
for (int i = 0; i <= c; ++i) L[i] = i - 1, R[i] = i + 1, U[i] = D[i] = i;
n = r, m = c; L[0] = c, R[c] = 0, tot = c;
memset(first, 0, sizeof(first)); memset(siz, 0, sizeof(siz));
}
void insert(const int &r, const int &c) {
col[++tot] = c, row[tot] = r, ++siz[c];
D[tot] = D[c], U[D[c]] = tot, U[tot] = c, D[c] = tot;
if (!first[r]) first[r] = L[tot] = R[tot] = tot;
else {
R[tot] = R[first[r]], L[R[first[r]]] = tot;
L[tot] = first[r], R[first[r]] = tot;
}
}
void remove(const int &c) {
L[R[c]] = L[c], R[L[c]] = R[c];
IT(i, D, c) IT(j, R, i) U[D[j]] = U[j], D[U[j]] = D[j], --siz[col[j]];
}
void recover(const int &c) {
IT(i, U, c) IT(j, L, i) U[D[j]] = D[U[j]] = j, ++siz[col[j]];
L[R[c]] = R[L[c]] = c;
}
bool dance(int dep) {
if (!R[0]) return ans = dep, 1;
int c = R[0];
IT(i, R, 0) if (siz[i] < siz[c]) c = i;
remove(c);
IT(i, D, c) {
stk[dep] = row[i];
IT(j, R, i) remove(col[j]);
if (dance(dep + 1)) return 1;
IT(j, L, i) recover(col[j]);
}
recover(c);
return 0;
}
#undef IT
} dlx;
int a[10][10];
void insert(int r, int c, int n) {
int g = (r - 1) / 3 * 3 + (c - 1) / 3 + 1;
int id = (r - 1) * 81 + (c - 1) * 9 + n;
dlx.insert(id, (r - 1) * 9 + n);
dlx.insert(id, 81 + (c - 1) * 9 + n);
dlx.insert(id, 162 + (g - 1) * 9 + n);
dlx.insert(id, 243 + (r - 1) * 9 + c);
}
int main() {
string s;
while (cin >> s, s != "end") {
dlx.build(729, 324);
for (int i = 1; i <= 9; ++i) for (int j = 1; j <= 9; ++j) {
a[i][j] = s[(i - 1) * 9 + j - 1] == '.' ? 0 : s[(i - 1) * 9 + j - 1] ^ '0';
for (int v = 1; v <= 9; ++v) if (!a[i][j] || a[i][j] == v) insert(i, j, v);
}
dlx.dance(1);
for (int i = 1; i < dlx.ans; ++i)
a[(dlx.stk[i] - 1) / 81 + 1][(dlx.stk[i] - 1) / 9 % 9 + 1] = (dlx.stk[i] - 1) % 9 + 1;
for (int i = 1; i <= 9; ++i) for (int j = 1; j <= 9; ++j) cout << a[i][j]; cout << '\n';
}
return 0;
}
剪枝
木棒
bool dfs(int len, int tot, int cur) {
if (tot == n) return 1;
if (cur == 0) cur = len;
for (int i = cur; i; --i) if (a[i]) {
--a[i]; if (dfs(len, tot + 1, cur - i)) return 1; ++a[i];
if (cur == len || cur - i == 0) return 0;
}
return 0;
}
int main() {
while (cin >> n, n) {
int s = 0, t; memset(a, 0, sizeof(a));
for (int i = 0; i < n; ++i) { cin >> t; if (t <= 50) ++a[t], s += t; }
for (int i = 1; i <= s >> 1 && !a[0]; ++i) if (!(s % i) && dfs(i, 0, i)) a[0] = i;
cout << (a[0] ? a[0] : s) << '\n';
}
return 0;
}
⭐生日蛋糕
void dfs(int dep) {
if (!dep) { if (v == n) ans = min(ans, s); return; }
for (r[dep] = min((int)sqrt(n - v), r[dep + 1] - 1); r[dep] >= dep; --r[dep])
for(h[dep] = min((int)((double)(n - v) / r[dep] / r[dep]), h[dep + 1] - 1); h[dep] >= dep; --h[dep]) {
if (v + minv[dep] > n || s + mins[dep] > ans) continue;
if (2 * (n - v) / r[dep] + s > ans) continue;
if (dep == m) s += r[dep] * r[dep];
s += 2 * r[dep] * h[dep];
v += r[dep] * r[dep] * h[dep];
dfs(dep - 1);
if (dep == m) s -= r[dep] * r[dep];
s -= 2 * r[dep] * h[dep];
v -= r[dep] * r[dep] * h[dep];
}
}
int main() {
cin >> n >> m;
for(int i = 1; i <= m; ++i) minv[i] = minv[i - 1] + i * i * i, mins[i] = mins[i - 1] + i * i;
h[m + 1] = r[m + 1] = inf; dfs(m); cout << (ans == inf ? 0 : ans);
return 0;
}
数独2
struct DLX {
static const int N = 2e6 + 5;
#define IT(i, A, x) for(int i=A[x];i^x;i=A[i])
int n, m, tot, first[N], siz[N], stk[N], ans;
int L[N], R[N], U[N], D[N], col[N], row[N];
void build(const int& r, const int& c) {
for (int i = 0; i <= c; ++i) L[i] = i - 1, R[i] = i + 1, U[i] = D[i] = i;
n = r, m = c; L[0] = c, R[c] = 0, tot = c;
memset(first, 0, sizeof(first)); memset(siz, 0, sizeof(siz));
}
void insert(const int& r, const int& c) {
col[++tot] = c, row[tot] = r, ++siz[c];
D[tot] = D[c], U[D[c]] = tot, U[tot] = c, D[c] = tot;
if (!first[r]) first[r] = L[tot] = R[tot] = tot;
else {
R[tot] = R[first[r]], L[R[first[r]]] = tot;
L[tot] = first[r], R[first[r]] = tot;
}
}
void remove(const int& c) {
L[R[c]] = L[c], R[L[c]] = R[c];
IT(i, D, c) IT(j, R, i) U[D[j]] = U[j], D[U[j]] = D[j], --siz[col[j]];
}
void recover(const int& c) {
IT(i, U, c) IT(j, L, i) U[D[j]] = D[U[j]] = j, ++siz[col[j]];
L[R[c]] = R[L[c]] = c;
}
bool dance(int dep) {
if (!R[0]) return ans = dep, 1;
int c = R[0];
IT(i, R, 0) if (siz[i] < siz[c]) c = i;
remove(c);
IT(i, D, c) {
stk[dep] = row[i];
IT(j, R, i) remove(col[j]);
if (dance(dep + 1)) return 1;
IT(j, L, i) recover(col[j]);
}
recover(c);
return 0;
}
#undef IT
} dlx;
int a[17][20];
char c[17][20];
void insert(int r, int c, int n) {
int g = (r - 1) / 4 * 4 + (c - 1) / 4 + 1;
int id = (r - 1) * 16 * 16 + (c - 1) * 16 + n;
dlx.insert(id, (r - 1) * 16 + n);
dlx.insert(id, 16 * 16 + (c - 1) * 16 + n);
dlx.insert(id, 16 * 16 * 2 + (g - 1) * 16 + n);
dlx.insert(id, 16 * 16 * 3 + (r - 1) * 16 + c);
}
int main() {
while (scanf("%s", c[1] + 1) != EOF) {
for (int i = 2; i <= 16; ++i) scanf("%s", c[i] + 1);
dlx.build(16 * 16 * 16, 16 * 16 * 4);
for (int i = 1; i <= 16; ++i) for (int j = 1; j <= 16; ++j) {
a[i][j] = c[i][j] == '-' ? 0 : c[i][j] - 'A' + 1;
for (int v = 1; v <= 16; ++v) if (!a[i][j] || a[i][j] == v) insert(i, j, v);
}
dlx.dance(1);
for (int i = 1; i < dlx.ans; ++i)
c[(dlx.stk[i] - 1) / 16 / 16 + 1][(dlx.stk[i] - 1) / 16 % 16 + 1] = (dlx.stk[i] - 1) % 16 + 'A';
for (int i = 1; i <= 16; ++i) printf("%s\n", c[i] + 1); puts("");
}
return 0;
}
迭代加深
加成序列
bool dfs(int u, int k) {
if (u == k + 1) return a[u - 1] == n;
bool v[101] = {0};
for (int i = u - 1; i; --i)
for (int j = i; j; --j) {
int s = a[i] + a[j];
if (s > n || s <= a[u - 1] || v[s]) continue;
v[s] = 1; a[u] = s;
if (dfs(u + 1, k)) return true;
}
return false;
}
int main() {
while (cin >> n, n) {
int k = 1;
while (!dfs(2, k)) ++k;
for (int i = 1; i <= k; ++i) cout << a[i] << ' '; cout << '\n';
}
return 0;
}
⭐送礼物
要先排序a, 再双向搜
void dfs(int k, int *a, bool f, int c) {
if (k == n + f >> 1) {
if (f) { v.push_back(c); return; }
auto it = upper_bound(v.begin(), v.end(), m - c);
if (it == v.begin()) ans = max(ans, c);
else ans = max(ans, c + *(--it));
return;
}
dfs(k + 1, a, f, c);
if (0ll + c + a[k] <= m) dfs(k + 1, a, f, c + a[k]);
}
int main() {
cin >> m >> n; for (int i = 0; i < n; ++i) cin >> a[i]; sort(a, a + n);
dfs(0, a + (n >> 1), 1, 0); sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end()); dfs(0, a, 0, 0);
cout << ans;
return 0;
}
广度优先搜索
立体推箱子
struct node { int x, y, a, b, cnt;} s, der, cur;
int mp[505][505], vis[505][505], tot, n, m, flag;
inline int read(int i, int j) {
char c = getchar();
while (c != '#' && c != '.' && c != 'E' && c != 'X' && c != 'O') c = getchar();
switch (c) {
case '#' : return -1;
case '.' : return 1;
case 'E' : return 0;
case 'X' : if (!s.x) s.x = i, s.y = j; else s.a = i, s.b = j; return 11;
case 'O' : if (!der.x) der.x = i, der.y = j; else der.a = i, der.b = j; return 21;
}
}
inline bool check(const node& t) {
if (t.x <1 || t.x > n || t.y < 1 || t.y > m || mp[t.x][t.y] == -1) return 0;
if (t.a == -1)
if (mp[t.x][t.y] == 0 || vis[t.x][t.y] & 1) return 0;
else return vis[t.x][t.y] |= 1;
if (t.a <1 || t.a > n || t.b < 1 || t.b > m || mp[t.a][t.b] == -1) return 0;
if (t.a == t.x)
if (vis[t.x][t.y] & (1 << 1)) return 0;
else return vis[t.x][t.y] |= (1 << 1), 1;
else
if (vis[t.x][t.y] & (1 << 2)) return 0;
else return vis[t.x][t.y] |= (1 << 2), 1;
}
inline bool checked(node& t, queue<node>& qu) {
if (!check(t)) return 0; qu.push(t);
if (t.a != der.a || t.x != der.x || t.y != der.y) return 0;
printf("%d\n", cur.cnt); return flag = 1;
}
int main() {
while (scanf("%d%d", &n, &m), n && m) {
s.a = der.a = -1, s.x = der.x = flag = s.cnt = 0;
memset(vis, 0, sizeof vis);
for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) mp[i][j] = read(i, j);
vis[s.x][s.y] |= s.a == -1 ? 1 : s.a == s.x ? 1 << 1 : 1 << 2;
queue<node> qu; qu.push(s);
while (!qu.empty()) {
s = qu.front(); qu.pop(); cur.cnt = s.cnt + 1;
if (s.a == -1) {
cur.x = s.x - 2, cur.a = s.x - 1, cur.b = cur.y = s.y;
if (checked(cur, qu)) break;
cur.x = cur.a = s.x, cur.y = s.y - 2, cur.b = s.y - 1;
if (checked(cur, qu)) break;
cur.x = cur.a = s.x, cur.y = s.y + 1, cur.b = s.y + 2;
if (checked(cur, qu)) break;
cur.x = s.x + 1, cur.a = s.x + 2, cur.y = cur.b = s.y;
if (checked(cur, qu)) break;
} else
if (s.a == s.x) {
cur.x = cur.a = s.a - 1, cur.b = s.b, cur.y = s.y;
if (checked(cur, qu)) break;
cur.x = cur.a = s.a + 1;
if (checked(cur, qu)) break;
cur.a = -1, cur.x = s.x, cur.y = s.y - 1;
if (checked(cur, qu)) break;
cur.y = s.y + 2;
if (checked(cur, qu)) break;
} else {
cur.a = -1, cur.x = s.x - 1, cur.y = s.y;
if (checked(cur, qu)) break;
cur.x = s.x + 2;
if (checked(cur, qu)) break;
cur.x = s.x, cur.a = s.a, cur.y = cur.b = s.y - 1;
if (checked(cur, qu)) break;
cur.y = cur.b = s.y + 1;
if (checked(cur, qu)) break;
}
}
if (!flag) puts("Impossible");
}
return 0;
}
矩阵距离
queue<pair<pair<int, int>, int> > qu;
inline int read(int i, int j) {
char c = getchar();
while (c != '0' && c != '1') c = getchar();
return c == '1' ? qu.push({{i, j}, 0}), 0; -1;
}
void check(int x, int y, int cnt) {
if (x < 1 || x > n || y < 1 || y > m)return;
if (mp[x][y] == -1) mp[x][y] = cnt + 1, qu.push({{x, y}, mp[x][y]});
}
int main() {
cin >> n >> m; for(int i = 1; i <= n; ++ i) for(int j = 1; j <= m; ++ j) mp[i][j] = read(i, j);
while(!qu.empty()) {
auto p = qu.front();qu.pop();
for (int i = 0; i < 4; ++ i) check(p.first.first + d[i][0], p.first.second + d[i][1], p.second);
}
for(int i = 1; i <= n; ++ i, puts("")) for(int j = 1; j <= m; ++ j) printf("%d ", mp[i][j]);
return 0;
}
⭐推箱子
int ma[21][21], n, m, _, d[4][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
char der[5] = "nswe";
int read() {
char c = getchar();
while (c != '#' && c != '.' && c != 'T' && c != 'B' && c != 'S') c = getchar();
if (c == '#') return 1;
if (c == '.') return 0;
if (c == 'T') return 2;
if (c == 'B') return 3;
return 4;
}
queue<pair<PII, string>> q;
set<PII> st;
string bfs_man(PII a, PII b, PII box) {
queue<pair<PII, string>>().swap(q); set<PII>().swap(st);
q.push({ a, "" }); st.insert(a);
if (ma[b.fi][b.se] == 1 || ma[a.fi][a.se] == 1) return "1";
while (!q.empty()) {
string s = q.front().se;
PII cur = q.front().fi; q.pop();
if (cur == b) return s;
rep(i, 0, 3) {
int x = cur.fi + d[i][0], y = cur.se + d[i][1];
if (x > n || x < 1 || y > m || y < 1) continue;
if (ma[x][y] == 1 || (x == box.fi && y == box.se)) continue;
if (!st.count({ x, y }))
q.push({ {x, y}, s + der[i] }), st.insert({ x, y });
}
}
return "1";
}
queue<pair<pair<PII, PII>, string>> qu;
set <pair<PII, PII>> stt;
string bfs_box(PII b, PII r, PII t) {
set<pair<PII, PII>>().swap(stt); qu.push({ {b, r}, "" });
vector<string> ve;
while (!qu.empty()) {
b = qu.front().fi.fi, r = qu.front().fi.se;
string s = qu.front().se; qu.pop();
if (b == t) {ve.emplace_back(s); continue;}
if (!ve.empty()) continue;
for (int i = 0; i <= 3; ++i) {
int x = b.fi + d[i][0], y = b.se + d[i][1];
int rx = b.fi - d[i][0], ry = b.se - d[i][1];
if (x > n || x < 1 || y > m || y < 1 || ma[x][y] == 1) continue;
string pe = bfs_man(r, { rx, ry }, b);
if (pe == "1") continue;
string cur = s + pe + char(der[i] ^ 32);
if (!stt.count({ {x, y}, b }))
qu.push({ {{x, y}, b}, cur }), stt.insert({ {x, y}, b });
}
}
if (ve.empty()) return "";
return *min_element(ve.begin(), ve.end(), [](string& a, string& b) {
if (a.size() != b.size()) return a.size() < b.size();
for (int i = 0; i < a.size(); ++i) if (a[i] != b[i]) for (int j = 0; j < 4; ++j)
if (a[i] == der[j] || a[i] == char(der[j] ^ 32)) return true;
else if (b[i] == der[j] || b[i] == char(der[j] ^ 32)) return false;
});
}
int main() {
int bx, by, tx, ty, sx, sy;
while (scanf("%d%d", &n, &m), n + m) {
printf("Maze #%d\n", ++_);
rep(i, 1, n) rep(j, 1, m) switch (ma[i][j] = read()) {
case 2 : tx = i, ty = j; break;
case 3 : bx = i, by = j; break;
case 4 : sx = i, sy = j; break;
}
string ans = bfs_box({ bx, by }, { sx, sy }, { tx, ty });
if (ans == "") puts("Impossible.\n");
else printf("%s\n\n", ans.c_str());
}
return 0;
}
广搜变形
电路维修
int h[N], ne[N << 2], co[N << 2], to[N << 2], tot;
void add(int u, int v, int c) {
ne[++tot] = h[u]; h[u] = tot; to[tot] = v; co[tot] = c;
}
bool read() {
char c = getchar();
while (c != '/' && c != '\\') c = getchar();
return c == '/';
}
deque<PII> q;
void dij() {
q.push_back({ 0, 1 });
rep(i, 2, s) d[i] = N << 1;
while (!q.empty()) {
int x = q.front().second; q.pop_front();
for (int i = h[x]; i; i = ne[i])
if (co[i] && d[to[i]] > d[x] + 1) {
d[to[i]] = d[x] + 1;
q.push_back({ d[x] + 1, to[i] });
} else if (!co[i] && d[to[i]] > d[x]) {
d[to[i]] = d[x];
q.push_front({ d[x], to[i] });
}
}
}
int main() {
for (cin >> _; _; --_) {
cin >> n >> m; tot = 0;
s = m * n + n + m + 1;
rep(i, 1, s) h[i] = 0;
rep(i, 1, n) rep(j, 1, m) {
int a = i * m + i - m + j - 1, b = a + 1;
int c = a + m + 1, d = c + 1, k = read();
add(a, d, k); add(d, a, k);
add(b, c, !k); add(c, b, !k);
}
dij();
if (d[s] >= (N << 1)) cout << "NO SOLUTION\n";
else cout << d[s] << '\n';
}
return 0;
}
⭐装满油的油箱
int bfs(int s, int t, int c) {
vector<vector<int>> v(n + 1, vector<int>(c + 1, 2e9)); v[s][0] = 0;
priority_queue<pair<int, pair<int, int>>> q; q.push({0, {0, s}});
while (!q.empty()) {
auto x = q.top(); q.pop();
if (x.se.se == t) return -x.fi;
if (v[x.se.se][x.se.fi] ^ -x.fi) continue;
if (x.se.fi < c && umin(v[x.se.se][x.se.fi + 1], -x.fi + a[x.se.se]))
q.push({x.fi - a[x.se.se], {x.se.fi + 1, x.se.se}});
for (auto y : h[x.se.se]) if (x.se.fi >= y.se && umin(v[y.fi][x.se.fi - y.se], -x.fi))
q.push({x.fi, {x.se.fi - y.se, y.fi}});
}
return -1;
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; ++i) cin >> a[i];
for (int i = 0; i < m; ++i) {
int u, v, c; cin >> u >> v >> c;
h[u].push_back({v, c}); h[v].push_back({u, c});
}
for (cin >> m; m; --m) {
int s, t, c, ans; cin >> c >> s >> t;
ans = bfs(s, t, c);
if (ans > -1) cout << ans << '\n';
else cout << "impossible\n";
}
return 0;
}
噩梦
bool check(int x, int y, int t, PII gh[]) {
if (x < 1 || x > n || y < 1 || y > m || g[x][y] == 'X') return 0;
if (abs(x - gh[0].first) + abs(y - gh[0].second) <= t * 2) return 0;
if (abs(x - gh[1].first) + abs(y - gh[1].second) <= t * 2) return 0;
return 1;
}
int bfs() {
memset(v, 0, sizeof v); int cnt = 0; PII boy, girl, gh[2];
for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j)
if (g[i][j] == 'M') boy = { i, j };
else if (g[i][j] == 'G') girl = { i, j };
else if (g[i][j] == 'Z') gh[cnt++] = { i, j };
queue<PII> qb, qg; qb.push(boy); qg.push(girl);
for (int t = 1; !qb.empty() || !qg.empty(); ++t) {
for (int i = 1; i <= 3; ++i) for (int j = 1, len = qb.size(); j <= len; ++j) {
auto cur = qb.front(); qb.pop();
if (!check(cur.fi, cur.se, t, gh)) continue;
for (int k = 0; k < 4; ++k) {
int x = cur.fi + d[k][0], y = cur.se + d[k][1];
if (check(x, y, t, gh))
if (v[x][y] == 2) return t;
else if (!v[x][y]) v[x][y] = 1, qb.push({ x, y });
}
}
for (int j = 1, len = qg.size(); j <= len; ++j) {
auto cur = qg.front(); qg.pop();
if (!check(cur.fi, cur.se, t, gh)) continue;
for (int k = 0; k < 4; ++k) {
int x = cur.fi + d[k][0], y = cur.se + d[k][1];
if (check(x, y, t, gh))
if (v[x][y] == 1) return t;
else if (!v[x][y]) v[x][y] = 2, qg.push({ x, y });
}
}
}
return -1;
}
int main() {
for (cin >> _; _; --_) {
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> g[i] + 1;
cout << bfs() << '\n';
}
return 0;
}
A*
⭐第k短路
vector<pair<int, int>> h[1001], g[1001];
int d[3][1001];
void dij(int s, int *d, vector<pair<int, int>>* h) {
for (int i = 0; i <= n; ++i) d[i] = 0x3f3f3f3f; d[s] = 0;
priority_queue<pair<int, int>> q; q.push({0, s});
while (!q.empty()) {
auto x = q.top(); q.pop();
if (-x.fi ^ d[x.se]) continue;
for (auto y : h[x.se]) if (umin(d[y.fi], -x.fi + y.se)) q.push({-d[y.fi], y.fi});
}
}
int main() {
cin >> n >> m;
for (int i = 0; i < m; ++i) {
int u, v, c; cin >> u >> v >> c;
h[u].push_back({v, c}); g[v].push_back({u, c});
}
cin >> s >> t >> k; if (s == t) ++k;
dij(t, d[0], g); dij(t, d[1], h); dij(s, d[2], h);
for (int i = 1; i <= n; ++i) if (i != t && max(d[0][i], max(d[1][i], d[2][i])) < d[0][0]) m = -1;
if (m != -1) return cout << -1, 0;
priority_queue<pair<int, pair<int, int>>> q; q.push({-d[0][s], {0, s}});
while (k && !q.empty()) {
auto c = q.top(); q.pop(); m = -c.fi; auto x = c.se;
if (x.se == t) --k;
for (auto y : h[x.se]) q.push({-d[0][y.fi] - x.fi - y.se, {x.fi + y.se, y.fi}});
}
cout << (k ? -1 : m);
return 0;
}
八数码
int de[4][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1} };
char der[5] = "urdl";
int f(string& s) {
int res = 0;
for (int i = 0; i < 9; ++i) if (s[i] != 'x') {
int t = s[i] - '1';
res += abs(i / 3 - t / 3) + abs(i % 3 - t % 3);
}
return res;
}
string bfs(string s) {
priority_queue<pair<int, string>> q; q.push({ f(s), s });
unordered_map<string, int> d; d[s] = 0;
unordered_map<string, bool> v;
unordered_map<string, pair<string, char>> pr;
string res, t = "12345678x";
while (!q.empty()) {
auto x = q.top(); q.pop();
if (x.se == t) break;
if (v[x.se]) continue; v[x.se] = true;
int a, b;
for (int i = 0; i < 9; ++i) if (x.se[i] == 'x') a = i / 3, b = i % 3;
for (int i = 0; i < 4; ++i) {
int z = a + de[i][0], w = b + de[i][1];
if (z < 0 || z >= 3 || w < 0 || w >= 3) continue;
auto cur = x.se; swap(cur[a * 3 + b], cur[z * 3 + w]);
if (!d.count(cur) || d[cur] > d[x.se] + 1) {
d[cur] = d[x.se] + 1;
pr[cur] = { x.se, der[i] };
q.push({ -f(cur) - d[cur], cur});
}
}
}
while (s != t) res += pr[t].se, t = pr[t].fi;
reverse(res.begin(), res.end());
return res;
}
int main() {
string g, s; char c;
while (cin >> c) { g += c; if (c != 'x') s += c; }
int t = 0;
for (int i = 0; i < 8; ++i) for (int j = i + 1; j < 8; ++j) t += s[i] > s[j];
if (t & 1) puts("unsolvable");
else cout << bfs(g) << '\n';
return 0;
}
IDA*
⭐排书
通过考虑后继想估价函数
int f() {
int res = 0;
rep (i, 1, n - 1) if (a[i + 1] != a[i] + 1) ++res;
return (res + 2) / 3;
}
bool dfs(int u) {
int ff = f();
if (u + ff > ans) return false;
if (ff == 0) return true;
rep (l, 1, n) rep (r, l, n) rep (k, r + 1, n) {
memcpy(w[u], a, sizeof a);
int idx = l - 1;
rep (i, r + 1, k) a[++idx] = w[u][i];
rep (i, l, r) a[++idx] = w[u][i];
if (dfs(u + 1)) return true;
memcpy(a, w[u], sizeof a);
}
return false;
}
int main() {
for (cin >> _; _; --_) {
cin >> n; ans = 0;
rep (i, 1, n) cin >> a[i];
while (ans < 5 && !dfs(0)) ++ans;
if (ans >= 5) cout << "5 or more\n";
else cout << ans << '\n';
}
return 0;
}
⭐回转游戏
int d[8][7] = {
{1, 3, 7, 12, 16, 21, 23}, {2, 4, 9, 13, 18, 22, 24},
{11, 10, 9, 8, 7, 6, 5}, {20, 19, 18, 17, 16, 15, 14},
{24, 22, 18, 13, 9, 4, 2}, {23, 21, 16, 12, 7, 3, 1},
{14, 15, 16, 17, 18, 19, 20}, {5, 6, 7, 8, 9, 10, 11} }, a[25];
int b[8] = {7, 8, 9, 12, 13, 16, 17, 18}, ls[9] = {5, 4, 7, 6, 1, 0, 3, 2, -1};
char s[] = "ABCDEFGH";
int f() {
int c[3] = { 0 };
for (int i = 0; i < 8; ++i) ++c[a[b[i]] - 1];
return 8 - (*max_element(c, c + 3));
}
int dfs(int k, string& op, int las) {
int cur = f(), ans;
if (!cur) return a[b[0]];
if (k < cur) return 0;
for (int i = 0; i < 8; ++i, op.pop_back()) {
if (i == ls[las]) { op += 'a'; continue; }
for (int j = 1; j < 7; ++j) swap(a[d[i][j - 1]], a[d[i][j]]);
op += s[i]; if (ans = dfs(k - 1, op, i)) return ans;
for (int j = 6; j; --j) swap(a[d[i][j]], a[d[i][j - 1]]);
}
return 0;
}
int main() {
while (cin >> a[1], a[1]) {
for (int i = 2; i <= 24; ++i) cin >> a[i];
int k = 0, ans = 0; string op;
while (!(ans = dfs(k, op, 8))) ++k;
cout << (op.empty() ? "No moves needed" : op) << '\n' << ans << '\n';
}
return 0;
}
⭐破坏正方形
bool st[61], cur[61];
VI v[56];
void init() {
rep (k, 1, n) rep (i, 0, n - k) rep (j, 0, n - k) {
VI().swap(v[++cnt]); int p = i * t + j + 1, q = p + n;
rep (g, 0, k - 1)
v[cnt].pb(p + g), v[cnt].pb(p + g + k * t),
v[cnt].pb(q + g * t), v[cnt].pb(q + g * t + k);
}
}
bool check(VI &v, bool st[]) {
for (int x : v) if (st[x]) return false;
return true;
}
int f() {
memcpy(cur, st, sizeof st);
int res = 0;
rep (i, 1, cnt) if (check(v[i], cur) && ++res)
for (int x : v[i]) cur[x] = true;
return res;
}
bool dfs(int dep) {
if (f() > dep) return false;
rep (i, 1, cnt) if (check(v[i], st)) {
for (int x : v[i]) {
st[x] = true;
if (dfs(dep - 1)) return true;
st[x] = false;
}
return false;
}
return true;
}
int main() {
for (cin >> _; _; --_) {
cin >> n >> m; t = (n << 1) + 1;
memset(st, 0, sizeof st); cnt = 0; init();
rep (i, 1, m) cin >> ans, st[ans] = 1; ans = 0;
while (!dfs(ans)) ++ans;
cout << ans << '\n';
}
return 0;
}
总结与练习
靶形数独
struct DLX {
static const int N = 1e5 + 5;
#define IT(i, A, x) for(int i=A[x];i^x;i=A[i])
int n, m, tot, first[N], siz[N], stk[N], ans;
int L[N], R[N], U[N], D[N], col[N], row[N], mx, w[N];
void build(const int &r, const int &c) {
for (int i = 0; i <= c; ++i) L[i] = i - 1, R[i] = i + 1, U[i] = D[i] = i;
n = r, m = c; L[0] = c, R[c] = 0, tot = c;
memset(first, 0, sizeof(first)); memset(siz, 0, sizeof(siz));
}
void insert(const int &r, const int &c, const int &W) {
col[++tot] = c, row[tot] = r, w[tot] = W, ++siz[c];
D[tot] = D[c], U[D[c]] = tot, U[tot] = c, D[c] = tot;
if (!first[r]) first[r] = L[tot] = R[tot] = tot;
else {
R[tot] = R[first[r]], L[R[first[r]]] = tot;
L[tot] = first[r], R[first[r]] = tot;
}
}
void remove(const int &c) {
L[R[c]] = L[c], R[L[c]] = R[c];
IT(i, D, c) IT(j, R, i) U[D[j]] = U[j], D[U[j]] = D[j], --siz[col[j]];
}
void recover(const int &c) {
IT(i, U, c) IT(j, L, i) U[D[j]] = D[U[j]] = j, ++siz[col[j]];
L[R[c]] = R[L[c]] = c;
}
bool dance(int dep, int cur) {
if (!R[0]) return mx = max(cur, mx), 1;
int c = R[0];
IT(i, R, 0) if (siz[i] < siz[c]) c = i;
remove(c);
IT(i, D, c) {
stk[dep] = row[i];
IT(j, R, i) remove(col[j]);
dance(dep + 1, cur + w[i]);
IT(j, L, i) recover(col[j]);
}
recover(c);
return 0;
}
#undef IT
} dlx;
int a[10][10];
void insert(int r, int c, int n, int w) {
int g = (r - 1) / 3 * 3 + (c - 1) / 3 + 1;
int id = (r - 1) * 81 + (c - 1) * 9 + n;
dlx.insert(id, (r - 1) * 9 + n, w);
dlx.insert(id, 81 + (c - 1) * 9 + n, w);
dlx.insert(id, 162 + (g - 1) * 9 + n, w);
dlx.insert(id, 243 + (r - 1) * 9 + c, w);
}
int main() {
dlx.build(729, 324);
for (int i = 1; i <= 9; ++i) for (int j = 1; j <= 9; ++j) {
cin >> a[i][j]; int d = max(abs(i - 5), abs(j - 5));
for (int v = 1; v <= 9; ++v) if (!a[i][j] || a[i][j] == v) insert(i, j, v, (10 - d) * v);
}
dlx.dance(1, 0); cout << (dlx.mx ? dlx.mx : -1);
return 0;
}
虫食算
int n, q[27], path[27];;
char e[3][27];
bool st[27];
bool check(){
for (int i = n - 1, t = 0; i >= 0; --i) {
int a = e[0][i] - 'A', b = e[1][i] - 'A', c = e[2][i] - 'A';
if (path[a] != -1 && path[b] != -1 && path[c] != -1) {
a = path[a], b = path[b], c = path[c];
if (t != -1) {
if ((a + b + t) % n != c) return 0;
if (!i && a + b + t >= n) return 0;
t = (a + b + t) / n;
} else {
if ((a + b + 0) % n != c && (a + b + 1) % n != c) return 0;
if (!i && a + b >= n) return 0;
}
}
else t = -1;
}
return 1;
}
bool dfs(int u){
if (u == n) return true;
for (int i = 0; i < n; ++i) if (!st[i]) {
st[i] = 1; path[q[u]] = i;
if (check() && dfs(u + 1)) return true;
st[i] = 0; path[q[u]] = -1;
}
return false;
}
int main(){
cin >> n >> e[0] >> e[1] >> e[2];
for (int i = n - 1, k = 0; i >= 0; --i) for (int j = 0; j < 3; ++j) if (!st[e[j][i] - 'A'])
st[e[j][i] - 'A'] = 1, q[k++] = e[j][i] - 'A';
memset(st, 0, sizeof st); memset(path, -1, sizeof path);
dfs(0);
for (int i = 0; i < n; ++i) cout << path[i] << ' ';
return 0;
}
⭐玛雅游戏
多次声明stl, 复制, 尽管开了噢O2, 还是比memcpy慢两倍, 差点t
bool v[7][5];
bool check(vector<vector<int>>& a) {
for (int j = 0; j < 5; ++j) if (a[0][j]) return 0;
return 1;
}
void drop(vector<vector<int>>& a) {
for (int j = 0, k = 0; j < 5; ++j, k = 0) for (int i = 0; i < 7; ++i)
if (a[i][j]) swap(a[k++][j], a[i][j]);
}
bool isdelet(vector<vector<int>>& b) {
bool f = 0;
for (int i = 0; i < 7; ++i) for (int j = 0; j < 5; ++j) if (b[i][j]) {
if (j < 3 && b[i][j] == b[i][j + 1] && b[i][j + 2] == b[i][j])
f = v[i][j] = v[i][j + 1] = v[i][j + 2] = 1;
if (i < 5 && b[i][j] == b[i + 1][j] && b[i + 2][j] == b[i][j])
f = v[i][j] = v[i + 1][j] = v[i + 2][j] = 1;
}
if (!f) return 0;
for (int i = 0; i < 7; ++i) for (int j = 0; j < 5; ++j) if (v[i][j]) b[i][j] = v[i][j] = 0;
return f;
}
bool dfs(vector<vector<int>>& b, vector<pair<pair<int, int>, int>>& path, int n) {
if (check(b)) return 1;
if (!n) return 0;
for (int j = 0; j < 5; ++j) for (int i = 0; i < 7; ++i) if (b[i][j]) {
if (j < 4 && b[i][j + 1] != b[i][j]) {
vector<vector<int>> a(b);
swap(a[i][j], a[i][j + 1]); path.push_back({ {j, i}, 1 });
for (int k = i - 1; ~k && !a[k][j + 1]; --k) swap(a[k][j + 1], a[k + 1][j + 1]);
for (int k = i; k < 6 && !a[k][j]; ++k) swap(a[k][j], a[k + 1][j]);
while (isdelet(a)) drop(a);
if (dfs(a, path, n - 1)) return 1; path.pop_back();
}
if (j && !b[i][j - 1]) {
vector<vector<int>> a(b);
swap(a[i][j], a[i][j - 1]); path.push_back({ {j, i}, -1 });
for (int k = i - 1; ~k && !a[k][j - 1]; --k) swap(a[k][j - 1], a[k + 1][j - 1]);
for (int k = i; k < 6 && !a[k][j]; ++k) swap(a[k][j], a[k + 1][j]);
while (isdelet(a)) drop(a);
if (dfs(a, path, n - 1)) return 1; path.pop_back();
}
}
return 0;
}
int main() {
int n; cin >> n; vector<vector<int>> a(7, vector<int>(5));
for (int i = 0; i < 5; ++i) for (int j = 0, c; cin >> c, c; ++j) a[j][i] = c;
vector<pair<pair<int, int>, int>> path;
dfs(a, path, n);
if (path.empty()) return cout << -1, 0;
for (auto& i : path) cout << i.first.first << ' ' << i.first.second << ' ' << i.second << '\n';
return 0;
}
巴士
vector<pair<int, PII>> li;
bool check(int a, int d) {
for (int i = a; i < 60; i += d) if (b[i] == 0) return 0;
return true;
}
bool dfs(int k, int cnt, int tot) {
if (cnt == ans) return tot == n;
rep (i, k, li.size() - 1) {
int& a = li[i].se.fi, d = li[i].se.se;
if (-li[i].fi * (ans - cnt) + tot < n) break;
if (!check(a, d)) continue;
for (int j = a; j < 60; j += d) --b[j];
if (dfs(i, cnt + 1, tot - li[i].fi)) return true;
for (int j = a; j < 60; j += d) ++b[j];
}
return false;
}
int main() {
cin >> n;
rep (i, 1, n) cin >> m, ++b[m];
rep (i, 0, 59) rep (d, i + 1, 59 - i)
if (check(i, d)) li.pb({-(59 - i) / d - 1, {i, d}});
sort(li.begin(), li.end());
while (ans < 17 && !dfs(0, 0, 0)) ++ans;
cout << ans;
return 0;
}
导弹防御系统
bool dfs(int cx, int cy, int k, int dep) {
if (cx + cy > dep) return 0;
if (k == n) return 1;
int c = cx; x[c] = -1;
for (int i = 0; i < cx; ++i) if (x[i] > x[c] && x[i] < a[k]) c = i;
swap(a[k], x[c]);
if (dfs(cx + (c == cx), cy, k + 1, dep)) return 1;
swap(a[k], x[c]);
y[c = cy] = 2e9;
for (int i = 0; i < cy; ++i) if (y[i] < y[c] && y[i] > a[k]) c = i;
swap(a[k], y[c]);
if (dfs(cx, cy + (c == cy), k + 1, dep)) return 1;
swap(a[k], y[c]);
return 0;
}
int main() {
while (cin >> n, n) {
for (int i = 0; i < n; ++i) cin >> a[i];
int ans = 1;
while (!dfs(0, 0, 0, ans)) ++ans;
cout << ans << '\n';
}
return 0;
}
武士风度的牛
bool check(int x,int y) {
return min(x, y) >= 1 && x <= n && y <= m && s[x][y] != '*' && dis[x][y] == -1;
}
int bfs() {
memset(dis, -1, sizeof(dis));
queue<pair<int, int>> q; q.push({st.first,st.second});
dis[st.first][st.second] = 0;
while(q.size()) {
p = q.front(); q.pop();
for(int i = 0; i < 8; ++i) {
int x = p.first + dx[i], y = p.second + dy[i];
if (check(x,y)) {
dis[x][y] = dis[p.first][p.second] + 1;
q.push({x, y});
if (x == ed.first && y == ed.second) return dis[x][y];
}
}
}
return -1;
}
int main() {
cin >> m >> n;
for(int i = 1; i <= n; ++i) {
cin >> s[i] + 1;
for(int j = 1; j <= m; ++j)
if (s[i][j] == 'K') st = {i, j};
else if (s[i][j]=='H') ed = {i, j};
}
cout << bfs();
return 0;
}
乳草的入侵
int main() {
cin >> m >> n >> y >> x; x = n - x + 1;
for (int i = 1; i <= n; ++i) cin >> (st[i] + 1);
st[x][y] = '*'; queue<pair<int, int>> q; q.push({x, y});
for (; !q.empty(); ++ans) for (int j = 1, len = q.size(); j <= len; ++j) {
auto p = q.front(); q.pop();
for (int i = 0; i < 8; ++i) {
int x = p.first + d[i][0], y = p.second + d[i][1];
if (x < 1 || x > n || y < 1 || y > m || st[x][y] == '*') continue;
st[x][y] = '*'; q.push({ x, y });
}
}
cout << ans - 1;
return 0;
}
字符串变换
map<string, int> mp;
set<string> st;
int bfs(string s, bool f) {
if (f && mp.count(s)) return mp[s];
queue<pair<string, int>> q; q.push({ s, mp[s] = 0 });
while (!q.empty()) {
s = q.front().first; c = q.front().second; q.pop();
for (int i = 1; i <= cnt; ++i)
for (int p = s.find(ch[i][f], 0); p != string::npos; p = s.find(ch[i][f], p + 1)) {
string cur = s;
cur.replace(p, ch[i][f].size(), ch[i][f ^ 1]);
if (!f) { if (!mp[cur]) { mp[cur] = mp[s] + 1; if (c < 4) q.push({ cur, c + 1 }); } }
else if (mp[cur]) return mp[cur] + c + 1;
else if (!st.count(cur)) st.insert(cur), q.push({ cur, c + 1 });
}
}
return -1;
}
int main() {
cin >> a >> b; mp[a] = 0;
while (cin >> ch[++cnt][0] >> ch[cnt][1]);
bfs(a, 0);
ans = bfs(b, 1);
if (~ans) cout << ans;
else cout << "NO ANSWER!";
⭐天气预报
struct node{ int day, x, y, s[4]; };
bool a[366][4][4], vis[366][4][4][7][7][7][7];
bool check(int x, int y, int day, int d[]) {
if (x < 0 || y < 0 || x > 2 || y > 2) return 0;
rep (i, 0, 1) rep (j, 0, 1) if (a[day][x + i][y + j]) return 0;
return max(max(d[0], d[1]), max(d[2], d[3])) < 7;
}
bool bfs() {
if (a[1][1][1] || a[1][1][2] || a[1][2][1] || a[1][2][2]) return 0;
queue<node> q; q.push({1, 1, 1, {1, 1, 1, 1}});
memset(vis,0,sizeof(vis));
int sd[4]; vis[1][1][1][1][1][1][1]=1;
while (!q.empty()) {
node cur = q.front(); q.pop();
if (cur.day == n) return 1;
rep (i, 0, 8) {
int x = cur.x + dx[i], y = cur.y + dy[i];
rep (j, 0, 3) sd[j] = cur.s[j] + 1;
if (x == 0 && y == 0) sd[0] = 0;
if (x == 0 && y == 2) sd[1] = 0;
if (x == 2 && y == 0) sd[2] = 0;
if (x == 2 && y == 2) sd[3] = 0;
if (check(x, y, cur.day + 1, sd) &&
!vis[cur.day + 1][x][y][sd[0]][sd[1]][sd[2]][sd[3]]) {
q.push({cur.day + 1, x, y, {sd[0], sd[1], sd[2], sd[3]}});
vis[cur.day + 1][x][y][sd[0]][sd[1]][sd[2]][sd[3]] = 1;
}
}
}
return 0;
}
int main() {
while(cin >> n, n) {
rep (i, 1, n) rep (j, 0, 3) rep (k, 0, 3) cin >> a[i][j][k];
cout << bfs() << '\n';
}
return 0;
}
⭐立体推箱子2
struct node { int x, y, z, t; }t, cur;
int dx[3][4] = {{-2, 0, 1, 0}, {-1, 0, 2, 0}, {-1, 0, 1, 0}};
int dy[3][4] = {{0, 1, 0, -2}, {0, 1, 0, -1}, {0, 2, 0, -1}};
int dz[3][4] = {{1, 2, 1, 2}, {0, 1, 0, 1}, {2, 0, 2, 0}};
int mp[9][9][3], d[3][3][3][4];
void bfs(int x, int y, int z) {
queue<node> q; q.push({ x, y, z, 0 });
memset(mp, -1, sizeof mp); mp[x][y][z] = 0;
while (!q.empty()) {
t = q.front(); q.pop(); cur.t = t.t + 1;
rep(i, 0, 3) {
cur.x = t.x + dx[t.z][i]; cur.y = t.y + dy[t.z][i]; cur.z = dz[t.z][i];
if (cur.x < 0 || cur.x > 5 || cur.y < 0 || cur.y > 5) continue;
if (mp[cur.x][cur.y][cur.z] == -1 || mp[cur.x][cur.y][cur.z] > cur.t)
mp[cur.x][cur.y][cur.z] = cur.t, q.push(cur);
}
}
}
void init() {
rep (k, 0, 2) rep (i, 0, 2) rep (j, 0, 2) {
bfs(i + 3, j + 3, k);
d[i][j][k][0] = mp[3][0][0]; d[i][j][k][1] = mp[3][3][0];
d[i][j][k][2] = mp[0][0][0]; d[i][j][k][3] = mp[0][3][0];
}
}
ll a, b;
char op;
ll calc(int c) {
ll x = a / 3, y = b / 3; a %= 3, b %= 3;
ll ans = d[a][b][c][1] + (x << 1) + (y << 1);
if (y) ans = min(ans, d[a][b][c][0] + (x << 1) + (y - 1 << 1));
if (x) ans = min(ans, d[a][b][c][2] + (x - 1 << 1) + (y - 1 << 1));
return ans;
}
int main() {
init();
while (cin >> op >> a >> b) {
int c = op == 'U' ? 0 : op == 'V' ? 1 : 2;
if (a > b) swap(a, b), c = c == 0 ? 0 : c == 1 ? 2 : 1;
cout << calc(c) << '\n';
}
return 0;
}
⭐算乘方的牛
bool dfs(int u, int a, int b) {
if (a == p || b == p) return true;
if (a > b) swap(a, b);
if (!u || b << u < p || p % __gcd(a, b)) return false;
if (st.count({u, {a, b}})) return false; st.insert({u, {a, b}});
if (dfs(u - 1, a << 1, b)) return true;
if (a != b && dfs(u - 1, a, a << 1)) return true;
if (a != b && dfs(u - 1, a, b << 1)) return true;
if (a != b && dfs(u - 1, b, b << 1)) return true;
if (a != b && dfs(u - 1, a, a + b)) return true;
if (a != b & dfs(u - 1, b, a + b)) return true;
if (a != b && dfs(u - 1, b - a, a)) return true;
if (a != b && dfs(u - 1, b - a, b)) return true;
return false;
}
int main() {
cin >> p;
while (!dfs(ans, 1, 0)) ++ans;
cout << ans;
return 0;
}
涂满它
int f() {
int tot = 0, s = 0;
rep (i, 1, n) rep (j, 1, n) if (v[i][j] != 1 && !(s & mp[i][j])) ++tot, s ^= mp[i][j];
return tot;
}
void draw(int a, int b, int c) {
v[a][b] = 1;
rep (i, 0, 3) {
int x = a + d[i][0], y = b + d[i][1];
if (x < 1 || x > n || y < 1 || y > n || v[x][y] == 1) continue;
if (mp[x][y] == c) draw(x, y, c);
else v[x][y] = 2;
}
}
bool check(int c) {
bool flag = 0;
rep (i, 1, n) rep (j, 1, n) if (mp[i][j] == c && v[i][j] == 2) draw(i, j, c), flag = 1;
return flag;
}
bool dfs(int u) {
int ff = f();
if (ff == 0) return true;
if(u + ff > ans) return false;
rep (i, 0, 5) {
int cur[9][9]; memcpy(cur, v, sizeof v);
if (!check(1 << i)) continue;
if (dfs(u + 1)) return true;
memcpy(v, cur, sizeof v);
}
return false;
}
int main() {
while (cin >> n, n) {
memset(v, 0, sizeof v); ans = 0;
rep (i, 1, n) rep(j, 1, n) cin >> mp[i][j], mp[i][j] = 1 << mp[i][j];
draw(1, 1, mp[1][1]);
while (!dfs(0)) ++ans;
cout << ans << '\n';
}
return 0;
}
骑士精神
int f() {
int x = 0, y = 0;
for (int i = 1; i < 5; ++i) for (int j = 0; j < b[i]; ++j)
x += a[i][j] != 0, y += a[4 - i][4 - j] != 1;
return x + y;
}
int dfs(int n, int x, int y, int las) {
int ff = f();
if (!ff) return 1;
if (n - ff < 0) return 0;
for (int i = 0; i < 8; ++i) {
int dx = x + d[i][0], dy = y + d[i][1];
if (min(dx, dy) < 0 || max(dx, dy) > 4 || abs(las - i) == 4) continue;
swap(a[dx][dy], a[x][y]);
if (dfs(n - 1, dx, dy, i)) return 1;
swap(a[dx][dy], a[x][y]);
}
return 0;
}
int main() {
for (cin >> _; _; --_) {
int x, y, ans = 0;
for (int i = 0; i < 5; ++i) for (int j = 0; j < 5; ++j) {
char c; cin >> c, a[i][j] = c ^ '0';
if (c == '*') x = i, y = j;
}
while (ans <= 15 && !dfs(ans, x, y, -5)) ++ans;
cout << (ans > 15 ? -1 : ans) << '\n';
}
return 0;
}
数学知识
质数
⭐质数的距离
int main() {
init(1e6);
while (cin >> L >> R) {
memset(v, 0, sizeof v); L = max(L, 2);
rep (i, 1, tot)
for (ll j = max(((L - 1) / prime[i] + 1ll) * prime[i], prime[i] << 1); j <= R; j += prime[i])
v[j - L] = 1;
int mx = -1, mi = 2e9, a, b, x, y;
for (int i = 0, j = -1;; j = i++) {
while (v[i] && i <= R - L) ++i;
if (i > R - L) break;
if (j == -1) continue;
if (i - j > mx) mx = i - j, a = j + L, b = i + L;
if (i - j < mi) mi = i - j, x = j + L, y = i + L;
}
if (mx == -1) cout << "There are no adjacent primes.\n";
else cout << x << "," << y << " are closest, " << a << "," << b << " are most distant.\n";
}
return 0;
}
阶乘分解
void work(int n) {
for (int i = 2; i <= n; ++i) {
if (!v[i]) {
int cnt = 0; prime[++tot] = i;
for (long long j = i; j <= n; j *= i) cnt += n / j;
cout << i << ' ' << cnt << '\n';
}
for (int j = 1; j <= tot && prime[j] <= n / i; ++j) {
v[i * prime[j]] = 1;
if (i % prime[j] == 0) break;
}
}
}
int main() {
int n; cin >> n; work(n);
return 0;
}
约数
反素数
void dfs(int depth, ll temp, int num, int las) {
if (depth > 15 || temp > n) return;
if (ans_num < num) ans = temp, ans_num = num;
if (ans_num == num && ans > temp) ans = temp;
for (int i = 1; i <= las; ++i) {
if (temp * p[depth] > n) break;
dfs(depth + 1, temp *= p[depth], num * (i + 1), i);
}
}
int main() {
cin >> n; dfs(0, 1, 1, 32);
cout << ans;
return 0;
}
⭐余数之和
#include <bits/stdc++.h>
using namespace std;
int main() {
long long n, m, ans; cin >> n >> m; ans = n * m; n = min(m, n);
for (int l = 1, r; l <= n; l = r + 1)
r = min(m / (m / l), n), ans -= m / l * (l + r) * (r - l + 1) >> 1;
cout << ans;
return 0;
}
⭐Hankson的趣味题
unordered_map<int, int> solve(int n) {
unordered_map<int, int> st;
for (int i = 2; i <= n / i; ++i) if (n % i == 0)
while (n % i == 0) ++st[i], n /= i;
if (n > 1) st[n] = 1;
return st;
}
int main() {
for (cin >> _; _; --_) {
cin >> a0 >> a1 >> b0 >> b1;
unordered_map<int, int> a[2] = {solve(a0), solve(a1)}, b[2] = {solve(b0), solve(b1)};
long long ans = 1;
for (auto& i : b[1]) {
int x = a[0][i.first], z = a[1][i.first], y = b[0][i.first];
if (x > z && y < i.second && i.second == z) continue;
else if (x > z && y == i.second && z <= i.second) continue;
else if (x == z && y < i.second && z <= i.second) continue;
else if (x == z && y == i.second && z <= i.second) ans *= i.second - z + 1;
else { ans = 0; break; }
}
cout << ans << '\n';
}
return 0;
}
可见的点
void euler(int n) {
for (int i = 1; i <= n; ++i) phi[i] = i;
for(int i = 2; i <= n; ++i) if(phi[i] == i)
for (int j = i; j <= n; j += i) phi[j] = phi[j] / i * (i - 1);
}
int main() {
euler(1000);
for (cin >> _; _; --_, ans = 0) {
cin >> n;
for (int i = 2; i <= n; ++i) ans += phi[i] << 1;
cout << ++cas << ' ' << n << ' ' << (n ? ans + 3 : 0) << '\n';
}
return 0;
}
同余
最幸运的数字
ll mul(ll a, ll b, ll p) {
return (a * b - (ll)((double)a * b / p) * p) % p;
}
ll qpow(ll a, ll b, ll p) {
ll ans = 1;
for(; b; b >>= 1, a = mul(a, a, p)) if (b & 1) ans = mul(ans, a, p);
return ans;
}
ll getphi(ll n) {
ll ans = n;
for (int i = 2; i <= n / i; ++i) if (n % i == 0) {
ans = ans / i * (i - 1);
while (n % i == 0) n /= i;
}
return n - 1 ? ans / n * (n - 1) : ans;
}
ll work(ll x, ll p) {
ll ans = 2e18;
if (__gcd(p, 10ll) != 1) return 0;
for (int i = 1; i <= x / i; ++i) if (x % i == 0) {
if (qpow(10, i, p) == 1) ans = min(ans, (ll)i);
if (qpow(10, x / i, p) == 1) ans = min(ans, x / i);
}
return ans == 2e18 ? 0 : ans;
}
int main() {
ll b, cas = 0;
while (scanf("%lld", &b), b) {
b = b / __gcd(b, 8ll) * 9;
printf("Case %lld: %lld\n", ++cas, work(getphi(b), b));
}
return 0;
}
同余方程
ll exgcd(ll a, ll b, ll& x, ll& y) {
if (!b) { x = 1, y = 0; return a; }
ll d = exgcd(b, a % b, y, x); y -= a / b * x;
return d;
}
int main() {
ll a, b, x, y; cin >> a >> b;
ll d = exgcd(a, b, x, y);
cout << (x + b / d) % (b / d);
return 0;
}
表达整数的奇怪方式
ll exgcd(ll a, ll b, ll& x, ll& y) {
if (b == 0) { x = 1, y = 0; return a; }
ll d = exgcd(b, a % b, y, x); y -= a / b * x;
return d;
}
ll mod(ll x, ll p) { return (x % p + p) % p; }
ll work(ll a[], ll m[], int n) {
for (int i = 2; i <= n; ++i) {
ll k1, k2, d = exgcd(m[1], m[i], k1, k2);
ll c = mod(a[i] - a[1], m[i]);
if (c % d) return -1;
ll p = m[i] / d; c = c / d % p; k1 = mod(k1 * c, p);
a[1] += m[1] * k1; m[1] = m[1] / d * m[i];
}
return a[1];
}
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) cin >> m[i] >> a[i];
cout << work(a, m, n);
return 0;
}
矩阵乘法
斐波那契
struct Matrix {
static const int mod = 10000;
int n, m;
vector<vector<int>> a;
Matrix(int N = 0, int M = 0): n(N), m(M) { a.resize(n, vector<int>(m)); }
Matrix operator*(const Matrix& x) {
Matrix ans(n, x.m);
for (int i = 0; i < n; ++i) for (int j = 0; j < x.m; ++j)
for (int k =0; k < m; ++k) ans.a[i][j] = (ans.a[i][j] + a[i][k] * x.a[k][j]) % mod;
return ans;
}
};
Matrix qpow(Matrix a, int b) {
Matrix ans(a.n, a.m);
for (int i = 0; i < a.n; ++i) ans.a[i][i] = 1;
for (; b; b >>= 1, a = a * a) if (b & 1) ans = ans * a;
return ans;
}
int main() {
int n;
while (cin >> n, n > -1) {
Matrix a(2, 2); a.a[0][1] = a.a[1][0] = a.a[1][1] = 1;
a = qpow(a, n); cout << a.a[1][0] << '\n';
}
return 0;
}
⭐石头游戏
struct Matrix {
int n, m;
vector<vector<long long>> a;
Matrix(int N = 0, int M = 0): n(N), m(M) { a.resize(n, vector<long long>(m)); }
Matrix operator*(const Matrix& x) {
Matrix ans(n, x.m);
for (int i = 0; i < n; ++i) for (int j = 0; j < x.m; ++j)
for (int k = 0; k < m; ++k) ans.a[i][j] += a[i][k] * x.a[k][j];
return ans;
}
};
Matrix qpow(Matrix a, int b) {
Matrix ans(a.n, a.m);
for (int i = 0; i < a.n; ++i) ans.a[i][i] = 1;
for (; b; b >>= 1, a = a * a) if (b & 1) ans = ans * a;
return ans;
}
Matrix a[61];
int c[9][9], len[10], n, m, t, act;
char s[10][10];
int main() {
scanf("%d%d%d%d", &n, &m, &t, &act);
a[0] = Matrix(n * m + 1, n * m + 1);
for (int i = 0; i < m * n + 1; ++i) a[0].a[i][i] = 1;
for (int i = 1; i < 61; ++i) a[i] = a[0];
for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) scanf("%1d", &c[i][j]);
for (int i = 0; i < act; ++i) cin >> s[i], len[i] = strlen(s[i]);
for (int k = 1; k < 61; a[k] = a[k - 1] * a[k], ++k) for (int i = 1; i <= n; ++i)
for (int j = 1, id = (i - 1) * m + 1; j <= m; ++j, ++id)
switch (s[c[i][j]][(k - 1) % len[c[i][j]]]) {
case 'N': if (i > 1) a[k].a[id][id - n] = 1; a[k].a[id][id] = 0; break;
case 'W': if (j > 1) a[k].a[id][id - 1] = 1; a[k].a[id][id] = 0; break;
case 'S': if (i < n) a[k].a[id][id + n] = 1; a[k].a[id][id] = 0; break;
case 'E': if (j < m) a[k].a[id][id + 1] = 1; a[k].a[id][id] = 0; break;
case 'D': a[k].a[id][id] = 0; break;
default : a[k].a[0][id] = s[c[i][j]][(k - 1) % len[c[i][j]]] ^ '0';
}
a[60] = qpow(a[60], t / 60); a[60] = a[60] * a[t % 60];
long long mx = 0; for (int i = 1; i < n * m + 1; ++i) mx = max(mx, a[60].a[0][i]);
printf("%lld", mx);
return 0;
}
高斯消元与线性空间
球星空间产生器
int gauss(int n, int m) {
int c = 1, r = 1;
for (int t = r; c < m && r <= n; ++c, t = r) {
rep (i, r + 1, n) if (fabs(a[i][c]) > fabs(a[t][c])) t = i;
if (fabs(a[t][c]) < 1e-6) continue;
if (t != r) rep (i, 1, m) swap(a[t][i], a[r][i]);
rep (i, c + 1, m) a[r][i] /= a[r][c]; a[r][c] = 1;
for (int i = r + 1; i <= n; a[i++][c] = 0) if (a[i][c])
rep (j, c + 1, m) a[i][j] -= a[i][c] * a[r][j];
++r;
}
rep (i, r, n) if (a[i][m]) return -1;
if (r < m) return 0;
per (i, m - 2, 1) rep (j, i + 1, m - 1) a[i][m] -= a[j][m] * a[i][j];
return 1;
}
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[0][i];
for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) {
cin >> a[i][j]; a[i][n + 1] += a[i][j] * a[i][j] - a[0][j] * a[0][j];
a[i][j] = 2 * (a[i][j] - a[0][j]);
}
gauss(n, n + 1);
for (int i = 1; i <= n; ++i) cout << setiosflags(ios::fixed) << setprecision(3) << a[i][n + 1] << ' ';
return 0;
}
开关问题
int gauss(int n) {
bitset<29> a[n + 1]; a[0][0] = 1;
for (int i = 1; i <= n; ++i) cin >> m, a[i][0] = m, a[i][i] = 1;
for (int i = 1; i <= n; ++i) cin >> m, a[i][0] = a[i][0] ^ m;
while (cin >> x >> y, x || y) a[y][x] = 1;
int r = 1;
for (int c = 1, t = 0; c <= n; ++c, r += !!t, t = 0) {
for (int j = r; j <= n; ++j) if (a[j][c]) { t = j; break; }
if (!t) continue; swap(a[r], a[t]);
for (int j = 1; j <= n; ++j) if (j != r && a[j][c]) a[j] ^= a[r];
}
for (int i = n; i >= r; --i) if (a[i] == a[0]) return -1;
return pow(2, n - r + 1);
}
int main() {
for (cin >> _; _; --_) {
cin >> n;
int ans = gauss(n);
if (ans == -1) cout << "Oh,it's impossible~!!\n";
else cout << ans << '\n';
}
return 0;
}
装备购买
int gauss(int n, int m) {
int c = 1, r = 1;
for (int t = r; c <= m && r <= n; ++c, t = r) {
for (int i = r + 1; i <= n; ++i)
if (fabs(a[i][c]) > eps && a[i][0] < a[t][0] || fabs(a[t][c]) < eps) t = i;
if (fabs(a[t][c]) < eps) continue;
if (t != r) for (int i = 0; i <= m; ++i) swap(a[t][i], a[r][i]);
ans += a[r][0];
for (int i = c + 1; i <= m; ++i) a[r][i] /= a[r][c];
a[r][c] = 1;
for (int i = r + 1; i <= n; ++i) if (a[i][c]) {
for (int j = c + 1; j <= m; ++j) a[i][j] -= a[i][c] * a[r][j];
a[i][c] = 0;
}
++r;
}
return r - 1;
}
int main() {
cin >> n >> m;
rep (i, 1, n) rep (j, 1, m) cin >> a[i][j];
rep (i, 1, n) cin >> a[i][0];
cout << gauss(n, m) << ' ' << ans;
return 0;
}
⭐异或运算
struct XXJ {
static const int N = 59;
ll g[N + 1]; bool zero = 0; vector<ll> a;
void init() { memset(g, 0, sizeof g); zero = 0; }
void insert(ll x) {
per (i, N, 0) if (x >> i & 1) { if (!g[i]) {g[i] = x; return; }; x ^= g[i]; } zero = 1;
}
bool isin(ll x) { per (i, N, 0) if (x >> i & 1) x ^= g[i]; return !x; }
ll max() { ll mx = 0; per (i, N, 0) umax(mx, mx ^ g[i]); return mx; }
ll min() { if (zero) return 0; rep (i, 0, N) if (g[i]) return g[i]; }
void build() {
vector<ll>().swap(a);
rep (i, 0, N) {
per (j, i - 1, 0) if (g[i] >> j & 1) g[i] ^= g[j];
if (g[i]) a.emplace_back(g[i]);
}
}
ll kth(ll k) {
ll ans = 0; k -= zero; if (k <= 0) return !k ? 0 : -1;
if (k >> a.size()) return -1;
rep (i, 0, a.size() - 1) if (k >> i & 1) ans ^= a[i];
return ans;
}
} xxj;
int main() {
for (cin >> _; _; --_) {
cout << "Case #" << ++cas << ":\n"; cin >> n; xxj.init();
for (int i = 0; i < n; ++i) cin >> k, xxj.insert(k); xxj.build();
for (cin >> m; m; --m) cin >> k, cout << xxj.kth(k) << '\n';
}
return 0;
}
组合计数
计算系数
int qpow(long long a, int b) {
long long ans = 1;
for (; b; b >>= 1, a = a * a % mod) if (b & 1) ans = ans * a % mod;
return ans;
}
void init(int n) {
fac[0] = fac[1] = inv[0] = inv[1] = facinv[0] = facinv[1] = 1;
for (int i = 2; i <= n; ++i) {
fac[i] = fac[i - 1] * i % mod;
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
facinv[i] = facinv[i - 1] * inv[i] % mod;
}
}
int main() {
cin >> a >> b >> k >> n >> m; init(k);
int ans = qpow(a, n) * qpow(b, m) % mod * fac[k] % mod * facinv[n] % mod * facinv[k - n] % mod;
cout << ans;
return 0;
}
计数交换
int power(ll a, int b) {
ll ans = 1;
for (; b; b >>= 1, a = a * a % mod) if (b & 1) ans = ans * a % mod;
return ans;
}
void dfs(int u, int cnt) {
v[u] = 1;
if (v[a[u]]) ans = (ll)ans * d[cnt] % mod * c[cnt - 1] % mod;
else dfs(a[u], cnt + 1);
}
void init () {
c[0] = b[0] = d[1] = b[1] = c[1] = 1;
for (int i = 2; i <= 1e5; ++i) {
b[i] = (ll)b[i - 1] * i % mod;
c[i] = power(b[i], mod - 2);
d[i] = power(i, i - 2);
}
}
int main() {
IOS; init();
for (cin >> _; _; --_) {
cin >> n; cnt = 0, ans = 1;
for (int i = 1; i <= n; ++i) cin >> a[i], v[i] = 0;
for (int i = 1; i <= n; ++i) if (!v[i]) dfs(i, 1), ++cnt;
ans = (ll)ans * b[n - cnt] % mod;
cout << ans << '\n';
}
return 0;
}
⭐古代猪文
ll fac[4][N], inv[4][N], facinv[4][N], n, q, a[5], m[5];
int pri[N * 10], tot;
ll qpow(ll a, int b, ll p) {
ll ans = 1;
for (; b; b >>= 1, a = a * a % p) if (b & 1) ans = ans * a % p;
return ans;
}
ll C(int n, int m, int k) {
return m > n ? 0 : fac[k][n] * facinv[k][m] % mod[k] * facinv[k][n - m] % mod[k];
}
ll lucas(ll n, ll m, int k) {
return m ? C(n % mod[k], m % mod[k], k) * lucas(n / mod[k], m / mod[k], k) % mod[k] : 1;
}
void init(int k) {
fac[k][0] = fac[k][1] = inv[k][0] = inv[k][1] = facinv[k][0] = facinv[k][1] = 1;
for (int i = 2; i <= mod[k]; ++i) {
fac[k][i] = fac[k][i - 1] * i % mod[k];
inv[k][i] = (mod[k] - mod[k] / i) * inv[k][mod[k] % i] % mod[k];
facinv[k][i] = facinv[k][i - 1] * inv[k][i] % mod[k];
}
}
ll work(ll a[], ll m[], int n) {
ll t = 1, ans = 0;
for (int i = 1; i <= n; ++i) t *= m[i];
for (int i = 1; i <= n; ++i) {
ll cur = qpow(t / m[i], m[i] - 1, t) * a[i] % t;
ans = (ans + cur) % t;
}
return ans;
}
int main() {
for (int i = 0; i < 4; ++i) init(i), m[i + 1] = mod[i];
cin >> n >> q;
if (q == mod[4]) return cout << 0, 0;
for (int i = 1; i <= n / i; ++i) if (n % i == 0) {
pri[++tot] = i;
if (n / i != i) pri[++tot] = n / i;
}
for (int i = 0; i < 4; ++i) for (int j = 1; j <= tot; ++j)
a[i + 1] = (a[i + 1] + lucas(n, pri[j], i)) % mod[i];
ll ans = work(a, m, 4);
cout << qpow(q % mod[4], ans, mod[4]);
return 0;
}
容斥原理和Mobius函数
⭐Devu和鲜花
nt qpow(ll a, int b) {
ll ans = 1;
for (; b; b >>= 1, a = a * a % mod) if (b & 1) ans = ans * a % mod;
return ans;
}
int C(int n, int m) {
if (m > n) return 0;
ll ans = b[m];
for (int i = 1; i <= m; ++i) ans = ans * (n + 1 - i) % mod;
return ans;
}
int lucas(ll n, int m) {
return m ? (ll)C(n % mod, m) * lucas(n / mod, m / mod) % mod : 1;
}
int main() {
cin >> n >> m >> a[1];
for (int i = 2; i <= n; ++i) {
cin >> a[i];
inv[i] = (ll)(mod - mod / i) * inv[mod % i] % mod;
b[i] = (ll)b[i - 1] * inv[i] % mod;
}
for (int i = 0; i < 1 << n; ++i) {
int p = 0;
ll t = n + m;
for (int j = 0; j < n; ++j) if (i >> j & 1) ++p, t -= a[j + 1];
k = (k + (p & 1 ? -1 : 1) * lucas(t - p - 1, n - 1)) % mod;
}
cout << (k + mod) % mod;
return 0;
}
破译密码
void init(int n) {
mu[1] = s[1] = 1;
for (int i = 2; i <= n; ++i) {
if (!v[i]) pri[++tot] = i, mu[i] = -1;
s[i] = s[i - 1] + mu[i];
for (int j = 1; j <= tot && pri[j] <= n / i; ++j) {
v[i * pri[j]] = 1;
if (i % pri[j] == 0) break;
mu[i * pri[j]] = -mu[i];
}
}
}
int main() {
init(5e4);
for (cin >> _; _; --_) {
cin >> a >> b >> d; a /= d, b /= d;
long long ans = 0;
if (a > b) swap(a, b);
for (int l = 1, r; l <= a; l = r + 1) {
r = min(a, min(a / (a / l), b / (b / l)));
ans += (long long)(s[r] - s[l - 1]) * (a / l) * (b / l);
}
cout << ans << '\n';
}
return 0;
}
概率与数学期望
Rainbow的信号
void work(int k) {
int c1 = 0, c2 = 0, last[2] = {0};
double pos = 1.0 * (1 << k) / n / n;
for (int r = 1; r <= n; ++r) {
bool v = ((a[r] >> k) & 1);
if (v) {
ansxor += pos, ansand += pos, ansor += pos;
ansor += pos * (r - 1) * 2;
ansand += pos * (r - 1 - last[0]) * 2;
ansxor += pos * c1 * 2;
} else {
ansor += pos * last[1] * 2;
ansxor += pos * c2 * 2;
}
++c1;
if (v) swap(c1, c2);
last[v] = r;
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 0; i < 32; ++i) work(i);
printf("%.3lf %.3lf %.3lf", ansxor, ansand, ansor);
return 0;
}
⭐绿豆蛙的归宿
int main() {
cin >> n >> m;
for (int i = 1; i <= m; ++i) {
int u, v, c; cin >> u >> v >> c;
add(v, u, c); ++a[u], ++b[u];
}
queue<int> q; q.push(n);
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = h[x]; i; i = ne[i]) {
int y = to[i];
dis[y] += (dis[x] + co[i]) / b[y];
if (--a[y] == 0) q.push(y);
}
}
cout << setiosflags(ios::fixed) << setprecision(2) << dis[1];
return 0;
}
⭐扑克牌
double dfs(int a, int b, int c, int d, int e, int g) {
if (f[a][b][c][d][e][g] > eps) return f[a][b][c][d][e][g];
if (a + (e == 1) + (g == 1) >= A && b + (e == 2) + (g == 2) >= B &&
c + (e == 3) + (g == 3) >= C && d + (e == 4) + (g == 4) >= D) return 0;
double sum = 1.0, x = 1e9, y = 1e9;
int s = 54 - a - b - c - d - (e != 0) - (g != 0);
if (a < 13) sum += dfs(a + 1, b, c, d, e, g) * (13 - a) / s;
if (b < 13) sum += dfs(a, b + 1, c, d, e, g) * (13 - b) / s;
if (c < 13) sum += dfs(a, b, c + 1, d, e, g) * (13 - c) / s;
if (d < 13) sum += dfs(a, b, c, d + 1, e, g) * (13 - d) / s;
if (e == 0) for (int i = 1; i < 5; ++i) x = min(x, dfs(a, b, c, d, i, g) / s);
if (g == 0) for (int i = 1; i < 5; ++i) y = min(y, dfs(a, b, c, d, e, i) / s);
if (e == 0) sum += x;
if (g == 0) sum += y;
return f[a][b][c][d][e][g] = sum;
}
int main() {
cin >> A >> B >> C >> D;
if (max(A - 13, 0) + max(B - 13, 0) + max(C - 13, 0) + max(D - 13, 0) > 2)
cout << setiosflags(ios::fixed) << setprecision(3) << -1.00;
else cout << setiosflags(ios::fixed) << setprecision(3) << dfs(0, 0, 0, 0, 0, 0);
return 0;
}
0/1分数规划
博弈论之SG函数
⭐剪纸游戏
void init() {
for (int n = 2; n <= 200; ++n) for (int m = 2; m <= 200; ++m) {
memset(mex, 0, sizeof mex);
for (int i = 2; n - i >= 2; ++i) mex[sg[i][m] ^ sg[n - i][m]] = 1;
for (int j = 2; m - j >= 2; ++j) mex[sg[n][j] ^ sg[n][m - j]] = 1;
for (int i = 0; i <= 200; ++i) if (!mex[i]) { sg[n][m] = i; break; }
}
}
int main() {
init();
while (cin >> n >> m) cout << (sg[n][m] ? "WIN\n" : "LOSE\n");
return 0;
}
总结与练习
最大公约数
int init(int n) {
for (int i = 2; i <= n; ++i) {
if (!v[i]) pri[++tot] = i, phi[i] = i - 1;
s[i] = s[i - 1] + phi[i];
for (int j = 1; j <= tot && pri[j] <= n / i; ++j) {
v[pri[j] * i] = 1;
phi[pri[j] * i] = phi[i] * (pri[j] - (i % pri[j] != 0));
if (i % pri[j] == 0) break;
}
}
}
int main() {
cin >> n; init(n);
for (int i = 1; i <= tot; ++i) ans += s[n / pri[i]] << 1 | 1;
cout << ans;
return 0;
}
龙哥的问题
int phi(int n) {
int ans = n;
for (int i = 2; i <= n / i; ++i) if (n % i == 0) {
ans = ans / i * (i - 1);
while (n % i == 0) n /= i;
}
return n - 1 ? ans / n * (n - 1) : ans;
}
int main() {
long long ans = 0, n; cin >> n;
for (int i = 1; i <= n / i; ++i) if (n % i == 0) {
ans += (long long)i * phi(n / i);
if (i != n / i) ans += (long long)n / i * phi(i);
}
cout << ans;
return 0;
}
青蛙的约会
ll exgcd(ll a, ll b, ll &x, ll &y) {
if (!b) return x = 1, y = 0, a;
ll d = exgcd(b, a % b, y, x); y -= a / b * x;
return d;
}
int main() {
cin >> x >> y >> m >> n >> L; d = exgcd(m - n, -L, a, b);
if ((y - x) % d) return cout << "Impossible", 0;
a = ((y - x) / d * a % abs(L / d) + abs(L / d)) % abs((L / d));
return cout << a, 0;
}
阿九大战朱最学
ll exgcd(ll a, ll b, ll &x, ll &y) {
if (!b) return x = 1, y = 0, a;
ll d = exgcd(b, a % b, y, x); y -= a / b * x;
return d;
}
ll CRT(ll a[], ll m[], int n) {
ll t = 1, ans = 0;
for (int i = 0; i < n; ++i) t *= m[i];
for (int i = 0; i < n; ++i) {
ll cur = t / m[i], x, y; exgcd(cur, m[i], x, y);
ans = (ans + a[i] * cur % t * x % t) % t;
}
return (ans + t) % t;
}
int main() {
cin >> n; for (int i = 0; i < n; ++i) cin >> a[i] >> b[i];
cout << CRT(b, a, n);
return 0;
}
计算器
ll qpow(ll a, ll b, int p) {
ll ans = 1;
for (; b; b >>= 1, a = a * a % p) if (b & 1) ans = ans * a % p;
return ans;
}
ll exgcd(ll a, ll b, ll &x, ll &y) {
if (!b) return x = 1, y = 0, a;
ll d = exgcd(b, a % b, y, x); y -= a / b * x;
return d;
}
ll baby_step_giant_step(ll a, ll b, ll p) { //a^x%p=b (gcd(a, p)=1)
unordered_map<ll, ll> st; b %= p;
int t = sqrt(p - 1) + 1; ll cur = 1;
for (int i = 0; i < t; ++i, cur = cur * a % p) st[b * cur % p] = i;
a = qpow(a, t, p); cur = a;
if (a == 0) return b == 0 ? 1 : -1;
for (int i = 1; i <= t; ++i, cur = cur * a % p) {
ll c = st.count(cur) ? st[cur] : -1;
if (c >= 0 && i * t - c >= 0) return i * t - c;
}
return -1;
}
int main() {
cin >> n >> k;
for (int i = 0; i < n; ++i) {
cin >> a >> b >> c;
if (k == 1) cout << qpow(a, b, c) << '\n';
else if (k == 2) {
ll x, y, d = exgcd(a, c, x, y); y = abs(c / d);
if (b % d) cout << "Orz, I cannot find x!\n";
else cout << (x % y * b / d % y + y) % y << '\n';
} else {
ll ans = baby_step_giant_step(a, b, c);
if (ans == -1) cout << "Orz, I cannot find x!\n";
else cout << ans << '\n';
}
}
return 0;
}
矩阵幂求和
struct matrix {
long long n, m, a[30][30];
matrix(int N = 0, int M = 0) : n(N), m(M) { memset(a, 0, sizeof a); };
matrix operator*(const matrix& b) {
matrix ans(n, b.m);
for (int i = 0; i < n; ++i) for (int j = 0; j < b.m; ++j)
for (int k = 0; k < m; ++k) ans.a[i][j] = (ans.a[i][j] + a[i][k] * b.a[k][j] % p) % p;
return ans;
}
matrix operator+(const matrix& b) {
matrix ans(n, m);
for (int i = 0; i < n; ++i) for (int j = 0; j < b.m; ++j) ans.a[i][j] = (a[i][j] + b.a[i][j]) % p;
return ans;
}
} a;
matrix qpow(matrix a, int b) {
matrix ans(a.n, a.m);
for (int i = 0; i < a.n; ++i) ans.a[i][i] = 1;
for (; b; b >>= 1, a = a * a) if (b & 1) ans = ans * a;
return ans;
}
matrix work(int len, matrix x) {
if (len == 1) return x;
matrix ans = work(len >> 1, x), t = qpow(x, len >> 1);
ans = ans + t * ans;
return len & 1 ? ans + qpow(x, len) : ans;
}
int main() {
cin >> n >> k >> p; a = matrix(n, n);
for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) cin >> a.a[i][j];
a = work(k, a);
for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) cout << a.a[i][j] << " \n"[j == n - 1];
return 0;
}
⭐矩阵
struct Matrix {
int n; vector<vector<ll>> a;
Matrix(int x = 0): n(x) { vector<vector<ll>>(x, vector<ll>(x, 0ll)).swap(a); }
Matrix operator*(const Matrix& y) {
Matrix ans(n);
for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j)
for (int k = 0; k < n; ++k) ans.a[i][j] = (ans.a[i][j] + a[i][k] * y.a[k][j] % mod) % mod;
return ans;
}
} t;
Matrix qpow(Matrix a, int b) {
Matrix ans(a.n);
for (int i = 0; i < a.n; ++i) ans.a[i][i] = 1;
for (; b; a = a * a, b >>= 1) if (b & 1) ans = ans * a;
return ans;
}
int main() {
while (cin >> n >> m) {
for (int i = 1; i <= n; ++i) cin >> a[i]; a[0] = 23; a[n + 1] = 3;
t = Matrix(n + 2);
for (int j = 0; j <= n; ++j) {
t.a[0][j] = 10;
for (int i = 1; i <= j; ++i) t.a[i][j] = 1;
}
for (int j = 0; j <= n + 1; ++j) t.a[n + 1][j] = 1;
t = qpow(t, m); ll ans = 0;
for (int i = 0; i <= n + 1; ++i) ans = (ans + t.a[i][n] * a[i] % mod) % mod;
cout << ans << '\n';
}
return 0;
}
小部件场
int calc(char a, char b) {
switch (a) {
case 'M' : return 0;
case 'T' : return b == 'U' ? 1 : 3;
case 'W' : return 2;
case 'F' : return 4;
default : return b == 'A' ? 5 : 6;
}
}
int qpow(int a, int b) {
int ans = 1;
for (; b; b >>= 1, a = a * a % mod)
if (b & 1) ans = ans * a % mod;
return ans;
}
int gauss(int n, int m) {
int c = 1, r = 1;
for (int t = -1; c < m && r <= n; ++c, t = -1) {
rep (i, r, n) if (a[i][c]) { t = i; break; }
if (t == -1) continue;
if (t != r) swap(a[t], a[r]);
a[r][c] = qpow(a[r][c], mod - 2);
rep (i, c + 1, m) a[r][i] = (ll)a[r][i] * a[r][c] % mod; a[r][c] = 1;
for (int i = r + 1; i <= n; a[i++][c] = 0) if (a[i][c])
rep (j, c + 1, m) a[i][j]=((a[i][j] - a[r][j] * a[i][c])%mod+mod)%mod;
++r;
}
rep (i, r, n) if (a[i][m]) return -1;
if (r < m) return 0;
per (i, m - 1, 1) {
rep (j, i + 1, m - 1) a[i][m] = ((a[i][m] - a[j][m] * a[i][j]) % mod + mod) % mod;
if (a[i][m] < 3) a[i][m] += 7;
}
return 1;
}
int main() {
while (scanf("%d%d", &n, &m), n || m) {
memset(a, 0, sizeof a);
for (int i = 1; i <= m; ++i) {
int k, cur; scanf("%d%s%s", &k, s, t);
while(k--) scanf("%d", &cur), a[i][cur] = (a[i][cur] + 1) % mod;
a[i][n + 1] = (calc(t[0], t[1]) - calc(s[0], s[1]) + 1 + mod) % mod;
}
int t = gauss(m, n + 1);
if (t == 1) {
for (int i = 1; i <= n; ++i) printf("%d ", a[i][n + 1]);
puts("");
}
else if (t == 0) puts("Multiple solutions.");
else puts("Inconsistent data.");
}
return 0;
}
⭐异或
struct XXJ {
static const int N = 59;
ll g[N + 1];
void insert(ll x) {
per (i, N, 0) if (x >> i & 1)
if (!g[i]) {g[i] = x; return; } else x ^= g[i];
zero = 1;
}
ll max(ll x) { per (i, N, 0) if (!(x >> i & 1)) x ^= g[i]; return x; }
} xxj;
ll n, m, a[50001];
vector<pair<int, ll>> h[50001];
void dfs(int x) {
for (auto &y : h[x])
if (a[y.first] != -1) xxj.insert(a[y.first] ^ a[x] ^ y.second);
else a[y.first] = a[x] ^ y.second, dfs(y.first);
}
int main() {
cin >> n >> m; memset(a, -1, sizeof a); a[1] = 0;
for (int i = 0; i < m; ++i) {
int u, v; ll c; cin >> u >> v >> c;
h[u].emplace_back(v, c); h[v].emplace_back(u, c);
}
dfs(1); if (a[n] != -1) cout << xxj.max(a[n]);
return 0;
}
新NIM游戏
bool insert(int x) {
for (int i = 29; ~i; --i) if (x >> i & 1)
if (!a[i]) return a[i] = x, 1;
else x ^= a[i];
return 0;
}
int main() {
cin >> n;
for (int i = 0; i < n; ++i) cin >> b[i]; sort(b, b + n);
for (int i = n - 1; ~i; --i) if (!insert(b[i])) ans += b[i];
cout << ans;
return 0;
}
排列计数
ll C(int n, int m) { return m > n ? 0 : fac[n] * facinv[m] % mod * facinv[n - m] % mod; }
void init(int n) {
for (int i = 0; i < 2; ++i) fac[i] = inv[i] = facinv[i] = 1; f[0] = 1;
for (int i = 2; i <= n; ++i)
fac[i] = fac[i - 1] * i % mod,
inv[i] = (ll)(mod - mod / i) * inv[mod % i] % mod,
facinv[i] = facinv[i - 1] * inv[i] % mod,
f[i] = (f[i - 2] + f[i - 1]) % mod * (i - 1) % mod;
}
int main() {
IOS; init(1e6);
for (cin >> _; _; --_) {
cin >> n >> m;
cout << C(n, m) * f[n - m] % mod << '\n';
}
return 0;
}
⭐天码
void work(ll x) {
int tot = 0;
for (int i = 2; i <= x / i; ++i) if (x % i == 0) {
pri[tot++] = i;
while (x % i == 0) x /= i;
}
if (x != 1) pri[tot++] = x;
for (int i = 0; i < 1 << tot; ++i) {
int c = 0, k = 1;
for (int j = 0; j < tot; ++j) if (i >> j & 1) k *= pri[j], ++c;
cnt[k] = c, ++tax[k];
}
}
int main() {
for (int i = 5; i <= 1e4; ++i) c[i] = c[i - 1] * i / (i - 4);
while (cin >> n) {
memset(tax, 0, sizeof tax);
for (int i = 0; i < n; ++i) cin >> m, work(m);
ll ans = c[n];
for (int i = 2; i <= 1e4; ++i) ans += c[tax[i]] * (cnt[i] & 1 ? -1 : 1);
cout << ans << '\n';
}
return 0;
}
⭐守卫者的挑战
int main() {
cin >> n >> m >> k;
rep (i ,1, n) cin >> p[i], p[i] /= 100;
rep (i, 1, n) cin >> a[i];
f[0][0][N] = 1;
rep(i, 1, n) rep(j, 1, n) rep(t, -i, n)
f[i][j][min(t + N + a[i], n + N)] += f[i - 1][j - 1][t + N] * p[i],
f[i][j - 1][t + N] += f[i - 1][j - 1][t + N] * (1 - p[i]);
rep(i, m, n) rep(j, max(-k, -n), n) ans += f[n][i][j + N];
cout << setiosflags(ios::fixed) << setprecision(6) << ans;
return 0;
}
⭐换教室
int main() {
cin >> n >> m >> v >> e; memset(d, 0x3f, sizeof d);
rep (i, 1, v) d[i][i] = 0; rep (i, 1, n) cin >> a[i];
rep (i, 1, n) cin >> b[i]; rep (i, 1, n) cin >> k[i];
rep (i, 1, e) {
int u, v, c; cin >> u >> v >> c;
d[u][v] = d[v][u] = min(d[u][v], c);
}
rep (k, 1, v) rep (i, 1, v) rep (j, 1, v) d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
rep (i, 0, n) rep (j, 0, m) f[i][j][0] = f[i][j][1] = 1e9;
f[1][0][0] = f[1][1][1] = 0;
rep (i, 2, n) rep (j, 0, min(i, m)) {
if (j < i) f[i][j][0] = min(f[i - 1][j][0] + d[a[i - 1]][a[i]], f[i - 1][j][1] +
d[a[i - 1]][a[i]] * (1 - k[i - 1]) + d[b[i - 1]][a[i]] * k[i - 1]);
if (j) f[i][j][1] = min(f[i - 1][j - 1][0] + d[a[i - 1]][a[i]] * (1 - k[i]) + d[a[i - 1]][b[i]] * k[i],
f[i - 1][j - 1][1] + (d[a[i - 1]][a[i]] * (1 - k[i - 1]) + d[b[i - 1]][a[i]] * k[i - 1]) * (1 - k[i])
+ (d[a[i - 1]][b[i]] * (1 - k[i - 1]) + d[b[i - 1]][b[i]] * k[i - 1]) * k[i]);
}
rep (i, 0, m) ans = min(ans, min(f[n][i][0], f[n][i][1]));
cout << setiosflags(ios::fixed) << setprecision(2) << ans;
return 0;
}
放弃测试
bool check(double mid) {
vector<double> c; double cur = 0;
for (int i = 0; i < n; ++i) c.emplace_back(100.0 * a[i] - mid * b[i]);
sort(c.begin(), c.end());
for (int i = k; i < n; ++i) cur += c[i];
return cur >= 0;
}
int main() {
while (cin >> n >> k, n || k) {
for (int i = 0; i < n; ++i) cin >> a[i];
for (int i = 0; i < n; ++i) cin >> b[i];
double l = 0, r = 100;
while (r - l > 1e-6) {
double mid = (l + r) / 2;
if (check(mid)) l = mid;
else r = mid;
}
cout << round(l) << '\n';
}
return 0;
}
魔法珠
int work (int x) {
if(sg[x] != -1) return sg[x];
vector<int> a(1, 1);
for (int i = 2; i <= x / i; ++i) if (x % i == 0) {
a.emplace_back(i);
if (i * i != x) a.emplace_back(x / i);
}
unordered_map<int, bool> v;
int cur = 0;
for (int i : a) cur ^= work(i);
for (int i : a) v[cur ^ work(i)] = 1;
while (v[++sg[x]]);
return sg[x];
}
int main() {
memset(sg, -1, sizeof sg); sg[1] = 0;
while (cin >> n) {
int c = 0;
for (int i = 0; i < n; ++i) cin >> m, c ^= work(m);
cout << (c ? "freda\n" : "rainbow\n");
}
return 0;
}
格鲁吉亚和鲍勃
int main() {
for (cin >> _; _; --_) {
cin >> n; m = 0;
for (int i = 1; i <= n; ++i) cin >> a[i];
sort(a + 1, a + 1 + n);
for (int i = n; i > 0;) m ^= (a[i--] - a[i--] - 1);
cout << (m ? "Georgia will win\n" : "Bob will win\n");
}
return 0;
}
数据结构进阶
并查集
⭐程序自动分析
int f[N << 1], x[N], y[N], z[N];
int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); }
void unit(int x, int y) { x = find(x); y = find(y); if (x != y) f[x] = y; }
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> m; VI c; bool g = 0;
rep (i, 1, m) cin >> x[i] >> y[i] >> z[i], c.pb(x[i]), c.pb(y[i]);
sort(all(c)); c.erase(unique(all(c)), c.end()); n = c.size();
rep (i, 1, n) f[i] = i, f[i + n] = i + n;
rep (i, 1, m) {
x[i] = lower_bound(all(c), x[i]) - c.begin() + 1;
y[i] = lower_bound(all(c), y[i]) - c.begin() + 1;
if (!z[i] && find(x[i]) == find(y[i])) g = 1;
else if (!z[i]) unit(x[i] + n, y[i] + n);
else if (find(x[i]) != find(y[i]) && find(x[i] + n) == find(y[i] + n)) g = 1;
else unit(x[i], y[i]), unit(x[i] + n, y[i] + n);
}
cout << (!g ? "YES\n" : "NO\n");
}
return 0;
}
银河英雄传说
int find(int x) {
if (x == f[x]) return x;
if (f[x] == f[f[x]]) return f[x];
int fa = find(f[x]); d[x] += d[f[x]] - 1;
return f[x] = fa;
}
void unit(int x, int y) {
x = find(x), y = find(y);
if (x != y) { d[y] = sz[x] + 1; sz[f[y] = x] += sz[y]; }
}
int main() {
for (int i = 1; i <= 3e4; ++i) f[i] = i, d[i] = sz[i] = 1;
for (cin >> _; _; --_) {
char op; int x, y; cin >> op >> x >> y;
if (op == 'M') unit(y, x);
else cout << (find(x) == find(y) ? abs(d[x] - d[y]) - 1 : -1) << '\n';
}
return 0;
}
奇偶游戏
int main() {
cin >> n >> m; vector<int> c;
for (int i = 0; i < m; ++i) cin >> x[i] >> y[i] >> op + i, c.push_back(--x[i]), c.push_back(y[i]);
sort(c.begin(), c.end()); c.erase(unique(c.begin(), c.end()), c.end()); n = c.size();
for (int i = 0; i < n; ++i) f[i] = i, f[i + n] = i + n;
for (int i = 0; i < m; ++i) {
x[i] = lower_bound(c.begin(), c.end(), x[i]) - c.begin();
y[i] = lower_bound(c.begin(), c.end(), y[i]) - c.begin();
if (op[i] == 'o') {
if (find(x[i]) == find(y[i])) return cout << i, 0;
unit(x[i], y[i] + n), unit(x[i] + n, y[i]);
} else {
if (find(x[i]) == find(y[i] + n)) return cout << i, 0;
unit(x[i], y[i]), unit(x[i] + n, y[i] + n);
}
}
return cout << m, 0;
}
食物链
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) f[i] = i, f[i + n] = i + n, f[i + n * 2] = i + 2 * n;
for (int i = 0; i < m; ++i) {
int x, y, op; cin >> op >> x >> y;
if (x > n || y > n) ++c;
else if (op == 1) {
if (find(x) == find(y + n) || find(x) == find(y + 2 * n)) ++c;
else unit(x, y), unit(x + n, y + n), unit(x + 2 * n, y + 2 * n);
} else {
if (find(x) == find(y) || find(x + n) == find(y)) ++c;
else unit(x, y + n), unit(x + n, y + 2 * n), unit(x + 2 * n, y);
}
}
cout << c;
return 0;
}
树状数组
楼兰图腾
void add(int x, int k) { for (; x <= n; x += x & -x) c[x] += k; }
int ask(int x) { int ans = 0; for (; x; x -= -x & x) ans += c[x]; return ans; }
int main() {
cin >> n;
for (int i = 0; i < n; ++i) {
int a, c; cin >> a; c = ask(a); add(a, 1);
x += c * (a - 1ll - c), y += (long long)(i - c) * (n - a - (i - c));
}
cout << y << ' ' << x;
一个简单的整数问题
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 1; i <= m; ++i) {
char op; int x, y, z; cin >> op >> x;
if (op == 'Q') cout << a[x] + ask(x) << '\n';
else cin >> y >> z, add(x, z), add(y + 1, -z);
}
return 0;
}
一个简单的整数问题2
ll c[2][N], a[N], sum[N], n, m, x, y, d;
char s[N];
void add(int x, ll k) { for (int i = x; i <= n; i += -i & i) c[0][i] += k, c[1][i] += x * k; }
ll ask(int x) {
ll p = 0, q = 0, f = x + 1;
for (; x; x -= -x & x) p += c[0][x], q += c[1][x];
return p * f - q;
}
ll ask(int l, int r) { return ask(r) - ask(l - 1); }
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++ i) cin >> a[i], add(i, a[i] - a[i - 1]);
while(m--) {
cin >> s >> x >> y;
if (s[0] == 'Q') cout << ask(y) - ask(x - 1) << '\n';
else cin >> d, add(x, d), add(y + 1, -d);
}
return 0;
}
谜一样的牛
int main() {
cin >> n;
for (int i = 2; i <= n; ++i) cin >> a[i], add(i, 1);
for (int i = n; i; --i) {
int len = 1, j = n;
while (len) len = ask(max(j - len, 1)) < a[i] ? len >> 1 : (j = max(j - len, 1), len << 1);
add(a[i] = j, -1);
}
for (int i = 1; i <= n; ++i) cout << a[i] << '\n';
return 0;
}
线段树
你能回答这些问题吗
#include <bits/stdc++.h>
using namespace std;
struct BIT {
static const int N = 5e5 + 5;
struct node { int val[4], l, r; } tr[N << 2];
void push_up(int rt) {
tr[rt].val[0] = max(tr[rt << 1].val[0], tr[rt << 1].val[2] + tr[rt << 1 | 1].val[0]);
tr[rt].val[1] = max(tr[rt << 1 | 1].val[1], tr[rt << 1 | 1].val[2] + tr[rt << 1].val[1]);
tr[rt].val[2] = tr[rt << 1].val[2] + tr[rt << 1 | 1].val[2];
tr[rt].val[3] = max(max(tr[rt << 1].val[3], tr[rt << 1 | 1].val[3]), tr[rt << 1 | 1].val[0] + tr[rt << 1].val[1]);
}
void build(int rt, int l, int r, int* a) {
tr[rt].l = l, tr[rt].r = r;
if (l == r) { tr[rt].val[0] = tr[rt].val[1] = tr[rt].val[2] = tr[rt].val[3] = a[l]; return; }
int mid = l + r >> 1; build(rt << 1, l, mid, a); build(rt << 1 | 1, mid + 1, r, a);
push_up(rt);
}
void change(int rt, int d, int k) {
if (tr[rt].l == d && tr[rt].r == d) { tr[rt].val[0] = tr[rt].val[1] = tr[rt].val[2] = tr[rt].val[3] = k; return; }
int mid = tr[rt].l + tr[rt].r >> 1;
if (d <= mid) change(rt << 1, d, k);
else if (d > mid) change(rt << 1 | 1, d, k);
push_up(rt);
}
node ask(int rt, int l, int r) {
if (tr[rt].l >= l && tr[rt].r <= r) return tr[rt];
int mid = tr[rt].l + tr[rt].r >> 1;
if (mid >= r) return ask(rt << 1, l, r);
if (mid < r && l > mid) return ask(rt << 1 | 1, l, r);
auto resb = ask(rt << 1 | 1, l, r), resa = ask(rt << 1, l, r); node ans;
ans.val[0] = max(resa.val[0], resa.val[2] + resb.val[0]);
ans.val[1] = max(resb.val[1], resb.val[2] + resa.val[1]);
ans.val[3] = max(max(resa.val[3], resb.val[3]), max(ans.val[0], ans.val[1]));
ans.val[3] = max(ans.val[3], resb.val[0] + resa.val[1]);
ans.val[2] = resa.val[2] + resb.val[2];
return ans;
}
} bit;
int a[500001], n, m;
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> a[i]; bit.build(1, 1, n, a);
for (int i = 0; i < m; ++i) {
int op, x, y; cin >> op >> x >> y;
if (op == 1) cout << bit.ask(1, min(x, y), max(x, y)).val[3] << '\n';
else bit.change(1, x, y);
}
return 0;
}
区间最大公约数
struct BIT {
static const int N = 5e5 + 5;
struct node {int l, r; long long val; } tr[2000005];
void push_up(int rt) { tr[rt].val = __gcd(tr[rt << 1].val, tr[rt << 1 | 1].val); }
void build(int rt, int l, int r, long long* a) {
tr[rt].l = l, tr[rt].r = r;
if (l == r) { tr[rt].val = a[l] - a[l - 1]; return; }
int mid = l + r >> 1;
build(rt << 1, l, mid, a); build(rt << 1 | 1, mid + 1, r, a);
push_up(rt);
}
void change(int rt, int d, long long k) {
if (d > tr[rt].r || d < tr[rt].l) return;
if (tr[rt].l == d && tr[rt].r == d) { tr[rt].val += k; return; }
int mid = tr[rt].l + tr[rt].r >> 1;
if (d <= mid) change(rt << 1, d, k);
else if (d > mid) change(rt << 1 | 1, d, k);
push_up(rt);
}
long long ask(int rt, int l, int r) {
if (tr[rt].l >= l && tr[rt].r <= r) return tr[rt].val;
int mid = tr[rt].l + tr[rt].r >> 1;
if (r <= mid) return ask(rt << 1 , l, r);
if (l > mid) return ask(rt << 1 | 1, l, r);
return __gcd(ask(rt << 1, l, r), ask(rt << 1 | 1, l, r));
}
} bit;
int n, m;
long long a[500005], d, c[500005];
void add(int x, long long k) { for (; x <= n; x += -x & x) c[x] += k; }
long long ask(int x) { long long ans = 0; for (; x; x -= -x & x) ans += c[x]; return ans; }
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> a[i]; bit.build(1, 1, n, a);
for (int i = 0; i < m; ++i) {
char op; int x, y; cin >> op >> x >> y;
if (op == 'C') cin >> d, bit.change(1, x, d), bit.change(1, y + 1, -d), add(x, d), add(y + 1, -d);
else cout << (x < y ? abs(__gcd(bit.ask(1, x + 1, y), a[x] + ask(x))) : a[x] + ask(x)) << '\n';
}
return 0;
}
亚特兰蒂斯
struct BIT {
struct Node { int l, r, cnt; double len, val; } tr[160005];
void push_up(int rt) { tr[rt].val = tr[rt].cnt ? tr[rt].val = tr[rt].len : tr[rt << 1].val + tr[rt << 1 | 1].val; }
void build(int rt, int l, int r, vector<double>& a) {
tr[rt] = { l, r, 0, a[r] - a[l], 0.0 };
if (l + 1 == r) return;
int mid = l + r >> 1;
build(rt << 1, l, mid, a); build(rt << 1 | 1, mid, r, a);
}
void change(int rt, int l, int r, int k) {
if (tr[rt].l >= l && tr[rt].r <= r) { tr[rt].cnt += k; push_up(rt); return; }
int mid = tr[rt].l + tr[rt].r >> 1;
if (mid > l) change(rt << 1, l, r, k);
if (mid < r) change(rt << 1 | 1, l, r, k);
push_up(rt);
}
} bit;
int n, _, cas;
vector<double> x;
struct line { double x1, x2, y; int k; } a[20000];
int getId(double a) { return lower_bound(x.begin(), x.end(), a) - x.begin(); }
int main() {
while (cin >> n, n) {
vector<double>(1, -1.0).swap(x); double ans = 0;
for (int i = 0; i < n; ++i) {
double x1, x2, y1, y2; cin >> x1 >> y1 >> x2 >> y2; x.push_back(x1); x.push_back(x2);
a[i << 1] = { x1, x2, y1, 1}, a[i << 1 | 1] = { x1, x2, y2, -1 };
}
sort(x.begin(), x.end()); x.erase(unique(x.begin(), x.end()), x.end());
sort(a, a + n * 2, [](line& a, line& b) { return a.y == b.y ? a.k > b.k : a.y < b.y; });
bit.build(1, 1, x.size() - 1, x); bit.change(1, getId(a[0].x1), getId(a[0].x2), 1);
for (int i = 1; i < n << 1; ++i) {
ans += bit.tr[1].val * (a[i].y - a[i - 1].y);
bit.change(1, getId(a[i].x1), getId(a[i].x2), a[i].k);
}
cout << "Test case #" << ++cas << "\nTotal explored area: " << setiosflags(ios::fixed) << setprecision(2) << ans << "\n\n";
}
return 0;
}
⭐窗内的星星
struct BIT {
struct Node { long long l, r, mx, val; } tr[80005];
void push_up(int rt) { tr[rt].mx = max(tr[rt << 1].mx, tr[rt << 1 | 1].mx) + tr[rt].val; }
void build(int rt, long long l, long long r, vector<long long>& a) {
tr[rt] = { a[l], a[r], 0, 0 };
if (l == r) return;
int mid = l + r >> 1;
build(rt << 1, l, mid, a); build(rt << 1 | 1, mid + 1, r, a);
}
void change(int rt, long long l, long long r, long long k) {
if (tr[rt].l >= l && tr[rt].r <= r) { tr[rt].mx += k, tr[rt].val += k; return; }
if (l <= tr[rt << 1].r) change(rt << 1, l, r, k);
if (r >= tr[rt << 1 | 1].l) change(rt << 1 | 1, l, r, k);
push_up(rt);
}
} bit;
int n, W, H, _, cas;
vector<long long> c;
struct line { long long x1, x2, y, k; } a[20000];
int main() {
while (cin >> n >> W >> H) {
vector<long long>(1, -1).swap(c); long long ans = 0;
for (int i = 0; i < n; ++i) {
long long x, y, z; cin >> x >> y >> z; c.push_back(x); c.push_back(x + W - 1);
a[i << 1] = { x, x + W - 1, y, z }, a[i << 1 | 1] = { x, x + W - 1, y + H - 1, -z };
}
sort(c.begin(), c.end()); c.erase(unique(c.begin(), c.end()), c.end());
sort(a, a + n * 2, [](line& a, line& b) { return a.y == b.y ? a.k > b.k : a.y < b.y; });
bit.build(1, 1, c.size() - 1, c);
for (int i = 0; i < n << 1; ++i) {
bit.change(1, a[i].x1, a[i].x2, a[i].k);
ans = max(ans, bit.tr[1].mx);
}
cout << ans << '\n';
}
return 0;
}
分块
蒲公英
int a[N], idx[N], x, tax[N];
vector<int> c(1, -1), b[N];
void init() {
sort(c.begin(), c.end()); c.erase(unique(c.begin(), c.end()), c.end());
sz = pow(m * n * log2(n), 1.0 / 3); len = (n - 1) / sz + 1;
for(int i=1;i<=n;++i) idx[i]=(i-1)/len+1,b[a[i]=lower_bound(c.begin(),c.end(),a[i])-c.begin()].push_back(i);
for (int i = 1; i < c.size(); ++i) b[i].push_back(n + 1);
for (int i = 1, res = a[1]; i <= sz; res = a[i++ * len + 1], memset(tax, 0, sizeof tax))
for (int j = (i - 1) * len + 1; j <= n; ++j) {
if (++tax[a[j]] > tax[res]) res = a[j];
else if (tax[a[j]] == tax[res]) res = min(res, a[j]);
if (j % len == 0 || j == n) f[i][idx[j]] = res, d[i][idx[j]] = tax[res];
}
}
int get(int l, int r, int k) { return upper_bound(b[k].begin(), b[k].end(), r) - lower_bound(b[k].begin(), b[k].end(), l); }
long long solve(long long cnt, int l, int r, int L, int R) {
for (int i = l; i <= r; ++i) if (x != a[i] || i == l) {
int res = get(L, R, a[i]);
if (res > cnt) cnt = res, x = a[i];
else if (res == cnt) x = min(x, a[i]);
}
return cnt;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> a[i], c.push_back(a[i]);
init(); long long ls = 0;
for (int i = 0; i < m; ++i) {
int l, r; cin >> l >> r; l = (l + ls - 1) % n + 1, r = (r + ls - 1) % n + 1;
if (l > r) swap(l, r); x = a[l];
int L = idx[l] + ((l - 1) % len != 0), R = idx[r] - (r % len && r != n);
if (L > R) { solve(0, l, r, l, r); cout << (ls = c[x]) << '\n'; continue; }
x = f[L][R]; L = (L - 1) * len + 1, R = R * len;
solve(solve(get(l, r, x), l, L - 1, l, r), R + 1, r, l, r);
cout << (ls = c[x]) << '\n';
}
return 0;
}
⭐磁力块
struct node { ll p, m, d, r; } a[250001];
int n, m, sz, len, h[505], mx[505];
bool v[250005];
ll x, y;
long long dist(pair<ll, ll> a, pair<ll, ll> b) {
return (a.first - b.first) * (a.first - b.first) + (a.second - b.second) * (a.second - b.second);
}
int main() {
cin >> x >> y >> a[0].p >> a[0].r >> n; a[0].r *= a[0].r;
for (int i = 1; i <= n; ++i) {
ll c, d; cin >> c >> d >> a[i].m >> a[i].p >> a[i].r;
a[i].d = dist({ x, y }, { c, d }); a[i].r *= a[i].r;
}
sort(a + 1, a + 1 + n, [](node& a, node& b) { return a.m < b.m; });
sz = sqrt(n); len = (n - 1) / sz + 1;
for (int i = 1; i <= sz; ++i) {
mx[i] = a[min(n, i * len)].m, h[i] = (i - 1) * len + 1;
sort(a + h[i], a + min(i * len, n) + 1, [](node& a, node& b) { return a.d < b.d; });
}
stack<int> st; st.push(0);
while (!st.empty()) {
int x = st.top(), l = 1; st.pop();
for (; l <= sz && a[x].p >= mx[l]; ++l) for (; h[l] <= min(l * len, n); ++h[l]) if (!v[h[l]])
if (a[h[l]].d <= a[x].r) st.push(h[l]), ++m; else break;
if (l <= sz) for (int i = h[l]; i <= min(l * len, n); ++i) if (!v[i])
if (a[i].d <= a[x].r && a[i].m <= a[x].p) v[i] = 1, st.push(i), ++m;
}
cout << m;
return 0;
}
小Z的袜子
struct node { int l, r, id, p, f; } q[N];
int t, len, n, m, a[N], b[N], d[N], c[N] = {1};
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 1; i <= m; ++i) {
cin >> q[i].l >> q[i].r; q[i].id = i;
q[i].p = (q[i].r - q[i].l + 1ll) * (q[i].r - q[i].l) >> 1;
}
len = sqrt(n); t = (n - 1) / len + 1;
sort(q + 1, q + 1 + m, [](node& a, node& b) { return a.l < b.l; });
for (int i = b[1] = d[1] = 1; i <= t && b[i] <= m; ++i, d[i] = b[i] = d[i - 1] + 1) {
while (d[i] < m && q[d[i] + 1].l <= i * len) ++d[i];
sort(q + b[i], q + d[i] + 1, [](node& a, node& b) { return a.r < b.r; });
}
for (int i = 1, l = 0, r = 0, cur = 0; d[i - 1] < m; ++i) for (int j = b[i]; j <= d[i]; ++j) {
while (r < q[j].r) { cur += c[a[++r]]; ++c[a[r]]; }
while (l > q[j].l) { cur += c[a[--l]]; ++c[a[l]]; }
while (r > q[j].r) { --c[a[r]]; cur -= c[a[r--]]; }
while (l < q[j].l) { --c[a[l]]; cur -= c[a[l++]]; }
if (!cur) q[j].p = 1;
else { q[j].f = __gcd(q[j].p, cur); q[j].p /= q[j].f, q[j].f = cur / q[j].f; }
}
sort(q + 1, q + 1 + m, [](node& a, node& b) { return a.id < b.id; });
for (int i = 1; i <= m; ++i) cout << q[i].f << '/' << q[i].p << '\n';
return 0;
}
点分治
树
void add(int u, int v, int c) {
ne[++tot] = h[u]; to[h[u] = tot] = v; co[tot] = c;
}
void dfsct(int x, int f) {
siz[x] = 1;
int mx = 0;
for (int i = h[x]; i; i = ne[i]) {
int y = to[i];
if (v[y] || y == f) continue;
dfsct(y, x);
siz[x] += siz[y];
umax(mx, siz[y]);
}
umax(mx, sum - siz[x]);
if (mx < mxsz) mxsz = mx, root = x;
}
void dfs(int x, int f, int id) {
q[++tail] = { d[x], b[x] = id };
for (int i = h[x]; i; i = ne[i]) {
int y = to[i];
if (y == f || v[y]) continue;
d[y] = d[x] + co[i];
dfs(y, x, id == root ? y : id);
}
}
void work(int x) {
dfsct(x, 0); v[x] = 1;
tail = 0, d[x] = 0; dfs(x, 0, x);
sort(q + 1, q + 1 + tail);
for (int l = 1, r = 1, sum; l <= tail; --s[q[++l].se]) {
while (r < tail && q[l].fi + q[r + 1].fi <= k) ++s[q[++r].se];
while (r > l && q[l].fi + q[r].fi > k) --s[q[r--].se];
if (r <= l) { ++s[q[++r].se]; continue; }
ans += r - l - s[q[l].se];
}
for (int i = h[x]; i; i = ne[i]) if (!v[to[i]]) {
sum = siz[to[i]]; mxsz = n + 1;
dfsct(to[i], -1); work(root);
}
}
int main() {
IOS;
while (cin >> n >> k, n & k) {
rep(i, 1, n) h[i] = v[i] = 0; tot = ans = 0;
rep(i, 2, n) {
int u, v, c; cin >> u >> v >> c;
++u, ++v; add(u, v, c); add(v, u, c);
}
sum = n; mxsz = n + 1;
dfsct(1, -1); work(root);
cout << ans << '\n';
}
return 0;
}
平衡树
普通平衡树
struct FHQ {
static const int N = 1e5 + 5;
struct Node {
int ch[2], val, pri, siz;
Node (int S = 0, int V = 0, int P = 0, int l = 0, int r = 0) :
siz(S), val(V), pri(P) { ch[0] = l, ch[1] = r; }
int& operator [](const int k) { return ch[k]; }
} tr[N];
FHQ() { srand((unsigned)time(NULL)); }
int tot, x, y, z, root;
int newNode (int v) { tr[++tot] = Node(1, v, rand()); return tot; }
void update(int x) { tr[x].siz = 1 + tr[tr[x][0]].siz + tr[tr[x][1]].siz; }
int merge(int x, int y) {
if (!x || !y) return x + y;
if (tr[x].pri < tr[y].pri) { tr[x][1] = merge(tr[x][1], y); update(x); return x; }
else { tr[y][0] = merge(x, tr[y][0]); update(y); return y; }
}
void split_v(int p, int k, int &x, int& y) {
if (!p) x = y = 0;
else {
if (tr[p].val <= k) x = p, split_v(tr[p][1], k, tr[p][1], y);
else y = p, split_v(tr[p][0], k, x, tr[p][0]);
update(p);
}
}
int kth(int p, int k) {
while (1) {
if (k <= tr[tr[p][0]].siz) p = tr[p][0];
else if (k == tr[tr[p][0]].siz + 1) return p;
else k -= tr[tr[p][0]].siz + 1, p = tr[p][1];
}
}
int getrk(int val) {
split_v(root, val - 1, x, y);
int ans = tr[x].siz + 1;
return root = merge(x, y), ans;
}
void add_v(int pos, int val) {
split_v(root, pos, x, y);
root = merge(merge(x, newNode(val)), y);
}
void del_v(int val) {
split_v(root, val, x, z);
split_v(x, val - 1, x, y);
y = merge(tr[y][0], tr[y][1]);
root = merge(merge(x, y), z);
}
int pre(int val) {
split_v(root, val - 1, x, y);
int ans = tr[kth(x, tr[x].siz)].val;
return root = merge(x, y), ans;
}
int nxt(int val) {
split_v(root, val, x, y);
int ans = tr[kth(y, 1)].val;
return root = merge(x, y), ans;
}
} T;
const int N = 1e5 + 5;
int n, m, _, k;
int main() {
IOS; cin >> n;
for (int i = 1; i <= n; ++i) {
int op, x; cin >> op >> x;
switch (op) {
case 1: T.add_v(x - 1, x); break;
case 2: T.del_v(x); break;
case 3: cout << T.getrk(x) << '\n'; break;
case 4: cout << T.tr[T.kth(T.root, x)].val << '\n'; break;
case 5: cout << T.pre(x) << '\n'; break;
case 6: cout << T.nxt(x) << '\n'; break;
default: break;
}
}
return 0;
}
离线分治算法
天使玩偶
int tot, ans[N << 1], c[M], mxx, mxy;
struct node { int op, x, y, t; } q[N << 1], a[N << 1], b[N << 1];
void add(int x, int k) { for (; x <= mxy; x += -x & x) c[x] = max(c[x], k); }
int ask(int x) { int ans = -1e7; for (; x; x -= -x & x) ans = max(ans, c[x]); return ans; }
void cl(int x) { for (; x <= mxy; x += -x & x) c[x] = -1e7; }
void init(int k) {
int x = 0, y = 0; tot = 0;
for (int i = 1; i <= n + m; ++i) {
if (k == 1) q[i].x = mxx - q[i].x + 1;
else if (k == 2) q[i].y = mxy - q[i].y + 1;
if (q[i].op == 2) x = max(x, q[i].x), y = max(y, q[i].y);
}
for (int i = 1; i <= n + m; ++i) if (q[i].x <= x && q[i].y <= y) a[++tot] = q[i];
}
void cdq(int l, int r) {
if (l == r) return;
int mid = l + r >> 1;
cdq(l, mid); cdq(mid + 1, r);
int x = l, y = mid + 1, z = l;
for (; y <= r; b[z++] = a[y++]) {
for (; x <= mid && a[x].x <= a[y].x; b[z++] = a[x++])
if (a[x].op == 1) add(a[x].y, a[x].x + a[x].y);
if (a[y].op == 2) ans[a[y].t] = min(ans[a[y].t], a[y].y + a[y].x - ask(a[y].y));
}
for (int i = l; i < x; ++i) if (a[i].op == 1) cl(a[i].y);
for (; x <= mid || y <= r;) {
if (y > r) while (x <= mid) b[z++] = a[x++];
else if (x > mid) while (y <= r) b[z++] = a[y++];
else if (a[x].x <= a[y].x) b[z++] = a[x++];
else b[z++] = a[y++];
}
for (int i = l; i <= r; ++i) a[i] = b[i];
}
int main() {
cin >> n >> m; vector<int> idx;
for (int i = 1; i <= n; ++i) {
cin >> q[i].x >> q[i].y, q[i].t = i; q[i].op = 1;
mxx = max(mxx, ++q[i].x); mxy = max(mxy, ++q[i].y);
}
for (int i = n + 1; i <= n + m; ++i) {
cin >> q[i].op >> q[i].x >> q[i].y; q[i].t = i;
mxx = max(mxx, ++q[i].x); mxy = max(mxy, ++q[i].y);
if (q[i].op == 2) idx.push_back(q[i].t), ans[i] = 1e7;
}
for (int i = 1; i <= mxy; ++i) c[i] = -1e7;
init(0); cdq(1, tot); init(1); cdq(1, tot);
init(2); cdq(1, tot); init(1); cdq(1, tot);
for (auto i : idx) cout << ans[i] << '\n';
return 0;
}
第K个数
struct CRBIT {
struct node { int l, r, val; } tr[N * 20];
int rt[N], tot;
void update(int& x, int y, int l, int r, int d) {
tr[x = ++tot] = tr[y]; ++tr[x].val;
if (l == r) return;
int mid = l + r >> 1;
if (d <= mid) update(tr[x].l, tr[y].l, l, mid, d);
if (d > mid) update(tr[x].r, tr[y].r, mid + 1, r, d);
}
int ask(int x, int y, int l, int r, int k) {
if (l == r) return l;
int val = tr[tr[x].l].val - tr[tr[y].l].val, mid = l + r >> 1;
if (val < k) return ask(tr[x].r, tr[y].r, mid + 1, r, k - val);
return ask(tr[x].l, tr[y].l, l, mid, k);
}
} bit;
int n, m, a[N];
int main() {
cin >> n >> m; vector<int> c;
for (int i = 1; i <= n; ++i) cin >> a[i], c.push_back(a[i]);
sort(c.begin(), c.end()); c.erase(unique(c.begin(), c.end()), c.end());
for (int i = 1; i <= n; ++i)
bit.update(bit.rt[i], bit.rt[i - 1], 1, c.size(), lower_bound(c.begin(), c.end(), a[i]) - c.begin() + 1);
for (int i = 1; i <= m; ++i) {
int l, r, k; cin >> l >> r >> k;
cout << c[bit.ask(bit.rt[r], bit.rt[l - 1], 1, c.size(), k) - 1] << '\n';
}
return 0;
}
可持久化数据结构
最大异或和
struct SustainableTrie {
struct node {
int son[2], cnt;
int& operator [](const int x) { return son[x]; }
} tr[N * M << 1];
int root[N << 1], tot;
void insert(int& x, int y, int k) {
int p = x = ++tot; tr[p] = tr[y];
for (int i = M; ~i; --i) {
int ch = k >> i & 1;
tr[p = tr[p][ch] = ++tot] = tr[y = tr[y][ch]];
++tr[p].cnt;
}
}
int ask(int x, int y, int k) {
int ans = 0;
for (int i = M; ~i; --i) {
int ch = k >> i & 1;
if (tr[tr[x][!ch]].cnt - tr[tr[y][!ch]].cnt)
ans ^= 1 << i, ch = !ch;
x = tr[x][ch], y = tr[y][ch];
} return ans;
}
} trie;
int n, m, _, k, s;
int main() {
IOS; cin >> n >> m; ++k, trie.insert(trie.root[k], trie.root[0], 0);
for (int i = 1; i <= n; ++i) cin >> _, ++k, trie.insert(trie.root[k], trie.root[k - 1], s ^= _);
for (int i = 1; i <= m; ++i) {
char op[2]; cin >> op;
if (op[0] == 'A') cin>>_,++k,trie.insert(trie.root[k],trie.root[k - 1],s^=_);
else {
int l, r, x; cin >> l >> r >> x;
cout << trie.ask(trie.root[r], trie.root[l - 1], x ^ s) << '\n';
}
} return 0;
}
总结与练习
关押罪犯
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) f[i] = i, f[i + n] = i + n;
for (int i = 1; i <= m; ++i) cin >> p[i].second.first >> p[i].second.second >> p[i].first;
sort(p + 1, p + 1 + m);
for (int i = m; i; --i) {
int x = p[i].second.first, y = p[i].second.second;
if (find(x) == find(y)) return cout << p[i].first, 0;
unit(x, y + n), unit(x + n, y);
}
return cout << 0, 0;
}
石头剪子布
int main() {
while (cin >> n >> m) {
int ans = n, res = 0, cnt = 0;
for (int i = 1; i <= m; ++i) cin >> a[i] >> c[i] >> b[i];
for (int k = 0; k < n; ++k) {
for (int i = 0; i < n; ++i) f[i] = i, f[i + n] = i + n, f[i + n * 2] = i + n * 2;
for (int i = 1; i <= m; ++i) {
if (a[i] == k || b[i] == k) continue;
if (c[i] == '=')
if (find(a[i]) == find(b[i] + n) || find(a[i]) == find(b[i] + n * 2)) {
--ans, res = max(res, i);
break;
}
else unit(a[i], b[i]), unit(a[i] + n, b[i] + n), unit(a[i] + n * 2, b[i] + n * 2);
else if (c[i] == '>')
if (find(a[i]) == find(b[i]) || find(a[i]) == find(b[i] + n)) {
--ans, res = max(res, i);
break;
}
else unit(a[i], b[i] + n * 2), unit(a[i] + n, b[i]), unit(a[i] + n * 2, b[i] + n);
else
if (find(a[i]) == find(b[i]) || find(a[i]) == find(b[i] + n * 2)) {
--ans, res = max(res, i);
break;
}
else unit(a[i], b[i] + n), unit(a[i] + n, b[i] + n * 2), unit(a[i] + n * 2, b[i]);
if (i == m) cnt = k;
}
}
if (!ans) cout << "Impossible\n";
else if (ans != 1) cout << "Can not determine\n";
else cout << "Player " << cnt << " can be determined to be the judge after " << res << " lines\n";
}
return 0;
}
真正的骗子
int main() {
while (cin >> n >> p1 >> p2, n || p1 || p2) {
bool g = 0;
for (int i = 1; i <= p1 + p2; ++i) f[i] = i, f[i + p1 + p2] = i + p1 + p2, sz[i] = 1, sz[i + p1 + p2] = 0;
for (int i = 0; i < n; ++i) {
int x, y; char s[5]; cin >> x >> y >> s;
if (s[0] == 'n')
if (find(x) == find(y)) g = 1;
else unit(x, y + p1 + p2), unit(x + p1 + p2, y);
else
if (find(x) == find(y + p1 + p2)) g = 1;
else unit(x, y), unit(x + p1 + p2, y + p1 + p2);
}
vector<pair<int, pair<int, int>>> a(1); vector<unordered_set<int>> st(1); st[0].insert(0);
for (int i = 1; i <= p1 + p2; ++i) if (f[i] == i) {
a.push_back({ i, {sz[i], sz[find(i + p1 + p2)]} }); st.push_back(unordered_set<int>());
for (auto b : st[st.size() - 2]) st.back().insert(b + sz[i]), st.back().insert(b + sz[find(i + p1 + p2)]);
}
unordered_set<int> ans;
for (int i = a.size() - 1, res = p1; i; --i)
if (st[i - 1].count(res - a[i].second.first) && st[i - 1].count(res - a[i].second.second)) { g = 1; break; }
else if (st[i - 1].count(res - a[i].second.first)) ans.insert(a[i].first), res -= a[i].second.first;
else ans.insert(a[i].first + p1 + p2), res -= a[i].second.second;
if (!st.back().count(p1) || g) { cout << "no\n"; continue; }
for (int i = 1; i <= p1 + p2; ++i) if (ans.count(find(i))) cout << i << '\n'; cout << "end\n";
}
return 0;
}
买票
void add(int x, int k) { for (; x <= n; x += -x & x) c[x] += k; }
int ask(int x) { int ans = 0; for (; x; x -= -x & x) ans += c[x]; return ans; }
int main () {
while (cin >> n) {
memset(c, 0, sizeof c);
for (int i = 1; i <= n; ++i) cin >> a[i].first >> a[i].second, ++a[i].first, add(i, 1);
for (int i = n, l = 1, r = n; i; --i, l = 1, r = n) {
while (l < r) {
int mid = l + r >> 1;
if (ask(mid) >= a[i].first) r = mid;
else l = mid + 1;
}
rk[l] = a[i].second; add(l, -1);
}
for (int i = 1; i <= n; ++i) cout << rk[i] << ' '; cout << '\n';
}
return 0;
}
旅馆
struct BIT {
static const int N = 5e4 + 5;
struct node { int val[4], l, r, len, tag; } tr[N << 2];
void push_up(int rt) {
tr[rt].val[0] = tr[rt << 1].val[0] + (tr[rt << 1].val[0] ^ tr[rt << 1].len ? 0 : tr[rt << 1 | 1].val[0]);
tr[rt].val[1] = tr[rt << 1 | 1].val[1] + (tr[rt << 1 | 1].val[1] ^ tr[rt << 1 | 1].len ? 0 : tr[rt << 1].val[1]);
if (tr[rt << 1].val[1] && tr[rt << 1 | 1].val[0]) tr[rt].val[2] = tr[rt << 1].val[1] + tr[rt << 1 | 1].val[0];
else tr[rt].val[2] = 0;
tr[rt].val[3] = max(max(tr[rt << 1].val[3], tr[rt << 1 | 1].val[3]), tr[rt].val[2]);
}
void push_down(int rt) {
if (!tr[rt].tag) return;
if (tr[rt].tag == -1) for (int i = 0; i < 4; ++i) tr[rt << 1].val[i] = tr[rt << 1 | 1].val[i] = 0;
else for (int i = 0; i < 4; ++i) tr[rt << 1].val[i] = tr[rt << 1].len, tr[rt << 1 | 1].val[i] = tr[rt << 1 | 1].len;
tr[rt << 1 | 1].tag = tr[rt << 1].tag = tr[rt].tag; tr[rt].tag = 0;
}
void build(int rt, int l, int r) {
tr[rt].l = l, tr[rt].r = r, tr[rt].len = r - l + 1;
if (l == r) { tr[rt].val[0] = tr[rt].val[1] = tr[rt].val[2] = tr[rt].val[3] = 1; return; }
int mid = l + r >> 1; build(rt << 1, l, mid); build(rt << 1 | 1, mid + 1, r);
push_up(rt);
}
void change(int rt, int l, int r, int k) {
if (tr[rt].l >= l && tr[rt].r <= r) {
if (k == -1) for (int i = 0; i < 4; ++i) tr[rt].val[i] = 0;
else for (int i = 0; i < 4; ++i) tr[rt].val[i] = tr[rt].len;
tr[rt].tag = k; return;
}
push_down(rt);
int mid = tr[rt].l + tr[rt].r >> 1;
if (l <= mid) change(rt << 1, l, r, k);
if (r > mid) change(rt << 1 | 1, l, r, k);
push_up(rt);
}
int ask(int rt, int len) {
if (tr[rt].val[3] < len) return 0;
if (tr[rt].val[0] >= len) return tr[rt].l;
push_down(rt); int ans = 0;
if (tr[rt << 1].val[3] >= len) ans = ask(rt << 1, len);
else if (tr[rt].val[2] >= len) ans = tr[rt << 1].r - tr[rt << 1].val[1] + 1;
else ans = ask(rt << 1 | 1, len);
push_up(rt); return ans;
}
} bit;
int n, m;
int main() {
cin >> n >> m; bit.build(1, 1, n);
for (int i = 0; i < m; ++i) {
int op, x, y; cin >> op >> x;
if (op == 1) {
int ans = bit.ask(1, x); cout << ans << '\n';
if (ans) bit.change(1, ans, ans + x - 1, -1);
}
else cin >> y, bit.change(1, x, y + x - 1, 1);
}
return 0;
}
海报
struct BIT {
static const int N = 1e4 + 5;
struct node { int l, r, len, cnt, tag, val[2]; } tr[N << 2];
void push(int rt) {
if (tr[rt].tag) tr[rt].val[0] = tr[rt].val[1] = tr[rt].len, tr[rt].cnt = 1;
else if (tr[rt].l + 1 == tr[rt].r) tr[rt].val[0] = tr[rt].val[1] = 0, tr[rt].cnt = 0;
else {
tr[rt].cnt = tr[rt << 1].cnt + tr[rt << 1 | 1].cnt - (tr[rt << 1].val[1] && tr[rt << 1 | 1].val[0] ? 1 : 0);
tr[rt].val[0] = tr[rt << 1].val[0] + (tr[rt << 1].val[0] ^ tr[rt << 1].len ? 0 : tr[rt << 1 | 1].val[0]);
tr[rt].val[1] = tr[rt << 1 | 1].val[1] + (tr[rt << 1 | 1].val[1] ^ tr[rt << 1 | 1].len ? 0 : tr[rt << 1].val[1]);
}
}
void build(int rt, int l, int r, vector<int>& a) {
tr[rt].l = l, tr[rt].r = r, tr[rt].len = a[r] - a[l];
if (l + 1 == r) return;
int mid = l + r >> 1; build(rt << 1, l, mid, a); build(rt << 1 | 1, mid, r, a);
}
void change(int rt, int l, int r, int k) {
if (tr[rt].l >= l && tr[rt].r <= r) { tr[rt].tag += k; push(rt); return; }
int mid = tr[rt].l + tr[rt].r >> 1;
if (l < mid) change(rt << 1, l, r, k);
if (r > mid) change(rt << 1 | 1, l, r, k);
push(rt);
}
} bit;
struct line { int y, a, b, k; } a[10005];
int n, x[10000], y[10000];
long long work(int x[], int y[]) {
vector<int> c; c.push_back(-2e9);
for (int i = 0; i < n; ++i) {
a[i << 1] = { y[i << 1], x[i << 1], x[i << 1 | 1], 1 };
a[i << 1 | 1] = { y[i << 1 | 1], x[i << 1], x[i << 1 | 1], -1 };
c.push_back(x[i << 1]); c.push_back(x[i << 1 | 1]);
}
sort(c.begin(), c.end()); c.erase(unique(c.begin(), c.end()), c.end());
sort(a, a + n * 2, [](line& a, line& b) { return a.y ^ b.y ? a.y < b.y : a.k > b.k; });
long long ans = 0; bit.build(1, 1, c.size() - 1, c);
bit.change(1, lower_bound(c.begin(), c.end(), a[0].a) - c.begin(), lower_bound(c.begin(), c.end(), a[0].b) - c.begin(), a[0].k);
for (int i = 1; i < n << 1; ++i) {
ans += (long long)bit.tr[1].cnt * (a[i].y - a[i - 1].y) << 1;
bit.change(1, lower_bound(c.begin(), c.end(), a[i].a) - c.begin(), lower_bound(c.begin(), c.end(), a[i].b) - c.begin(), a[i].k);
}
return ans;
}
int main() {
cin >> n;
for (int i = 0; i < n; ++i) cin >> x[i << 1] >> y[i << 1] >> x[i << 1 | 1] >> y[i << 1 | 1];
cout << work(x, y) + work(y, x);
return 0;
}
作诗
int n, m, k, cnt[M][N], val[M][M], t, len, a[N], id[N];
vector<int> c;
void init() {
for (int i = 1; i <= n; ++i) cin >> a[i], c.push_back(a[i]);
sort(all(c)); c.erase(unique(all(c)), c.end());
t = pow(n, 1.0 / 3); len = (n - 1) / t + 1; t = (n - 1) / len + 1;
for (int i = 1; i <= n; ++i) a[i] = lower_bound(all(c), a[i]) - c.begin(), id[i] = (i - 1) / len + 1;
for (int i = t, res = 0; i; --i, res = 0) {
for (int j = min(n, i * len); j; --j) {
++cnt[i][a[j]];
if ((cnt[i][a[j]] & 1) && cnt[i][a[j]] - 1) --res;
else if (cnt[i][a[j]] - 1) ++res;
if (j % len == 1) val[id[j]][i] = res;
}
}
}
int work(int l, int L, int R, int r) {
int ans = val[id[L]][id[R]];
for (int i = l; i < L; ++i) {
++cnt[id[L] - 1][a[i]];
if (cnt[id[R]][a[i]] - cnt[id[L] - 1][a[i]] & 1) --ans;
else if (cnt[id[R]][a[i]] - cnt[id[L] - 1][a[i]]) ++ans;
}
for (int i = r; i > R; --i) {
--cnt[id[R]][a[i]];
if (cnt[id[R]][a[i]] - cnt[id[L] - 1][a[i]] & 1) --ans;
else if (cnt[id[R]][a[i]] - cnt[id[L] - 1][a[i]]) ++ans;
}
for (int i = l; i < L; ++i) --cnt[id[L] - 1][a[i]];
for (int i = r; i > R; --i) ++cnt[id[R]][a[i]];
return ans;
}
int main() {
IOS; cin >> n >> k >> m; init();
for (int i = 0, ls = 0; i < m; ++i) {
int l, r; cin >> l >> r; l = (l + ls) % n + 1, r = (r + ls) % n + 1;
if (l > r) swap(l, r);
cout << (ls = work((id[l] - 1) * len + 1, l, r, min(id[r] * len, n))) << '\n';
}
return 0;
}
权值
int n, k, gra, sz[N], mxsz, q[N], f[N], ans;
bool v[N];
pair<int, int> dis[N];
vector<pair<int, int>> h[N];
void gravity(int x, int fa, int s) {
sz[x] = 1; int mx = 0;
for (auto& y : h[x]) if (y.first != fa && !v[y.first]) {
gravity(y.first, x, s); sz[x] += sz[y.first];
mx = max(mx, sz[y.first]);
}
if ((mx = max(mx, s - sz[x])) < mxsz) gra = x, mxsz = mx;
}
void dfs(int x, int fa, int id, int& tail) {
for (auto& y : h[x]) if (y.first != fa && !v[y.first]) {
f[y.first] = id; dis[q[++tail] = y.first].second = dis[x].second + 1;
dis[y.first].first = dis[x].first + y.second;
if (dis[y.first].first < k) dfs(y.first, x, id, tail);
}
}
void work(int x) {
int tail = 0; dis[x] = { 0, 0 }; q[++tail] = x; v[f[x] = x] = 1;
/*for (auto& y : h[x]) if (!v[y.first] && y.second <= k)
dis[q[++tail] = y.first] = { y.second, 1 }, dfs(y.first, x, f[y.first] = y.first, tail);
sort(q + 1, q + tail + 1, [&](int a, int b) { return dis[a] < dis[b]; });
for (int l = 1, r = 1; l <= tail; ++l) {
while (l < r - 1 && dis[q[l]].first + dis[q[r - 1]].first >= k) --r;
while (r < tail && dis[q[l]].first + dis[q[r]].first < k) ++r;
for (; r <= tail && dis[q[l]].first + dis[q[r]].first == k; ++r)
if (f[q[l]] ^ f[q[r]]) ans = min(ans, dis[q[l]].second + dis[q[r]].second);
}*/
unordered_map<int, int> st; st[0] = 0;//st可换成桶,循环完把更新过的位置重新设max即可
for (auto& y : h[x]) if (!v[y.first] && y.second <= k) {
dis[q[++tail] = y.first] = { y.second, 1 }; q[tail = 1] = y.first;
dfs(y.first, x, f[y.first] = y.first, tail);
for (int i = 1; i <= tail; ++i) if (st.count(k - dis[q[i]].first))
ans = min(ans, st[k - dis[q[i]].first] + dis[q[i]].second);
for (int i = 1; i <= tail; ++i) {
auto it = st.find(dis[q[i]].first);
if (it == st.end()) st.insert(dis[q[i]]);
else it->second = min(it->second, dis[q[i]].second);
}
}
gravity(x, -1, n); mxsz = n;
for (auto& y : h[x]) if (!v[y.first]) gravity(y.first, -1, sz[y.first]), work(gra), mxsz = n;
}
int main() {
IOS; cin >> n >> k; mxsz = ans = n;
for (int i = 1; i < n; ++i) {
int u, v, c; cin >> u >> v >> c;
h[u].push_back({ v, c }); h[v].push_back({ u, c });
}
gravity(0, -1, n); work(gra); cout << (ans ^ n ? ans : -1);
return 0;
}
营业额统计
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(0); cin.tie(0);
long long ans;
int n; cin >> n >> ans;
set<int> st; st.insert(ans);
st.insert(1e9); st.insert(-(1e9));
for (int i = 2; i<= n; ++i) {
int x; cin >> x;
auto it = st.lower_bound(x);
ans += min(abs(x - *(--it)), abs(x - *it));
st.insert(x);
}
cout << ans;
return 0;
}
超级备忘录
struct FHQ {
static const int N = 5e5 + 5;
struct Node {
int ch[2], pri, siz;
ll tag, val, miv;
bool rever;
int& operator [](const int k) { return ch[k]; }
} tr[N];
FHQ () { srand((unsigned)time(NULL)); }
int tot, x, y, z, root;
int newNode (int val) {
tr[++tot].val = val; tr[tot].pri = rand();
tr[tot].miv = val; tr[tot].siz = 1;
return tot;
}
void push_up(int p) {
tr[p].siz = 1 + tr[tr[p][0]].siz + tr[tr[p][1]].siz;
tr[p].miv = tr[p].val;
if (tr[p][0]) umin(tr[p].miv, tr[tr[p][0]].miv);
if (tr[p][1]) umin(tr[p].miv, tr[tr[p][1]].miv);
}
void down_tag(int p) {
ll tag = tr[p].tag; tr[p].tag = 0;
tr[p].val += tag; tr[p].miv += tag;
if (tr[p][0]) tr[tr[p][0]].tag += tag;
if (tr[p][1]) tr[tr[p][1]].tag += tag;
}
void down_rever(int p) {
tr[p].rever = 0;
swap(tr[p][1], tr[p][0]);
if (tr[p][0]) tr[tr[p][0]].rever ^= 1;
if (tr[p][1]) tr[tr[p][1]].rever ^= 1;
}
void push_down(int p) {
if (tr[tr[p][0]].tag) down_tag(tr[p][0]);
if (tr[tr[p][1]].tag) down_tag(tr[p][1]);
if (tr[p].rever) down_rever(p);
}
int merge(int x, int y) {
if (!x || !y) return x + y;
push_down(x); push_down(y);
if (tr[x].pri < tr[y].pri) tr[x][1] = merge(tr[x][1], y);
else tr[y][0] = merge(x, tr[y][0]), swap(x, y);
push_up(x); return x;
}
void split(int p, int k, int &x, int &y) {
if (!p) x = y = 0;
else {
push_down(p);
if (k <= tr[tr[p][0]].siz) y = p, split(tr[p][0], k, x, tr[p][0]);
else x = p, split(tr[p][1], k - tr[tr[p][0]].siz - 1, tr[p][1], y);
push_up(p);
}
}
void add(int pos, int val) {
split(root, pos, x, y);
root = merge(merge(x, newNode(val)), y);
}
void del(int k) {
split(root, k, x, z);
split(x, k - 1, x, y);
root = merge(x, z);
}
void res(int l, int r) { //反转l, r
split(root, r, x, z); split(x, l - 1, x, y);
tr[y].rever ^= 1;
root = merge(merge(x, y), z);
}
void rev(int l, int r, ll t) {
t %= (r - l + 1);
if (!t) return;
split(root, r, root, z);
split(root, r - t, root, y);
split(root, l - 1, root, x);
root = merge(merge(root, y), merge(x, z));
}
void change(int l, int r, ll k) {
split(root, r, x, z); split(x, l - 1, x, y);
tr[y].tag += k; down_tag(y);
root = merge(merge(x, y), z);
}
ll minval(int l, int r) {
split(root, r, x, z); split(x, l - 1, x, y);
ll ans = tr[y].miv;
root = merge(merge(x, y), z);
return ans;
}
} T;
const int N = 1e5 + 5;
int n, m, _, k;
ll a[N];
int main() {
IOS; cin >> n;
rep (i, 1, n) cin >> m, T.add(i - 1, m);
for (cin >> _; _; --_) {
string op; cin >> op;
if (op[0] == 'A') {
int l, r; ll d; cin >> l >> r >> d;
T.change(l, r, d);
} else if (op[0] == 'R' && op[3] == 'E') {
int l, r; cin >> l >> r;
T.res(l, r);
} else if (op[0] == 'R') {
int l, r; ll t; cin >> l >> r >> t;
T.rev(l, r, t);
} else if (op[0] == 'I') {
int val, key; cin >> val >> key;
T.add(val, key);
} else if (op[0] == 'D') {
int x; cin >> x;
T.del(x);
} else {
int l, r; cin >> l >> r;
cout << T.minval(l, r) << '\n';
}
}
return 0;
}
莫基亚
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e6 + 5, M = 1.8e5 + 5;
struct Query { int y, l, r, t, op; } a[M], b[M];
int W;
ll c[N], ans[M], tot;
void add(int x, int k) { for (; x <= W; x += -x & x) c[x] += k; }
ll ask(int x) { ll ans = 0; for (; x; x -= -x & x) ans += c[x]; return ans; }
void cdq(int l, int r) {
if (l == r) return;
int mid = l + r >> 1; cdq(l, mid); cdq(mid + 1, r);
int x = l, y = mid + 1, z = l;
for (; y <= r; b[z++] = a[y++]) {
for (; x <= mid && a[x].y <= a[y].y; b[z++] = a[x++])
if (a[x].op == 1) add(a[x].l, a[x].r);
if (a[y].op == 2) ans[a[y].t] += ask(a[y].r) - ask(a[y].l - 1);
}
for (int i = l; i < x; ++i) if (a[i].op == 1) add(a[i].l, -a[i].r);
for (int i = x; i <= mid; ++i) b[z++] = a[i];
for (int i = l; i <= r; ++i) a[i] = b[i];
}
int main() {
cin >> W >> W; vector<int> id;
while (cin >> a[++tot].op, a[tot].op != 3) {
if (a[tot].op == 1) cin >> a[tot].l >> a[tot].y >> a[tot].r, a[tot].t = tot;
else {
cin >> a[tot].l >> a[tot].y >> a[tot].r; --a[tot].y; cin >> a[++tot].y;
a[tot].l = a[tot - 1].l; a[tot].r = a[tot - 1].r; a[tot].op = 2;
a[tot - 1].t = tot - 1; a[tot].t = tot; id.push_back(tot);
}
}
cdq(1, tot - 1); for (auto& i : id) cout << ans[i] - ans[i - 1] << '\n';
return 0;
}
流星
struct node { ll op, l, r, id; } q[N << 1], qu[N << 1];
int n, m, _, k;
ll ans[N], c[2][N];
vector<int> a[N];
void add(int x, ll k) { for (int i = x; i <= m; i += -i & i) c[0][i] += k, c[1][i] += x * k; }
void add(int l, int r, ll k) { add(l, k); add(r + 1, -k); }
ll ask(int x) {
ll p = 0, q = 0, f = x + 1;
for (; x; x -= -x & x) p += c[0][x], q += c[1][x];
return p * f - q;
}
ll ask(int l, int r) { return ask(r) - ask(l - 1); }
void solve(int l, int r, int ql, int qr) {
if (ql > qr) return;
if (l == r) {
rep(i, ql, qr) if (q[i].op == 0) ans[q[i].id] = l;
return;
}
int mid = l + r >> 1, nl = ql - 1, nr = 0;
rep(i, ql, qr)
if (q[i].op) {
if (q[i].id > mid) { qu[++nr] = q[i]; continue; }
if (q[i].l <= q[i].r) add(q[i].l, q[i].r, q[i].op);
else add(q[i].l, m, q[i].op), add(1, q[i].r, q[i].op);
q[++nl] = q[i];
}
else {
__int128 cur = 0;//3e5*3e5*1e9 爆ll
for (auto j : a[q[i].id]) cur += ask(j, j);
if (cur >= q[i].l) q[++nl] = q[i];
else q[i].l -= cur, qu[++nr] = q[i];
}
rep(i, ql, nl) if (q[i].op)
if (q[i].l <= q[i].r) add(q[i].l, q[i].r, -q[i].op);
else add(q[i].l, m, -q[i].op), add(1, q[i].r, -q[i].op);
rep(i, 1, nr) q[i + nl] = qu[i];
solve(l, mid, ql, nl);
solve(mid + 1, r, nl + 1, qr);
}
int main() {
cin >> n >> m;
rep(i, 1, m) cin >> _, a[_].push_back(i);
rep(i, 1, n) cin >> qu[i].l, qu[i].op = 0, qu[i].id = i;
cin >> k;
rep(i, 1, k) cin >> q[i].l >> q[i].r >> q[i].op, q[i].id = i;
++k; q[k] = { (int)2e9, 1, m, k };
rep(i, 1, n) q[k + i] = qu[i];
solve(1, k, 1, k + n);
rep(i, 1, n) if (ans[i] != k) cout << ans[i] << '\n'; else cout << "NIE\n";
return 0;
}
Fotile模拟赛L
struct SustainableTrie {
struct node {
int son[2], cnt;
int& operator [](const int x) { return son[x]; }
} tr[N * M];
int rt[N], tot;
void init() {
for (int i = 1; i <= tot; ++i) rt[i] = 0;
tot = 0;
for (int i = 0; i < M; ++i) tr[0][i] = 0;
}
void insert(int& x, int y, int k) {
int p = x = ++tot; tr[p] = tr[y];
for (int i = M - 1; ~i; --i) {
int ch = k >> i & 1;
tr[p = tr[p][ch] = ++tot] = tr[y = tr[y][ch]];
++tr[p].cnt;
}
}
int ask(int x, int y, int k) {
int ans = 0;
for (int i = M - 1; ~i; --i) {
int ch = k >> i & 1;
if (tr[tr[x][!ch]].cnt - tr[tr[y][!ch]].cnt)
ans ^= 1ll << i, ch = !ch;
x = tr[x][ch], y = tr[y][ch];
} return ans;
}
} T, RT;
int n, m, f[151][151], t, len, a[N], b[N], id[N];
void init() {
len = 150; t = (n - 1) / len + 1;
for (int i = 1; i <= n; ++i) cin >> a[i], id[i] = (i - 1) / len + 1;
T.insert(T.rt[1], T.rt[0], 0); RT.insert(RT.rt[1], RT.rt[0], 0);
for (int i = 1; i <= n; ++i) b[i] = a[n + 1 - i], RT.insert(RT.rt[i + 1], RT.rt[i], b[i] ^= b[i - 1]);
for (int i = 1; i <= n; ++i) T.insert(T.rt[i + 1], T.rt[i], a[i] ^= a[i - 1]);
for (int i = 1, res = 0; i <= t; ++i, res = 0) for (int j = (i - 1) * len + 1; j <= n; ++j) {
res = max(res, T.ask(T.rt[j], T.rt[(i - 1) * len], a[j]));
if (j % len == 0 || j == n) f[i][id[j]] = res;
}
}
int ask(SustainableTrie& T, int l, int r, int a[], int L) {
int ans = 0;
for (int i = l; i <= r; ++i)
ans = max(ans, T.ask(T.rt[i], T.rt[L - 1], a[i]));
return ans;
}
int main() {
IOS; cin >> n >> m; init();
for (int i = 0, ls = 0; i < m; ++i) {
int l, r; cin >> l >> r;
l = ((long long)l + ls) % n + 1, r = ((long long)r + ls) % n + 1;
if (l > r) swap(l, r);
if (id[r] - id[l] < 2) cout << (ls = ask(T, l, r, a, l)) << '\n';
else {
ls = f[id[l] + 1][id[r] - 1];
ls = max(ls, max(ask(T, (id[r] - 1) * len + 1, r, a, l),
ask(RT, (id[n + 1 - l] - 1) * len + 1, n + 1 - l, b, n + 1 - r)));
cout << ls << '\n';
}
}
return 0;
}
可持久化并查集加强版
动态规划
线性DP
杨老师的照相排列
int n, m, _, k, cas, s[6];
ll f[31][16][11][8][7];
int main() {
IOS; f[0][0][0][0][0] = 1;
while (cin >> n, n) {
rep (i, 1, n) cin >> s[i];
rep (i, n + 1, 5) s[i] = 0;
rep (a, 1, s[1]) rep (b, 0, min(a, s[2])) rep (c, 0, min(b, s[3]))
rep (d, 0, min(c, s[4])) rep (e, 0, min(d, s[5])) {
f[a][b][c][d][e] = 0;
if (a) f[a][b][c][d][e] += f[a - 1][b][c][d][e];
if (b) f[a][b][c][d][e] += f[a][b - 1][c][d][e];
if (c) f[a][b][c][d][e] += f[a][b][c - 1][d][e];
if (d) f[a][b][c][d][e] += f[a][b][c][d - 1][e];
if (e) f[a][b][c][d][e] += f[a][b][c][d][e - 1];
}
cout << f[s[1]][s[2]][s[3]][s[4]][s[5]] << '\n';
}
return 0;
}
⭐最长上升公共子序列
最长上升子序列多了个公共
即当且仅当 a[i] == b[j] 的时候, b[j] 才能去拼接到已有的子序列上
注意已有的子序列也是不断通过(a[ii < i] == b[jj < j], a[i] < a[i])更得到的, 故已有的子序列就是公共的子序列
int n, m, f[N], a[N];
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 1, mx = 0; i <= n; ++i, mx = 0) {
cin >> m;
for (int j = 1; j <= n; ++j)
if (a[j] == m) f[j] = max(mx + 1, f[j]);
else if (m > a[j]) mx = max(mx, f[j]);
}
cout << *max_element(f + 1, f + 1 + n);
return 0;
}
⭐分级
注意观察决策集合的范围随状态的变化情况, 决策元素只增不减(等),就可以用一个变量优化掉一个循环
long long work(int f) {
long long ans = 0;
priority_queue<int> q;
for (int i = 0; i < n; ++i) {
q.push(a[i] * f);
if (a[i] * f < q.top()) {
ans += q.top() - a[i] * f;
q.pop(); q.push(a[i] * f);
}
}
return ans;
}
int main() {
cin >> n;
for (int i = 0; i < n; ++i) cin >> a[i];
cout << min(work(1), work(-1));
return 0;
}
⭐移动服务
int n, m, _, k = 2e9, cas;
int d[N][N], a[2], f[2][N][N];
int main() {
IOS; cin >> n >> m; memset(f[0], 0x3f, sizeof f[0]);
rep (i, 1, n) rep (j, 1, n) cin >> d[i][j];
a[f[0][1][2] = 0] = 3;
rep (i, 1, m) {
cin >> a[i & 1]; memset(f[i & 1], 0x3f, sizeof f[0]);
rep (x, 1, n) rep (y, 1, n) if ((x ^ y) && (x ^ a[i & 1 ^ 1]) && (y ^ a[i & 1 ^ 1])) {
if ((x ^ a[i]) && (a[i & 1 ^ 1] ^ a[i]))
f[i & 1][a[i & 1 ^ 1]][x] = f[i & 1][x][a[i & 1 ^ 1]] =
min(f[i & 1][a[i & 1 ^ 1]][x], f[i & 1 ^ 1][x][y] + d[y][a[i & 1]]);
if ((y ^ a[i]) && (a[i & 1 ^ 1] ^ a[i]))
f[i & 1][a[i & 1 ^ 1]][y] = f[i & 1][y][a[i & 1 ^ 1]] =
min(f[i & 1][a[i & 1 ^ 1]][y], f[i & 1 ^ 1][x][y] + d[x][a[i & 1]]);
if ((y ^ a[i]) && (x ^ a[i]))
f[i & 1][x][y] = f[i & 1][y][x] =
min(f[i & 1][x][y], f[i & 1 ^ 1][x][y] + d[a[i & 1 ^ 1]][a[i & 1]]);
}
}
rep (i, 1, n) rep (j, 1, n) umin(k, f[n & 1][i][j]);
cout << k;
return 0;
}
传纸条
int main() {
cin >> m >> n;
for (int i = 1; i <= m; ++ i) for(int j = 1; j <= n; ++ j) cin >> mp[i][j];
memset(f, -1, sizeof f);
f[2][1][1] = 0;
for (int k = 3; k < m + n; ++ k) for(int i = 1; i < n; ++ i) for(int j = i + 1; j <= n; ++ j) {
int s = max(max(f[k - 1][i][j], f[k - 1][i - 1][j]), max(f[k - 1][i][j - 1], f[k - 1][i - 1][j - 1]));
if (s ^ -1) f[k][i][j] = s + mp[k - i][i] + mp[k - j][j];
}
cout << f[m + n - 1][n - 1][n];
return 0;
}
区域
struct path { int k, i, j, l, r; } p[N * N][N][2][2][N][N];
int n, m, k, sum[N][N], f[N * N][N][2][2][N][N], ans, w;
int main() {
IOS; cin >> n >> m >> k; memset(f, -1, sizeof f); memset(f[0], 0, sizeof f[0]);
rep(i, 1, n) rep(j, 1, m) cin >> sum[i][j], sum[i][j] += sum[i][j - 1];
rep(i, 1, n) rep(j, 1, k) rep(l, 1, m) rep(r, l, m) if (j >= r - l + 1) {
int len = r - l + 1, s = sum[i][r] - sum[i][l - 1];
rep(a, l, r) rep(b, a, r)
if (~f[j - len][i - 1][1][1][a][b] && umax(f[j][i][1][1][l][r], f[j - len][i - 1][1][1][a][b] + s))
p[j][i][1][1][l][r] = { j - len, 1, 1, a, b };
rep(a, l, r) rep(b, r, m) {
if (~f[j - len][i - 1][1][1][a][b] && umax(f[j][i][1][0][l][r], f[j - len][i - 1][1][1][a][b] + s))
p[j][i][1][0][l][r] = { j - len, 1, 1, a, b };
if (~f[j - len][i - 1][1][0][a][b] && umax(f[j][i][1][0][l][r], f[j - len][i - 1][1][0][a][b] + s))
p[j][i][1][0][l][r] = { j - len, 1, 0, a, b };
}
rep(a, 1, l) rep(b, l, r) {
if (~f[j - len][i - 1][1][1][a][b] && umax(f[j][i][0][1][l][r], f[j - len][i - 1][1][1][a][b] + s))
p[j][i][0][1][l][r] = { j - len, 1, 1, a, b };
if (~f[j - len][i - 1][0][1][a][b] && umax(f[j][i][0][1][l][r], f[j - len][i - 1][0][1][a][b] + s))
p[j][i][0][1][l][r] = { j - len, 0, 1, a, b };
}
rep(a, 1, l) rep(b, r, m) {
if (~f[j - len][i - 1][1][1][a][b] && umax(f[j][i][0][0][l][r], f[j - len][i - 1][1][1][a][b] + s))
p[j][i][0][0][l][r] = { j - len, 1, 1, a, b };
if (~f[j - len][i - 1][1][0][a][b] && umax(f[j][i][0][0][l][r], f[j - len][i - 1][1][0][a][b] + s))
p[j][i][0][0][l][r] = { j - len, 1, 0, a, b };
if (~f[j - len][i - 1][0][1][a][b] && umax(f[j][i][0][0][l][r], f[j - len][i - 1][0][1][a][b] + s))
p[j][i][0][0][l][r] = { j - len, 0, 1, a, b };
if (~f[j - len][i - 1][0][0][a][b] && umax(f[j][i][0][0][l][r], f[j - len][i - 1][0][0][a][b] + s))
p[j][i][0][0][l][r] = { j - len, 0, 0, a, b };
}
}
rep(i, 1, n) rep(l, 1, m) rep(r, l, m) rep (x, 0, 1) rep (y, 0, 1)
if (umax(ans, f[k][i][x][y][l][r])) p[0][0][0][0][0][0] = { k, x, y, l, r }, w = i;
cout << "Oil : " << ans << '\n';
for (path *i = &p[0][0][0][0][0][0]; i->k; i = &p[i->k][w--][i->i][i->j][i->l][i->r])
rep (j, i->l, i->r) cout << w << ' ' << j << '\n';
return 0;
}
⭐饼干
通过额外的算法确定DP状态的计算顺序, 排序获得DP顺序, 对状态进行放缩
利用相对大小不变性, 把第i个孩子获得饼干数放缩到1,在考虑前面有多少人和自己数量相等
ll f[31][5001], a[31];
PLL g[31];
int main() {
IOS; cin >> n >> m; memset(f, 0x3f, sizeof f); f[0][0] = 0;
rep (i, 1, n) cin >> g[i].fi, g[i].se = i; sort(g + 1, g + n + 1, greater<PLL>());
rep (i, 1, n) g[i].fi += g[i - 1].fi;
rep (i, 1, n) rep (j, i, m) {
if (j > i) f[i][j] = f[i][j - i];
rep (k, 1, i) umin(f[i][j], f[i - k][j - k] + (g[i].fi - g[i - k].fi) * (i - k));
}
cout << f[n][m] << '\n';
for (int i = n, j = m, h = 0; i; ) {
while (j > i && f[i][j] == f[i][j - i]) ++h, j -= i;
per (k, i, 1) if (f[i][j] == f[i - k][j - k] + (g[i].fi - g[i - k].fi) * (i - k))
while (k--) a[g[i].se] = 1 + h, --j, --i;
}
rep (i, 1, n) cout << a[i] << ' ';
return 0;
}
背包
数字组合
ll f[10001], a[101];
int main() {
IOS; cin >> n >> m; f[0] = 1;
rep (i, 1, n) cin >> a[i];
rep (i, 1, n) per (j, m, 1) if (j >= a[i]) f[j] += f[j - a[i]];
cout << f[m];
return 0;
}
自然数拆分
int n, m, _, k, cas;
long long f[4001];
int main() {
IOS; cin >> n; f[0] = 1;
rep (i, 1, n) rep (j, i, n) f[j] = (f[j] + f[j - i]) % mod;
cout << (f[n] - 1ll + mod) % mod;
return 0;
}
陪审团
int p[201], q[201], f[201][21][801];
int main() {
IOS;
while (cin >> n >> m, n || m) {
memset(f, -1, sizeof f); f[0][0][400] = 0; cout << "Jury #" << ++cas << '\n';
rep(i, 1, n) cin >> p[i] >> q[i];
rep(i, 1, n) rep(j, 0, min(i, m)) rep(k, 0, j * 20 + 400) {
f[i][j][k] = f[i - 1][j][k];
if (!j || k - p[i] + q[i] < 0 || k - p[i] + q[i] > 800 || f[i - 1][j - 1][k - p[i] + q[i]] == -1) continue;
umax(f[i][j][k], f[i - 1][j - 1][k - p[i] + q[i]] + p[i] + q[i]);
}
int k = 0, sp = 0, sq = 0; VI a;
for (; k >= 0; ++k) if (~f[n][m][M + k] || ~f[n][m][M - k])
if (f[n][m][M - k] < f[n][m][M + k]) break;
else { k = -k; break; }
for (int i = n, j = m; j; sp += p[i], sq += q[i], k -= p[i] - q[i], a.pb(i--), --j)
while (f[i][j][k + M] == f[i - 1][j][k + M]) --i;
cout << "Best jury has value " << sp << " for prosecution and value " << sq << " for defence:\n";
per(i, a.size() - 1, 0) cout << a[i] << ' '; cout << "\n\n";
}
return 0;
}
硬币
int cnt[N], a[101], c;
bool f[N];
int main() {
IOS;
while (cin >> n >> m, k = 0, memset(f, 0, sizeof f), f[0] = 1, n || m) {
rep (i, 1, n) cin >> a[i];
rep (i, 1, n) {
cin >> c; memset(cnt, 0, sizeof cnt);
rep (j, a[i], m)
if (f[j]) cnt[j % a[i]] = 0;
else if (f[j - a[i]] && cnt[j % a[i]] + 1 <= c) f[j] = ++k, ++cnt[j % a[i]];
}
cout << k << '\n';
}
return 0;
}
区间DP
石子合并
ll f[301][301], a[N];
int main() {
IOS; cin >> n; memset(f, 0x3f, sizeof f);
rep (i, 1, n) cin >> a[i], a[i] += a[i - 1], f[i][i] = 0;
rep (len, 1, n) rep (l, 1, n + 1 - len) rep (k, l, l + len - 2)
umin(f[l][l + len - 1], f[l][k] + f[k + 1][l + len - 1] + a[l + len - 1] - a[l - 1]);
cout << f[1][n];
return 0;
}
多边形
int f[2][101][101], m = -1e9;
bool g[101];
int main() {
IOS; cin >> n; VI a; memset(f[0], 0xcf, sizeof f[0]); memset(f[1], 0x3f, sizeof f[1]);
rep (i, 1, n) {
char c; cin >> c >> f[0][i][i];
f[1][i][i] = f[0][i + n][i + n] = f[1][i + n][i + n] = f[0][i][i];
g[i - 1] = g[i - 1 + n] = c == 't';
}
rep (len, 1, n) rep (l, 1, n + n + 1 - len) rep (k, l, l + len - 2) {
if (g[k]) umax(f[0][l][l + len - 1], f[0][l][k] + f[0][k + 1][l + len - 1]),
umin(f[1][l][l + len - 1], f[1][l][k] + f[1][k + 1][l + len - 1]);
else umax(f[0][l][l + len - 1], max(f[0][l][k] * f[0][k + 1][l + len - 1],
f[1][l][k] * f[1][k + 1][l + len - 1])),
umin(f[1][l][l + len - 1], min(min(f[0][l][k] * f[0][k + 1][l + len - 1],
f[1][l][k] * f[1][k + 1][l + len - 1]), min(f[0][l][k] * f[1][k + 1][l + len - 1],
f[1][l][k] * f[0][k + 1][l + len - 1])));
}
rep (i, 1, n)
if (umax(m, f[0][i][i + n - 1])) VI(1, i).swap(a);
else if (m == f[0][i][i + n - 1]) a.pb(i);
cout << m << '\n'; for (auto &i : a) cout << i << ' ';
return 0;
}
⭐金字塔
一棵树必定是奇数个字母, 对于一个根x
没遍历过其一棵子树, 就会再走一遍x,
对于每棵树[l, r](s[l] == s[r]), 枚举其第最后一颗棵子树即可
保证一个状态的所有决策之间互斥
对于子树[l, k](s[l] == s[k]包含了除最后一棵子树的所有情况), 则
f[l,r] += f[l][k] * f[k + 1][r - 1] ([k + 1, r - 1]是最后一颗子树)
ll f[301][301];
char s[302];
int main() {
IOS; cin >> s + 1;
for (n = 1; s[n]; ++n) f[n][n] = 1; --n;
for (int len = 3; len <= n; len += 2) rep (l, 1, n + 1 - len) if (s[l] == s[l + len - 1])
for (int k = l; k < l + len - 1; k += 2) if (s[k] == s[l] && s[k + 1] == s[l + len - 2])
f[l][l + len - 1] = (f[l][l + len - 1] + f[l][k] * f[k + 1][l + len - 2] % mod) % mod;
cout << f[1][n];
return 0;
}
树形DP
没有上司的舞会
void dfs(int x) {
for (auto &y : h[x]) {
dfs(y); umax(f[x][1], f[x][1] + f[y][0]);
umax(f[x][0], f[x][0] + max(f[y][1], f[y][0]));
}
}
int main() {
IOS; cin >> n;
rep (i, 1, n) cin >> f[i][1];
rep (i, 2, n) { int L, K; cin >> L >> K; b[L] = K, h[K].pb(L); }
rep (i, 1, n) if (!b[i]) dfs(m = i);
cout << max(f[m][0], f[m][1]);
return 0;
}
选课
int b[N], f[N][N], d[N];
VI h[N];
void dfs(int x) {
for (auto &y : h[x]) {
dfs(y); memcpy(d, f[x], sizeof d);
if (x) rep (i, 1, m) rep (j, i + 1, m) umax(d[j], f[x][j - i] + f[y][i]);
else rep (i, 1, m) rep (j, i, m) umax(d[j], f[x][j - i] + f[y][i]);
memcpy(f[x], d, sizeof d);
}
}
int main() {
IOS; cin >> n >> m;
rep (i, 1, n) cin >> k >> f[i][1], h[k].pb(i);
dfs(0); cout << *max_element(f[0] + 1, f[0] + m + 1);
return 0;
}
积蓄程度
别忘了考虑, 换根的时候, 原根为出海口
int dfs(int x, int fa) {
for (auto &[y, c] : h[x]) if (y ^ fa) f[x] += min(c, dfs(y, x));
return h[x].size() == 1 && h[x][0].fi == fa ? INF : f[x];
}
void dfss(int x, int fa) {
for (auto &[y, c] : h[x]) if (y ^ fa) {
f[y] += h[x].size() == 1 ? c : min(c, f[x] - min(c, f[y]));
dfss(y, x);
}
}
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n; rep (i, 1, n) h[i].resize(0); memset(f, 0, sizeof f);
rep (i, 2, n) { int u, v, c; cin >> u >> v >> c; h[u].pb(v, c); h[v].pb(u, c); }
dfs(1, 0); dfss(1, 0); cout << *max_element(f + 1, f + 1 + n) << '\n';
}
return 0;
}
环形与后效性处理
⭐休息时间
强制改变设定初始状态, 与尾状态拼接
同时利用好 0, 1 表示当前阶段尾状态是否醒 or 睡
int f[2][N][2], a[N], ans;
int work() {
rep (i, 2, n) rep (j, 0, m) {
...
}
return max(f[n & 1][m][1], f[n & 1][m][0]);
}
int main() {
IOS; cin >> n >> m;
rep (i, 1, n) cin >> a[i];
memset(f, 0xcf, sizeof f); f[1][0][0] = f[1][1][1] = 0; ans = work();
memset(f, 0xcf, sizeof f); f[1][1][1] = a[1]; work();
cout << max(ans, f[n & 1][m][1]);
return 0;
}
环路运输
int n, a[N], h, t = -1, ans;
PII q[N];
int main() {
IOS; cin >> n;
rep (i, 0, n - 1) cin >> a[i];
rep (i, 0, (n << 1) - 1) {
while (t >= h && i - q[h].se > n >> 1) ++h;
if (t >= h) ans = max(ans, a[i % n] + q[h].fi + i);
while (t >= h && q[t].fi <= a[i % n] - i) --t;
q[++t] = { a[i % n] - i, i };
}
cout << ans;
return 0;
}
⭐坏掉的机器人
行之间无后效性, 行内后效性通过高斯消元求解
事实上, 很多数学期望DP都会采取倒推的方式执行
int n, m, x, y;
double a[N][N];
void gauss(int n, int m) {
rep (t, 1, m - 2) {
a[t][t + 1] /= a[t][t]; a[t][m] /= a[t][t]; a[t][t] = 1;
a[t + 1][t + 1] -= a[t + 1][t] * a[t][t + 1];
a[t + 1][m] -= a[t + 1][t] * a[t][m]; a[t + 1][t] = 0;
}
a[m - 1][m] /= a[m - 1][m - 1]; a[m - 1][m - 1] = 1;
per (i, m - 2, 1) a[i][m] -= a[i + 1][m] * a[i][i + 1];
}
int main() {
IOS; cin >> n >> m >> x >> y;
if (m == 1) return cout << precision(4) << 2.0 * (n - x) << '\n', 0;
per (i, n - 1, x) {
a[1][1] = 2.0 / 3, a[1][2] = -1.0 / 3, a[1][m + 1] = a[1][m + 1] / 3 + 1;
a[m][m - 1] = -1.0 / 3, a[m][m] = 2.0 / 3, a[m][m + 1] = a[m][m + 1] / 3 + 1;
rep (j, 2, m - 1)
a[j][j - 1] = a[j][j + 1] = -0.25, a[j][j] = 0.75, a[j][m + 1] = a[j][m + 1] / 4 + 1;
gauss(n, m + 1);
}
cout << precision(4) << a[y][m + 1];
return 0;
}
状压DP
蒙德里安的梦想
ll f[12][N];
bool v[N];
int main() {
IOS;
while (cin >> n >> m, n || m) {
memset(v, 0, sizeof v); memset(f, 0, sizeof f); f[0][0] = 1;
rep (i, 0, (1 << m) - 1) for (int j = -1, k = 0; j < m; j = k++) {
for (; k < m && !(i >> k & 1); ++k);
if (!(k - j & 1)) { v[i] = 1; break; }
}
rep (i, 1, n) rep (k, 0, (1 << m) - 1) if (f[i - 1][k])
rep (j, 0, (1 << m) - 1) if (!(k & j) && !v[k | j]) f[i][j] += f[i - 1][k];
cout << f[n][0] << '\n';
}
return 0;
}
炮兵阵地
int f[101][60][60];
char s[101][10];
bool v[N];
bool check(int i, int k) {
rep (j, 0, m - 1) if ((k >> j & 1) && s[i][j] == 'H') return 0;
return 1;
}
int main() {
IOS; cin >> n >> m; VI a, b; memset(f, -1, sizeof f); f[0][0][0] = 0;
rep (i, 0, (1 << m) - 1) rep (j, 0, m - 1) if (i >> j & 1)
rep (k, j + 1, m - 1) if ((i >> k & 1) && k - j < 3) v[i] = 1;
rep (i, 1, n) cin >> s[i];
rep (i, 0, (1 << m) - 1) if (!v[i]) a.pb(i), b.pb(__builtin_popcount(i));
rep (i, 1, n) rep (k, 0, a.size() - 1) rep (p, 0, a.size() - 1)
if (!(a[k] & a[p]) && ~f[i - 1][k][p]) rep (j, 0, a.size() - 1)
if (!(a[k] & a[j]) && !(a[p] & a[j]) && check(i, a[j])) umax(f[i][p][j], f[i - 1][k][p] + b[j]);
rep (k, 0, a.size() - 1) rep (p, 0, a.size() - 1) umax(_, f[n][k][p]);
cout << _;
return 0;
}
⭐宝藏
f[rt][k], 以rt为根, 状态为k 的最小化费, 局部最优, 并不是全局最优
5 5
1 2 1
2 3 1
3 4 1
4 5 2
2 5 5
f[2][2,3,4,5] = 7, 单对于全局 取边(4, 5, 2) 比 (2, 5, 5) 优
故应把树的深度作为dp的状态
int s[12][12];
ll f[13][1 << 12];
int main() {
IOS; cin >> n >> m; memset(s, 0x3f, sizeof s); memset(f, 0x3f, sizeof f);
rep (i, 1, m) {
int u, v, c; cin >> u >> v >> c; --u, --v;
s[u][v] = s[v][u] = min(s[u][v], c);
}
rep (i, 0, n - 1) f[1][1 << i] = 0;
rep (i, 2, n) rep (x, 1, (1 << n) - 1) if (f[i - 1][x] ^ f[0][0])
rep (y, x + 1, (1 << n) - 1) if ((y & x) == x) {
ll res = 0;
rep (p, 0, n - 1) if ((x ^ y) >> p & 1) {
int cur = f[0][0];
rep (q, 0, n - 1) if (q != p && (x >> q & 1)) umin(cur, s[p][q]);
res = cur < f[0][0] ? res + cur : -1;
}
if (res ^ -1) umin(f[i][y], f[i - 1][x] + res * (i - 1));
}
ll ans = 1e9;
rep (i, 2, n) ans = min(ans, f[i][(1 << n) - 1]);
cout << (ans == 1e9 ? 0 : ans);
return 0;
}
倍增DP
⭐开车旅行
ll a[N], f[M][N][2], da[M][N][2], db[M][N][2];
void init() {
set<PII> st; f[0][n - 1][1] = n; db[0][n - 1][1] = abs(a[n] - a[n - 1]);
st.insert({ a[n], n }); st.insert({ a[n - 1], n - 1 });
per (i, n - 2, 1) {
auto it = st.insert({ a[i], i }).fi, nxt = it, pre = it;
if (it == st.begin()) f[0][i][1] = (*++nxt).se, f[0][i][0] = (*++nxt).se;
else if (it == st.end()) f[0][i][1] = (*--pre).se, f[0][i][0] = (*--pre).se;
else {
if (a[i] - (*--pre).fi > (*++nxt).fi - a[i]) {
f[0][i][1] = nxt->se;
if (nxt == st.end() || (*++nxt).fi - a[i] >= a[i] - pre->fi) f[0][i][0] = pre->se;
else f[0][i][0] = nxt->se;
}
else if (a[i] - pre->fi < nxt->fi - a[i]) {
f[0][i][1] = pre->se;
if (pre == st.begin() || a[i] - (*--pre).fi > nxt->fi - a[i]) f[0][i][0] = nxt->se;
else f[0][i][0] = pre->se;
}
else f[0][i][0] = nxt->se, f[0][i][1] = pre->se;
}
da[0][i][0] = abs(a[i] - a[f[0][i][0]]), db[0][i][1] = abs(a[i] - a[f[0][i][1]]);
}
rep (i, 1, n) {
f[1][i][1] = f[0][f[0][i][1]][0], f[1][i][0] = f[0][f[0][i][0]][1];
da[1][i][0] = da[0][i][0], da[1][i][1] = da[0][f[0][i][1]][0];
db[1][i][1] = db[0][i][1], db[1][i][0] = db[0][f[0][i][0]][1];
}
rep (i, 2, 16) rep(j, 1, n) {
f[i][j][1] = f[i - 1][f[i - 1][j][1]][1], f[i][j][0] = f[i - 1][f[i - 1][j][0]][0];
da[i][j][0] = da[i - 1][j][0] + da[i - 1][f[i - 1][j][0]][0];
da[i][j][1] = da[i - 1][j][1] + da[i - 1][f[i - 1][j][1]][1];
db[i][j][0] = db[i - 1][j][0] + db[i - 1][f[i - 1][j][0]][0];
db[i][j][1] = db[i - 1][j][1] + db[i - 1][f[i - 1][j][1]][1];
}
}
PLL calc(int s, int x) {
ll la = 0, lb = 0;
per (i, 16, 0) if (f[i][s][0] && la + lb + da[i][s][0] + db[i][s][0] <= x)
la += da[i][s][0], lb += db[i][s][0], s = f[i][s][0];
return { la, lb };
}
int main() {
IOS; cin >> n; rep(i, 1, n) cin >> a[i]; init();
int s, x; cin >> x; double r = 2e9;
rep(i, 1, n) {
auto c = calc(i, x);
if (c.se && umin(r, c.fi / (double)c.se)) s = i;
}
cout << s << '\n';
for (cin >> _; _; --_) {
cin >> s >> x; auto c = calc(s, x);
cout << c.fi << ' ' << c.se << '\n';
}
return 0;
}
⭐计算重复
注意当 n1 >= f[j][i] 时 i 不用(--i)
int n1, n2;
ll f[105][20];
char s[105], t[105];
bool check() {
set<char> st;
rep (i, 0, n - 1) st.insert(s[i]);
rep (i, 0, m - 1) if (!st.count(t[i])) return 1;
return 0;
}
int main() {
IOS;
while (cin >> t >> n2 >> s >> n1) {
n = strlen(s), m = strlen(t); n1 *= n; _ = 0;
rep (i, 0, n - 1) f[i][0] = 0;
if (check()) { cout << "0\n"; continue; }
rep (i, 0, n - 1) rep (j, 0, m - 1) while (s[(++f[i][0] + i - 1) % n] != t[j]);
rep (i, 1, 19) rep (j, 0, n - 1)
f[j][i] = f[j][i - 1] + f[(j + f[j][i - 1]) % n][i - 1];
for (int i = 19, j = 0; ~i; --i)
if (f[j][i] <= n1) _ += 1 << i, n1 -= f[j][i], j = (j + f[j][i++]) % n;
cout << _ / n2 << '\n';
}
return 0;
}
数据结构优化DP
清理班次
int ne[N];
int main() {
IOS; cin >> n >> m;
rep (i, 1, n) { int l, r; cin >> l >> r; umax(ne[l], r); }
rep (i, 2, m) umax(ne[i], ne[i - 1]);
while (k < m && ne[k + 1] >= k + 1) ++_, k = ne[k + 1];
cout << (k ^ m ? -1 : _);
return 0;
}
清理班次2
struct BIT {
struct node { int r, l, val, tag; } tr[N * 20];
void push_up(int rt) { tr[rt].val = min(tr[rt << 1].val, tr[rt << 1 | 1].val); }
void push_down(int rt) {
umin(tr[rt << 1].val, tr[rt].tag); umin(tr[rt << 1 | 1].val, tr[rt].tag);
umin(tr[rt << 1].tag, tr[rt].tag); umin(tr[rt << 1 | 1].tag, tr[rt].tag);
tr[rt].tag = 1e9;
}
void build(int rt, int l, int r) {
tr[rt].l = l, tr[rt].r = r, tr[rt].val = 1e9, tr[rt].tag = 1e9;
if (l == r) return;
int mid = l + r >> 1;
build(rt << 1, l, mid); build(rt << 1 | 1, mid + 1, r);
}
void change(int rt, int l, int r, int k) {
if (tr[rt].l >= l && tr[rt].r <= r) { umin(tr[rt].val, k); umin(tr[rt].tag, k); return; }
push_down(rt);int mid =tr[rt].l + tr[rt].r >> 1;
if (mid >= l) change(rt << 1, l, r, k);
if (mid < r) change(rt << 1 | 1, l, r, k);
push_up(rt);
}
int ask(int rt, int l, int r) {
if (tr[rt].l >= l && tr[rt].r <= r) return tr[rt].val;
push_down(rt); int mid = tr[rt].l + tr[rt].r >> 1;
int ans = mid >= l ? ask(rt << 1, l, r) : 1e9;
if (mid < r) umin(ans, ask(rt << 1 | 1, l, r));
return push_up(rt), ans;
}
} bit;
struct node { int x, y, c; } a[10005];
int n, m, _, k, cas, e;
int main() {
IOS; cin >> n >> m >> e; bit.build(1, m, e);
rep (i, 1, n) cin >> a[i].x >> a[i].y >> a[i].c;
sort(a + 1, a + 1 + n, [](node& a, node& b) { return a.y < b.y; });
rep (i, 1, n) {
if (a[i].x == m) { bit.change(1, m, a[i].y, a[i].c); continue; }
int res = bit.ask(1, a[i].x - 1, a[i].y - 1);
if (res != 1e9) bit.change(1, a[i].x, a[i].y, a[i].c + res);
}
int res = bit.ask(1, e, e);
cout << (res == 1e9 ? -1 : res);
return 0;
}
赤壁之战
int c[N][N], a[N];
void add(int x, int k, int t) { for (; x <= n; x += -x & x) c[t][x] = (c[t][x] + k) % mod; }
int ask(int x, int t) {int ans = 0; for (; x; x -= -x & x) ans = (ans + c[t][x]) % mod; return ans; }
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n >> m; VI g;
rep (i, 1, n) cin >> a[i], g.pb(a[i]);
sort(all(g)); g.erase(unique(all(g)), g.end());
per (i, g.size(), 1) per (j, g.size(), 1) c[i][j] = 0;
rep (i, 1, n) {
a[i] = lower_bound(all(g), a[i]) - g.begin() + 1;
add(a[i], 1, 1);
rep (j, 2, m) add(a[i], ask(a[i] - 1, j - 1), j);
}
cout << "Case #" << ++cas << ": " << ask(g.size(), m) << '\n';
}
return 0;
}
单调队列优化DP
围栏
const int N = 1.6e4 + 5, M = 105;
struct node { int l, p, s; } a[M];
int n, m, _, k, cas;
int f[M][N], q[N];
int calc(int i, int k) { return f[i - 1][k] - a[i].p * k; }
int main() {
IOS; cin >> n >> m;
rep (i, 1, m) cin >> a[i].l >> a[i].p >> a[i].s;
sort(a + 1, a + 1 + m, [](node& a, node& b) { return a.s < b.s; });
rep (i, 1, m) {
int h = 0, t = -1;
rep (k, max(a[i].s - a[i].l, 0), a[i].s - 1) {
while (t >= h && calc(i, q[t]) <= calc(i, k)) --t;
q[++t] = k;
}
rep (j, 1, n) {
f[i][j] = max(f[i - 1][j], f[i][j - 1]);
if (j < a[i].s) continue;
while (t >= h && q[h] < j - a[i].l) ++h;
if (h <= t) umax(f[i][j], calc(i, q[h]) + a[i].p * j);
}
}
cout << f[m][n];
return 0;
}
⭐裁剪序列
单调队列优化, 本质时队列把不必要的转移舍去了
而这道题还需要额外的set来维护队列里的必要转移的最小值
单调队列DP模型 \(F[i] = min_{L(i) \leqslant j \leqslant R(i)} {F[j] + val(i, j)}\)
int n, m, _, k, cas;
int a[N], q[N], h, t = -1;
ll f[N], mx, s;
multiset<ll> st;
int main() {
IOS; cin >> n >> mx;
rep(i, 1, n) { cin >> a[i]; if (a[i] > mx) return cout << -1, 0; }
for (int i = 1, j = 0; i <= n; ++i) {
s += a[i]; while (s > mx) s -= a[++j];
while (q[h] < j) st.erase(st.find(f[q[h]] + a[q[h + 1]])), ++h;
int y = t;
for (; h <= t && a[q[t]] <= a[i]; --t) st.erase(st.find(f[q[t]] + a[q[t + 1]]));
if (h <= t && y != t) st.erase(st.find(f[q[t]] + a[q[t + 1]])), st.insert(f[q[t]] + a[i]);
f[i] = h <= t ? min(*st.begin(), f[j] + a[q[h]]) : f[j] + a[i];
q[++t] = i; st.insert(f[i] + a[i + 1]); q[t + 1] = i + 1;
}
cout << f[n];
return 0;
}
总结与练习
乌龟棋
卡空间注意循环顺序
int f[41][41][41][41], a[351], b[5];
int main() {
IOS; cin >> n >> m; memset(f, -1, sizeof f);
rep (i, 1, n) cin >> a[i];
rep (i, 1, m) cin >> k, ++b[k]; f[b[1]][b[2]][b[3]][b[4]] = a[1];
per (x, b[1], 0) per (y, b[2], 0) per (z, b[3], 0) per (t, b[4], 0) {
int d = (b[1] - x) + (b[2] - y) * 2 + (b[3] - z) * 3 + (b[4] - t) * 4 + 1;
if (~f[x + 1][y][z][t]) umax(f[x][y][z][t], f[x + 1][y][z][t] + a[d]);
if (~f[x][y + 1][z][t]) umax(f[x][y][z][t], f[x][y + 1][z][t] + a[d]);
if (~f[x][y][z + 1][t]) umax(f[x][y][z][t], f[x][y][z + 1][t] + a[d]);
if (~f[x][y][z][t + 1]) umax(f[x][y][z][t], f[x][y][z][t + 1] + a[d]);
}
cout << f[0][0][0][0] << '\n';
return 0;
}
花店橱窗
ll f[N][N], d[N][N];
int main() {
IOS; cin >> m >> n; memset(f, 0xcf, sizeof f); f[0][0] = 0;
rep (i, 1, m) rep (j, 1, n) cin >> d[i][j]; VI ans;
rep (i, 1, n) rep (j, 0, min(i, m)) {
f[i][j] = f[i - 1][j];
if (j) umax(f[i][j], f[i - 1][j - 1] + d[j][i]);
}
for (int i = n, j = m; j; ans.pb(i--), --j) while (f[i][j] == f[i - 1][j]) --i;
cout << f[n][m] << '\n'; per (i, ans.size() - 1, 0) cout << ans[i] << ' ';
return 0;
}
⭐低买
注意到, a[i] 只能去跟新最长串
eg: 3 4 6, 尽管6可以拼接成 3 6, 但是我们要求的是最长串的种类
再来个7, 最长串是 3 4 5 7, 跟3 6 7没关系, 要放缩规划的空间
即直接将a[i]拼接到最长串上, 低于短串不考虑拼接
严格递减, 则当 a[i] == a[j] 的时候, cnt[i] 会重复奇数cnt[j]
要将 cnt[j] 清0, 或cnt[i] -= cnt[j]
int f[N], a[N], c[N];
int main() {
IOS; cin >> n;
rep (i, 1, n) {
cin >> a[i]; f[i] = 1;
rep (j, 1, i - 1) if (a[j] > a[i]) umax(f[i], f[j] + 1); else if (a[i] == a[j]) c[j] = 0;
rep (j, 1, i - 1) if (f[i] == f[j] + 1 && a[j] > a[i]) c[i] += c[j];
if (!c[i]) c[i] = 1;
}
rep (i, 1, n) if (umax(m, f[i])) k = c[i]; else if (m == f[i]) k += c[i];
cout << m << ' ' << k;
return 0;
}
⭐旅行
裸的LCS, 主要是输出方案
- dfs 通过set减少爆搜空间
- dfs, 预处理fa[i][j], fb[i][j], 表示再串a(b)前j个字符最后一次出现字符i的位置, 也就减小了爆搜的空间(更快)
char s[85], t[85];
int f[85][85];
set<string> ans;
set<pair<PII, string>> st;
void dfs(int x, int y, string& cur, int k) {
if (st.count({ { x, y }, cur})) return;
st.insert({ {x, y }, cur});
if (k == -1) { ans.insert(cur); return; }
if (s[x] == t[y] && f[x][y] == f[x - 1][y - 1] + 1)
cur[k] = s[x], dfs(x - 1, y - 1, cur, k - 1);
if (f[x][y] == f[x][y - 1]) dfs(x, y - 1, cur, k);
if (f[x][y] == f[x - 1][y]) dfs(x - 1, y, cur, k);
}
int main() {
IOS; cin >> s + 1 >> t + 1; n = strlen(s + 1), m = strlen(t + 1);
rep (i, 1, n) rep (j, 1, m)
f[i][j] = s[i] == t[j] ? f[i - 1][j - 1] + 1 : max(f[i][j - 1], f[i - 1][j]);
string res(f[n][m], ' '); dfs(n, m, res, f[n][m] - 1);
for (auto &s : ans) cout << s << '\n';
return 0;
}
减操作
int a[N];
bool f[N][20001];
int main() {
IOS; cin >> n >> m; VI ans;
rep (i, 1, n) cin >> a[i];
f[1][a[1] + M] = f[2][a[1] - a[2] + M] = 1;
rep (i, 3, n) rep (j, -M, M) {
int x = j - a[i], y = j + a[i];
if (x >= -M && x <= M && f[i - 1][x + M]) f[i][j + M] = 1;
if (y >= -M && y <= M && f[i - 1][y + M]) f[i][j + M] = 1;
}
for (int i = n, j = n; i > 1; m += a[i], ans.pb(j - i), j = --i)
while (m - a[i] >= -M && m - a[i] <= M && f[i - 1][m - a[i] + M]) m -= a[i--];
per (i, ans.size() - 1, 0) { rep (j, 1, ans[i]) cout << 2 << '\n'; cout << "1\n"; }
return 0;
}
⭐划分大理石
别忘了集合, 还有一种不超过, 不少于
分多段的, 要考虑“第一段”括号序列
即划分成 {A}B、[A]B 或 (A)B,其中 A,B 是子问题,即可避免重复
int a[7], c[6];
bool f[N];
int main() {
IOS;
while (cin >> a[1] >> a[2] >> a[3] >> a[4] >> a[5] >> a[6], a[1] || a[2] || a[3] || a[4] || a[5] || a[6]) {
memset(f, 0, sizeof f); f[0] = 1;
int s = a[1] + a[2] * 2 + a[3] * 3 + a[4] * 4 + a[5] * 5 + a[6] * 6;
for (int i = 1; i <= 6; ++i, memset(c, 0, sizeof c)) rep (k, i, s >> 1) {
c[k % i] = f[k] ? 0 : c[k % i] + 1;
if (f[k - i] && c[k % i] <= a[i]) f[k] = 1;
}
cout << (!(s & 1) && f[s >> 1] ? "Can\n" : "Can't\n");
}
return 0;
}
⭐折叠序列
f[l][r] 表示[l, r]的最短折叠长度
d[l][r] 表示[l, r]只含一个折叠的最短即(...)
⭐注意到能[l, k](k < r)折叠 d[l][r],
但 d[l][r] != (k - l + 1) + cnt(折叠数字位数) + 2["()"]
而是 d[l][r] = f[l][k] + cnt(折叠数字位数) + 2["()"]
打印答案时也是, 对于循环[l, k] 也要去打印其折叠串
int n, m, _, k, cas;
int f[N][N], d[N][N], len[N][N];
char s[N];
int work(int l, int r, int k) {
if ((r - l + 1) % k) return 1000;
rep (i, k + l, r) if (s[i] != s[(i - l) % k + l]) return 1000;
int cnt = (r - l + 1) / k;
return f[l][l + k - 1] + 3 + cnt / 100 + (cnt > 9);
}
void dfs(int l, int r) {
if (r - l + 1 <= 4) { rep (i, l, r) cout << s[i]; return; }
if (f[l][r] == d[l][r]) {
if (d[l][r] != r - l + 1) cout << (r - l + 1) / len[l][r] << '(';
if (f[l][l + len[l][r] - 1] == len[l][r])
rep (i, l, l + len[l][r] - 1) cout << s[i];
else dfs(l, l + len[l][r] - 1);
if (len[l][r] != r - l + 1) cout << ')'; return;
}
rep (k, l, r - 1) if (f[l][k] + f[k + 1][r] == f[l][r]) {
dfs(l, k), dfs(k + 1, r); return;
}
}
int main() {
IOS; cin >> s + 1; n = strlen(s + 1); memset(f, 0x3f, sizeof f);
rep (i, 1, n) rep (l, 1, n) {
d[l][l + i - 1] = i, len[l][l + i - 1] = i;
rep (k, l, l + i - 2) {
umin(f[l][l + i - 1], f[l][k] + f[k + 1][l + i - 1]);
int cur = work(l, l + i - 1, k - l + 1);
if (umin(d[l][l + i - 1], cur)) len[l][l + i - 1] = k - l + 1;
}
umin(f[l][l + i - 1], d[l][l + i - 1]);
}
dfs(1, n);
return 0;
}
能量项链
ll a[N], f[N][N];
int main() {
cin >> n;
rep (i, 1, n) cin >> a[i], a[i + n] = a[i];
rep (len, 2, n) rep (l, 1, n*2-len+1) rep (k, l, l+len-2)
f[l][l+len-1]=max(f[l][l+len-1],f[l][k]+f[k+1][l+len-1]+a[l]*a[k+1]*a[l+len]);
ll ans = 0;
rep (i, 1, n) ans = max(ans, f[i][i + n - 1]);
cout << ans;
return 0;
}
⭐棋盘分割
int s[9][9];
ll f[16][9][9][9][9];
int main() {
IOS; cin >> n; memset(f, 0x3f, sizeof f);
rep (i, 1, 8) rep (j, 1, 8) {
cin >> s[i][j]; s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
rep (x, 1, i) rep (y, 1, j) f[1][x][y][i][j] = sqr(s[i][j] - s[i][y - 1] - s[x - 1][j] + s[x - 1][y - 1]);
}
rep (k, 2, n) rep (i, 1, 8) rep (j, 1, 8) rep (x, i, 8) rep (y, j, 8) {
rep (l, i, x - 1) umin(f[k][i][j][x][y], min(f[1][i][j][l][y] + f[k - 1][l + 1][j][x][y], f[k - 1][i][j][l][y] + f[1][l + 1][j][x][y]));
rep (h, j, y - 1) umin(f[k][i][j][x][y], min(f[1][i][j][x][h] + f[k - 1][i][h + 1][x][y], f[k - 1][i][j][x][h] + f[1][i][h + 1][x][y]));
}
cout << precision(3) << sqrt((double)f[n][1][1][8][8] / n - sqr((double)s[8][8] / n));
return 0;
}
⭐消木块
单独再开一维记录区间末尾的状态
int n, m, _, f[201][201][201], pre[201], ls[201], cas;
PII a[201];
int dfs(int l, int r, int len) {
if (~f[l][r][len]) return f[l][r][len];
if (l == r) return f[l][r][len] = sqr(a[l].se + len);
f[l][r][len] = dfs(l, r - 1, 0) + sqr(a[r].se + len);
for (int i = pre[r]; i >= l; i = pre[i])
umax(f[l][r][len], dfs(l, i, len + a[r].se) + dfs(i + 1, r - 1, 0));
return f[l][r][len];
}
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n; m = 1; memset(f, -1, sizeof f); memset(ls, 0, sizeof ls);
rep (i, 1, n) {
cin >> a[m].fi;
if (a[m].fi == a[m - 1].fi) ++a[m - 1].se;
else pre[m] = ls[a[m].fi], ls[a[m].fi] = m, a[m++].se = 1;
}
cout << "Case " << ++cas << ": " << dfs(1, m - 1, 0) << '\n';
}
return 0;
}
战略游戏
int f[N][2];
VI h[N];
bool vs[N];
void dfs(int x) {
for (auto& y : h[x]) {
dfs(y); f[x][1] += min(f[y][1], f[y][0]);
f[x][0] += f[y][1];
}
}
int main() {
while (~scanf("%d", &n)) {
rep (i, 0, n - 1) h[i].resize(0), f[i][0] = 0, f[i][1] = 1, vs[i] = 0;
rep (i, 0, n - 1) {
int u, k, v; scanf("%d:(%d)", &u, &k);
rep (i, 1, k) scanf("%d", &v), h[u].pb(v), vs[v] = 1;
}
int rt = 0; while (vs[rt]) ++rt;
dfs(rt); printf("%d\n", min(f[rt][0], f[rt][1]));
}
return 0;
}
贿赂FIPA
int get() {
ull c = 0;
for (int i = 0; s[i]; ++i) c = c * P + s[i];
return st.count(c) ? st[c] : (st[c] = st.size() + 1, st.size());
}
void dfs(int x) {
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]]) dfs(y), sz[x] += sz[y];
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]]) per(j, sz[x], 0)
per(k, min(sz[y], j), 1) umin(f[x][j], f[x][j - k] + f[y][k]);
if (x) rep(j, 0, sz[x]) umin(f[x][j], a[x]);
}
int main() {
while (read(n), n) {
read(m); unordered_map<ull, int>().swap(st); memset(f, 0x3f, sizeof f); tot = 0;
rep(i, 0, n) fa[i] = 1, f[i][0] = h[i] = 0, sz[i] = 1;
rep(i, 1, n) {
int u, v; scanf("%s", s); scanf("%d", &a[u = get()]);
for (char c = getchar(); c != '\n'; c = getchar())
scanf("%s", s), fa[v = get()] = 0, add(u, v);
}
rep(i, 1, n) if (fa[i]) add(0, i);
dfs(0); cout << f[0][m] << '\n';
}
return 0;
}
计算机
PII d[N][2];
vector<PII> h[N];
void dfs(int x, int fa) {
for (auto& [y, c] : h[x]) if (y ^ fa) {
dfs(y, x);
if (d[y][0].fi + c >= d[x][0].fi) d[x][1] = d[x][0], d[x][0] = { d[y][0].fi + c, y };
else if (umax(d[x][1].fi, d[y][0].fi + c)) d[x][1].se = y;
}
if (d[x][0].fi < 0) d[x][0] = { 0, x };
}
void dfss(int x, int fa) {
for (auto& [y, c] : h[x]) if (y ^ fa) {
int g = d[x][0].se == y;
if (d[x][g].fi + c >= d[y][0].fi) d[y][1] = d[y][0], d[y][0] = { d[x][g].fi + c, x };
else if (umax(d[y][1].fi, d[x][g].fi + c)) d[y][1].se = x;
dfss(y, x);
}
}
int main() {
IOS;
while (cin >> n) {
memset(d, 0xcf, sizeof d); rep (i, 1, n) h[i].resize(0);
rep(i, 2, n) { int v, c; cin >> v >> c; h[i].pb(v, c); h[v].pb(i, c); }
dfs(1, -1); dfss(1, -1); rep(i, 1, n) cout << d[i][0].fi << '\n';
}
return 0;
}
异或路径
int n, m, _, k;
int h[N], to[M << 1], ne[M << 1], co[M << 1], tot;
long double cnt[N];
void add(int u, int v, int c) {
ne[++tot] = h[u]; to[h[u] = tot] = v; co[tot] = c;
}
long double a[N][N];
int gauss(int n, int m) {
int c = 1, r = 1;
for (int t = r; c < m && r <= n; ++c, t = r) {
for (int i = r + 1; i <= n; ++i) if (fabs(a[i][c]) > fabs(a[t][c])) t = i;
if (fabs(a[t][c]) < eps) continue;
if (t != r) for (int i = 1; i <= m; ++i) swap(a[t][i], a[r][i]);
for (int i = c + 1; i <= m; ++i) a[r][i] /= a[r][c]; a[r][c] = 1;
for (int i = r + 1; i <= n; ++i)
if (a[i][c]) {
for (int j = c + 1; j <= m; ++j) a[i][j] -= a[i][c] * a[r][j];
a[i][c] = 0;
}
++r;
}
rep (i, r, n) if (a[i][m]) return -1;
if (r < m) return 0;
per (i, m - 2, 1) rep (j, i + 1, m) a[i][m] -= a[j][m] * a[i][j];
return 1;
}
int main() {
IOS; cin >> n >> m;
rep (i, 1, m) {
int u, v, co; cin >> u >> v >> co;
add(u, v, co); cnt[u] += 1;
if (u ^ v) cnt[v] += 1, add(v, u, co);
}
double ans = 0;
rep (i, 0, 29) {
memset(a, 0, sizeof a);
rep (j, 1, n - 1) {
a[j][j] = 1;
for (int k = h[j], y = to[k]; k; y = to[k = ne[k]]) {
double w = 1 / cnt[j];
if ((co[k] >> i) & 1) a[j][y] += w, a[j][n + 1] += w;
else a[j][y] -= w;
}
}
a[n][n] = 1; gauss(n, n + 1); ans += a[1][n + 1] * (1 << i);
}
cout << setiosflags(ios::fixed) << setprecision(3) << ans << '\n';
return 0;
}
岛和桥
ll d[M][M], a[M], g[M][M][M], s;
PLL f[N][M][M];
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n >> m; s = 0; memset(d, 0, sizeof d); memset(g, 0, sizeof g);
rep(i, 0, n - 1) cin >> a[i], s += a[i]; memset(f, 0xcf, sizeof f);
rep(i, 1, m) {
int u, v; cin >> u >> v; --u, --v;
if (u ^ v) d[u][v] = d[v][u] = a[u] * a[v],
f[1 << u ^ 1 << v][u][v] = f[1 << u ^ 1 << v][v][u] = { d[v][u], 1 };
}
rep(i, 0, n - 1) rep(j, 0, n - 1) rep(k, 0, n - 1)
if (d[i][j] && d[j][k] && d[k][i]) g[i][j][k] = a[i] * a[j] * a[k];
rep(i, 0, (1 << n) - 1) rep(x, 0, n - 1) if (i >> x & 1) rep(y, 0, n - 1)
if ((y ^ x) && (i >> y & 1) && d[x][y]) rep(k, 0, n - 1)
if ((y ^ k) && (x ^ k) && (i >> k & 1) && ~f[i ^ 1 << y][k][x].fi)
if (umax(f[i][x][y].fi, f[i ^ 1 << y][k][x].fi + d[x][y] + g[k][x][y]))
f[i][x][y].se = f[i ^ 1 << y][k][x].se;
else if (f[i][x][y].fi == f[i ^ 1 << y][k][x].fi + d[x][y] + g[k][x][y])
f[i][x][y].se += f[i ^ 1 << y][k][x].se;
PII ans = { 0, 0 };
rep(i, 0, n - 1) rep(j, 0, n - 1) if (i ^ j)
if (umax(ans.fi, f[(1 << n) - 1][i][j].fi)) ans.se = f[(1 << n) - 1][i][j].se;
else if (ans.fi == f[(1 << n) - 1][i][j].fi) ans.se += f[(1 << n) - 1][i][j].se;
cout << ans.fi + (ans.se ? s : 0) << ' ' << ans.se / 2 << '\n';
}
return 0;
}
玉米田
int f[13][N], g[13];
bool v[N];
int main() {
IOS; cin >> n >> m; f[0][0] = 1;
rep (i, 1, n) rep(j, 0, m - 1) cin >> k, g[i] ^= k << j;
rep (i, 0, (1 << m) - 1) rep (j, 0, m - 1) if (i >> j & 1)
rep (k, j + 1, m - 1) if ((i >> k & 1) && k - j < 2) v[i] = 1;
rep (i, 1, n) rep (k, 0, (1 << m) - 1) if (f[i - 1][k])
rep (j, 0, (1 << m) - 1) if (!(k & j) && !v[j] && (j & g[i]) == j)
f[i][j] = (f[i][j] + f[i - 1][k]) % mod;
rep (i, 0, (1 << m) - 1) _ = (_ + f[n][i]) % mod; cout << _;
return 0;
}
芯片
int f[2][59049], p[11];
bool v[N][M];
void dfs(int k, int st, int c, int q, int num) {
if (q == m) { umax(f[k & 1][c], f[k & 1 ^ 1][st] + num); umax(cas, f[k & 1][c]); return; }
if (st / p[q] % 3) { dfs(k, st, c + p[q] * (st / p[q] % 3 - 1), q + 1, num); return; }
if (k < n && q < m-1 && !v[k][q] && !v[k][q + 1] && !v[k + 1][q] && !v[k + 1][q + 1] && !(st/p[q+1]%3)) {
if (q < m - 2 && !v[k][q + 2] && st / p[q + 2] % 3 == 0 && !v[k + 1][q + 2])
dfs(k, st, c + p[q] * 13, q + 3, num + 1);
if (k < n - 1 && !v[k + 2][q] && !v[k + 2][q + 1]) dfs(k, st, c + p[q] * 8, q + 2, num + 1);
}
dfs(k, st, c, q + 1, num);
}
int main() {
IOS; p[0] = 1; rep(i, 1, 10) p[i] = p[i - 1] * 3; memset(f[1], -1, sizeof f[1]);
for (cin >> _; _; --_) {
memset(f[n & 1], -1, sizeof f[0]); f[0][0] = 0; cas = -1;
cin >> n >> m >> k; memset(v, 0, sizeof v);
rep(i, 1, k) { int x, y; cin >> x >> y; v[x][--y] = 1; }
rep(i, 1, n) rep(j, 0, p[m] - 1) if (~f[i & 1 ^ 1][j])
dfs(i, j, 0, 0, 0), f[i & 1 ^ 1][j] = -1;
cout << cas << '\n';
}
return 0;
}
围栏障碍训练场
struct BIT {
struct node { int l, r, val, tag; } tr[N * 20];
void push_down(int rt) {
if (!tr[rt].tag) return;
tr[rt << 1].val = tr[rt << 1 | 1].val =
tr[rt << 1].tag = tr[rt << 1 | 1].tag = tr[rt].tag;
tr[rt].tag = 0;
}
void build(int rt, int l, int r) {
tr[rt].l = l, tr[rt].r = r, tr[rt].val = tr[rt].tag = 0;
if (l == r) return;
int mid = l + r >> 1; build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
}
void change(int rt, int l, int r, int k) {
if (tr[rt].l >= l && tr[rt].r <= r) { tr[rt].tag = tr[rt].val = k; return; }
int mid = tr[rt].l + tr[rt].r >> 1; push_down(rt);
if (mid >= l) change(rt << 1, l, r, k);
if (mid < r) change(rt << 1 | 1, l, r, k);
}
int ask(int rt, int d) {
if (tr[rt].l == tr[rt].r) return tr[rt].val;
int mid = tr[rt].l + tr[rt].r >> 1; push_down(rt);
return ask(rt << 1 | (mid < d), d);
}
} bit;
int n, m, _, k, cas;
PII a[30005], f[30005];
int main() {
IOS; cin >> n >> m; bit.build(1, -1e5, 1e5);
rep (i, 1, n) {
cin >> a[i].fi >> a[i].se;
int l = bit.ask(1, a[i].fi), r = bit.ask(1, a[i].se);
f[i].fi = min(f[l].fi + abs(a[l].fi - a[i].fi), f[l].se + abs(a[l].se - a[i].fi));
f[i].se = min(f[r].fi + abs(a[r].fi - a[i].se), f[r].se + abs(a[r].se - a[i].se));
bit.change(1, a[i].fi, a[i].se, i);
}
cout << min(f[n].fi + abs(a[n].fi - m), f[n].se + abs(a[n].se - m));
return 0;
}
图论
最短路
通信线路
int check(int m) {
deque<pair<int, int>> q; q.push_back({1, 0});
memset(d, 0x3f, sizeof d); d[1] = 0;
while (!q.empty()) {
int x = q.front().first; q.pop_front();
if (x == n) return d[x];
for (auto &y : h[x])
if (y.second > m && d[y.first] > d[x] + 1) q.push_back({y.first, d[y.first] = d[x] + 1});
else if (y.second <= m && d[y.first] > d[x]) q.push_front({y.first, d[y.first] = d[x]});
}
cout << -1; exit(0); return -1;
}
int main() {
cin >> n >> m >> k;
for (int i = 1; i <= m; ++i) {
int u, v, c; cin >> u >> v >> c;
h[u].push_back({v, c}); h[v].push_back({u, c});
}
int l = 0, r = 1000000;
while (l < r) {
int mid = (l + r) >> 1;
if (check(mid) > k) l = mid + 1;
else r = mid;
}
cout << r;
return 0;
}
最优贸易
void dij(int k, int s){
d[k][s] = a[s];
priority_queue<PII> q; q.push({a[s], s});
while (!q.empty()) {
PII p = q.top(); q.pop();
int x = p.second, co = p.first;
if (k && d[1][x] > co) continue;
else if (!k && d[0][x] < -co) continue;
for (int i : h[k][x])
if (k && d[1][i] < max(a[i], d[1][x])) d[1][i] = max(d[1][x], a[i]), q.push({d[1][i], i});
else if (!k && d[0][i] > min(a[i], d[0][x])) d[0][i] = min(d[0][x], a[i]), q.push({-d[0][i], i});
}
}
int main() {
cin >> n >> m; memset(d[0], 0x3f3f, sizeof d[0]);
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 1, u, v, z; i <= m; ++i) {
cin >> u >> v >> z;
h[0][u].pb(v); h[1][v].pb(u);
if (z == 2) h[0][v].pb(u), h[1][u].pb(v);
}
dij(0, 1); dij(1, n);
int ans = 0;
for (int i = 1; i <= n; ++i) ans = max(ans, d[1][i] - d[0][i]);
cout << ans;
return 0;
}
⭐道路与航线
int n, m1, m2, s, f[N], deg[N];
bool v[N];
ll d[N];
vector<pair<int, int>> h[N];
vector<int> a[N];
int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); }
void unit(int x, int y) { x = find(x), y = find(y); if (x != y) f[y] = x; }
int main() {
memset(d, 0x3f, sizeof d);
cin >> n >> m1 >> m2 >> s;
for (int i = 1; i <= n; ++i) f[i] = i;
for (int i = 0; i < m1; ++i) {
int u, v, c; cin >> u >> v >> c; unit(u, v);
h[u].emplace_back(v, c); h[v].emplace_back(u, c);
}
for (int i = 1; i <= n; ++i) a[find(i)].emplace_back(i);
for (int i = 0; i < m2; ++i) {
int u, v, c; cin >> u >> v >> c;
h[u].emplace_back(v, c); ++deg[f[v]];
}
queue<int> qu; qu.push(f[s]); d[s] = 0;
for (int i = 1; i <= n; ++i) if (i == f[i] && i != f[s] && !deg[i]) qu.push(i);
while (!qu.empty()) {
int cur = qu.front(); qu.pop();
priority_queue<pair<ll, int>> q;
for (auto &i : a[cur]) q.push({-d[i], i});
while (!q.empty()) {
int x = q.top().second; q.pop();
if (v[x]) continue; v[x] = 1;
for (auto &y : h[x]) {
if (d[y.first] > d[x] + y.second) {
d[y.first] = d[x] + y.second;
if (f[x] == f[y.first]) q.push({-d[y.first], y.first});
}
if (f[x] != f[y.first] && --deg[f[y.first]] == 0) qu.push(f[y.first]);
}
}
}
for (int i = 1; i <= n; ++i)
if (d[i] >= 1e9) cout << "NO PATH\n";
else cout << d[i] << '\n';
return 0;
}
排序
int flo() {
for (int k = 0; k < n; ++k) for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) if (i != j)
if (!d[i][j] && d[i][k] && d[k][j]) d[i][j] = 1, ++ans[i];
else if (d[i][j] && d[j][i]) return -1;
sort(rk, rk + n, [](int a, int b) { return ans[a] < ans[b]; });
bool flag = 1;
for (int i = 0; i < n; ++i) if (i != ans[rk[i]]) return 0;
return flag;
}
int main() {
while (cin >> n >> m, n + m) {
memset(d, 0, sizeof d); int g = 0;
for (int i = 0; i < n; ++i) ans[i] = 0, rk[i] = i;
for (int i = 1, u, v; i <= m; ++i) {
cin >> s; if (g) continue;
u = s[2] - 'A', v = s[0] - 'A';
if (d[u][v]) continue; d[u][v] = 1, ++ans[u];
int res = flo();
if (res == -1) g = -i;
else if (res == 1) g = i;
}
if (g < 0) cout << "Inconsistency found after " << -g << " relations.\n";
else if (!g) cout << "Sorted sequence cannot be determined.\n";
else {
cout << "Sorted sequence determined after " << g << " relations: ";
for (int i = 0; i < n; ++i) cout << char('A' + rk[i]); cout << '.' << '\n';
}
}
return 0;
}
观光之旅
void find(int u, int v) {
if (!f[u][v]) b[++tot] = u;
else find(u, f[u][v]), find(f[u][v], v);
}
int main() {
cin >> n >> m; memset(a, 0x3f, sizeof a);
for (int i = 1; i <= n; ++i) a[i][i] = 0;
for (int i = 0; i < m; ++i) {
int u, v, c; cin >> u >> v >> c;
a[u][v] = a[v][u] = min(a[v][u], c);
}
int ans = 0x3f3f3f3f; memcpy(d, a, sizeof a);
for (int k = 1; k <= n; ++k) {
for (int i = 1; i < k; ++i) for (int j = i + 1; j < k; ++j) if (ans > (long long)d[i][j] + a[i][k] + a[k][j])
ans = d[i][j] + a[i][k] + a[k][j], tot = 0, find(i, j), b[++tot] = j, b[++tot] = k;
for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) if (d[i][j] > d[i][k] + d[k][j])
d[i][j] = d[i][k] + d[k][j], f[i][j] = k;
}
if (ans == 0x3f3f3f3f) return cout << "No solution.", 0;
for (int i = 1; i <= tot; ++i) cout << b[i] << ' ';
return 0;
}
牛站
int u[N], v[N], c[N];
vector<vector<ll>> a;
vector<int> x;
vector<vector<ll>> mul(vector<vector<ll>>& a, vector<vector<ll>>& b) {
vector<vector<ll>> ans(x.size(), vector<ll>(x.size(), 1e18));
for (int i = 0; i < x.size(); ++i) for (int j = 0; j < x.size(); ++j) for (int k = 0; k < x.size(); ++k)
ans[i][j] = min(ans[i][j], a[i][k] + b[k][j]);
return ans;
}
vector<vector<ll>> qpow(vector<vector<ll>> a, int b) {
vector<vector<ll>> ans(x.size(), vector<ll>(x.size(), 1e18));
for (int i = 0; i < x.size(); ++i) ans[i][i] = 0;
for (; b; b >>= 1, a = mul(a, a)) if (b & 1) ans = mul(ans, a);
return ans;
}
int main() {
cin >> n >> t >> s >> e;
for (int i = 0; i < t; ++i) cin >> c[i] >> u[i] >> v[i], x.push_back(u[i]), x.push_back(v[i]);
sort(x.begin(), x.end()); x.erase(unique(x.begin(), x.end()), x.end());
vector<vector<ll>>(x.size(), vector<ll>(x.size(), 1e18)).swap(a);
for (int i = 0; i < t; ++i) {
u[i] = lower_bound(x.begin(), x.end(), u[i]) - x.begin();
v[i] = lower_bound(x.begin(), x.end(), v[i]) - x.begin();
a[u[i]][v[i]] = a[v[i]][u[i]] = c[i];
}
a = qpow(a, n);
s = lower_bound(x.begin(), x.end(), s) - x.begin();
e = lower_bound(x.begin(), x.end(), e) - x.begin();
cout << a[s][e] << '\n';
return 0;
}
最小生成树
走廊泼水节
struct node { int x, y, c; } e[N];
int n, m, _;
int f[N], sz[N];
int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); }
int main() {
for (cin >> _; _; --_) {
cin >> n; long long ans = 0;
for (int i = 1; i <= n; ++i) f[i] = i, sz[i] = 1;
for (int i = 0; i < n - 1; ++i) cin >> e[i].x >> e[i].y >> e[i].c;
sort(e, e + n - 1, [](node& a, node& b) { return a.c < b.c; });
for (int i = 0; i < n - 1; ++i) {
int x = find(e[i].x), y = find(e[i].y);
if (x == y) continue;
ans += (sz[x] * sz[y] - 1ll) * (e[i].c + 1);
f[y] = x, sz[x] += sz[y];
}
cout << ans << "\n";
}
return 0;
}
野餐规划
int n, f[N], d[N], ans, s, m;
string t;
unordered_map<string, int> st;
int get(string& s) {
if (st.count(s)) return st[s];
return st[s] = st.size(), st.size() - 1;
}
int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); }
int main() {
t = "Park"; get(t); cin >> n; long long ans = 0;
for (int i = 0; i < n; ++i) {
cin >> t; e[i].x = get(t); cin >> t >> e[i].c; e[i].y = get(t);
} sort(e, e + n, [](node& a, node& b) { return a.c < b.c; });
cin >> s; m = st.size() - 1;
for (int i = 1; i <= m; ++i) f[i] = i, d[i] = 1e9;
vector<int> a;
for (int i = 0; i < n; ++i) {
int x = find(e[i].x), y = find(e[i].y);
if (x == y) continue;
if (x > y) swap(x, y);
if (!x) { d[y] = min(d[y], e[i].c); continue; }
if (max(d[x], d[y]) == 1e9) f[y] = x, ans += e[i].c, d[x] = min(d[x], d[y]), --m;
else a.push_back(i);
}
for (int i = 1; i < st.size(); ++i) if (i == f[i]) ans += d[i];
priority_queue<int> q;
for (auto& i : a) q.push(max(d[find(e[i].x)], d[find(e[i].y)]) - e[i].c);
while (m > s) --m, ans -= q.top(), q.pop();
cout << "Total miles driven: " << ans;
return 0;
}
沙漠之王
double ans, e[N][N], dis[N];
bool check(double x) {
for (int i = 0; i < n; ++i) dis[i] = 2e9, v[i] = 0; dis[0] = ans = 0;
for (int i = 1; i<= n; ++i) {
double mi = 2e9; int now;
for (int j = 0; j < n; ++j) if(!v[j] && dis[j] < mi) mi = dis[j], now = j;
v[now] = 1; ans += dis[now];
for (int j = 0; j < n; ++j) dis[j] = min(dis[j], abs(ve[now].z - ve[j].z) - x * e[now][j]);
}
return ans > 0;
}
int main() {
while (cin >> n, n) {
for (int i = 0, x, y, z; i < n; ++i) cin >> ve[i].x >> ve[i].y >> ve[i].z;
for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j)
e[i][j] = sqrt(0.0 + sqr(ve[i].x - ve[j].x) + sqr(ve[i].y - ve[j].y));
double l = 0, r = 2e9;
while(r - l > 1e-6) {
double mid = (l + r) / 2;
if (check(mid)) l = mid;
else r = mid;
}
cout << setiosflags(ios::fixed) << setprecision(3) << l << '\n';
}
return 0;
}
黑暗城堡
void dij() {
memset(d, 0x3f, sizeof d); d[1] = 0;
priority_queue<pair<int, int>> q; q.push({0, 1});
while (!q.empty()) {
int x = q.top().second; q.pop();
if (v[x]) continue; v[x] = 1;
for (auto &y : h[x]) if (d[y.first] > d[x] + y.second) {
d[y.first] = d[x] + y.second;
q.push({ -d[y.first], y.first });
}
}
}
int main() {
cin >> n >> m; long long ans = 1;
for (int i = 1; i <= m; ++i) {
int u, v, c; cin >> u >> v >> c;
h[u].emplace_back(v, c); h[v].emplace_back(u, c);
} dij();
for (int x = 2; x <= n; ++x) {
int cur = 0;
for (auto &y : h[x]) if (d[x] - d[y.first] == y.second) ++cur;
ans = (ans * cur) % mod;
}
cout << ans;
return 0;
}
树的直径与最近公共祖先
⭐巡逻
struct edge { int t, c, w; };
int n, m, _;
int d[N], s1, s2;
vector<edge> h[N];
pair<int, int> pre[N];
void dfs(int x, int fa, int& s) {
for (int i = 0; i < h[x].size(); ++i) if (h[x][i].t != fa) {
d[h[x][i].t] = d[x] + h[x][i].c; pre[h[x][i].t] = { x, i };
if (d[0] < d[h[x][i].t]) d[0] = d[s = h[x][i].t];
dfs(h[x][i].t, x, s);
}
}
int work() {
d[0] = 0; d[1] = 0; dfs(1, 0, s1);
d[0] = 0; d[s1] = 0; pre[s1] = { 0, 0 }; dfs(s1, 0, s2);
for (auto i = pre[s2]; i.first; i = pre[i.first])
h[i.first][i.second].c = -1, h[h[i.first][i.second].t][h[i.first][i.second].w].c = -1;
return d[0];
}
void dp(int x, int fa, int& ans) {
for (auto &y : h[x]) if (y.t != fa) {
d[y.t] = 0; dp(y.t, x, ans);
ans = max(ans, d[x] + d[y.t] + y.c);
d[x] = max(d[x], d[y.t] + y.c);
}
}
int main() {
cin >> n >> m; long long ans = n - 1 << 1;
for (int i = 2; i <= n; ++i) {
int u, v; cin >> u >> v;
h[u].push_back({v, 1, h[v].size()}); h[v].push_back({u, 1, h[u].size() - 1});
}
ans -= work() - 1; if (m == 2) d[1] = s1 = 0, dp(1, 0, s1), ans -= s1 - 1;
cout << ans;
return 0;
}
⭐树网的核
int n, m, _;
int f[N], p, q;
long long d[N], mx, ans = 2e18;
vector<pair<int, int>> h[N];
void dfs(int x, int fa, int& s) {
for (auto& y : h[x]) if (y.first != fa) {
d[y.first] = d[x] + y.second; f[y.first] = x;
if (d[0] < d[y.first]) d[0] = d[s = y.first];
dfs(y.first, x, s);
}
}
void work() {
f[1] = d[1] = 0; dfs(1, 0, p);
d[0] = f[p] = d[p] = 0; dfs(p, 0, q);
}
void dfs(int x, int fa) {
for (auto& y : h[x]) if (y.first != fa) {
mx = max(mx, d[y.first] = d[x] + y.second);
dfs(y.first, x);
}
}
int main() {
IOS; cin >> n >> m;
for (int i = 1; i < n; ++i) {
int u, v, c; cin >> u >> v >> c;
h[u].emplace_back(v, c); h[v].emplace_back(u, c);
}
work();
for (int i = q, j = 0; i; j = i, i = f[i]) for (auto& y : h[i])
if (y.first != j && y.first != f[i]) mx = max(mx, d[y.first] = y.second), dfs(y.first, i);
for (int i = q, j = q; i; i = f[i]) {
while (f[j] && d[i] - d[f[j]] <= m) j = f[j];
ans = min(ans, max(mx, max(d[j], d[q] - d[i])));
}
cout << ans;
return 0;
}
闇の連鎖
struct STFrom {
int f[N][20], dep[N], lg[N], t;//N为节点的数量
vector<int>* h;
void init(int n, vector<int>* H) {
t = log2(n - 1) + 1; h = H; lg[0] = -1;
rep(i, 1, n) dep[i] = 0, lg[i] = lg[i >> 1] + 1;
}
void bfs(int s) {
queue<int> q; q.push(s); dep[s] = 1;
rep(i, 0, t) f[s][i] = 0;
while (!q.empty()) {
int x = q.front(); q.pop();
for (auto& y : h[x]) {
if (dep[y]) continue;
dep[y] = dep[x] + 1; f[y][0] = x; q.push(y);
for (int j = 1; j <= t; ++j) f[y][j] = f[f[y][j - 1]][j - 1];
}
}
}
int lca(int x, int y) {
if (dep[x] > dep[y]) swap(x, y);
for (int k = dep[y] - dep[x], i = lg[k]; ~i; --i) if (k >> i & 1) y = f[y][i];
if (x == y) return x;
per(i, lg[dep[y]], 0) if (f[x][i] ^ f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
int dist(int x, int y) { return dep[x] + dep[y] - (dep[lca(x, y)] << 1); }
} ST;
int n, m, _, s[N];
long long ans;
vector<int> h[N];
void dfs(int x, int fa) {
for (auto& y : h[x]) if (y != fa) {
dfs(y, x); s[x] += s[y];
if (s[y] == 1) ++ans;
else if (!s[y]) ans += m;
}
}
int main() {
cin >> n >> m;
rep(i, 2, n) {
int u, v; cin >> u >> v;
h[u].push_back(v); h[v].push_back(u);
}
ST.init(n, h); ST.bfs(1);
rep(i, 1, m) {
int u, v, z; cin >> u >> v; z = ST.lca(u, v);
++s[u], --s[z]; ++s[v], --s[z];
}
dfs(1, 0); cout << ans;
return 0;
}
⭐雨天的尾巴
struct STFrom {
int f[N][20], dep[N], lg[N], t;//N为节点的数量
vector<int>* h;
void init(int n, vector<int>* H) {
t = log2(n - 1) + 1; h = H; lg[0] = -1;
rep(i, 1, n) dep[i] = 0, lg[i] = lg[i >> 1] + 1;
}
void bfs(int s) {
queue<int> q; q.push(s); dep[s] = 1;
rep(i, 0, t) f[s][i] = 0;
while (!q.empty()) {
int x = q.front(); q.pop();
for (auto& y : h[x]) {
if (dep[y]) continue;
dep[y] = dep[x] + 1; f[y][0] = x; q.push(y);
for (int j = 1; j <= t; ++j) f[y][j] = f[f[y][j - 1]][j - 1];
}
}
}
int lca(int x, int y) {
if (dep[x] > dep[y]) swap(x, y);
for (int k = dep[y] - dep[x], i = lg[k]; ~i; --i) if (k >> i & 1) y = f[y][i];
if (x == y) return x;
per(i, lg[dep[y]], 0) if (f[x][i] ^ f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
int dist(int x, int y) { return dep[x] + dep[y] - (dep[lca(x, y)] << 1); }
} ST;
struct BIT {
struct node { int l, r, val, mx; } tr[70 * N];
int rt[N], tot;
void push_up(int rt) {
if (tr[tr[rt].l].mx >= tr[tr[rt].r].mx) tr[rt].mx = tr[tr[rt].l].mx, tr[rt].val = tr[tr[rt].l].val;
else tr[rt].mx = tr[tr[rt].r].mx, tr[rt].val = tr[tr[rt].r].val;
}
void change(int& p, int l, int r, int d, int k) {
if (!p) p = ++tot;
if (l == r) { tr[p].val = l, tr[p].mx += k; return; }
int mid = l + r >> 1;
if (d <= mid) change(tr[p].l, l, mid, d, k);
else change(tr[p].r, mid + 1, r, d, k);
push_up(p);
}
void merge(int& x, int y, int l, int r) {
if (!x) { x = y; return; }
if (!y) return;
if (l == r) { tr[x].mx += tr[y].mx; return; }
int mid = l + r >> 1;
merge(tr[x].l, tr[y].l, l, mid); merge(tr[x].r, tr[y].r, mid + 1, r);
push_up(x);
}
int ask(int x) { return tr[x].val; }
} bit;
int n, m, ans[N];
int x[N], y[N], z[N], w[N];
vector<int> h[N], c;
void dfs(int x, int fa) {
for (auto& y : h[x]) if (y != fa) {
dfs(y, x);
bit.merge(bit.rt[x], bit.rt[y], 1, c.size() - 1);
}
ans[x] = bit.ask(bit.rt[x]);
}
int main() {
IOS; cin >> n >> m; c.push_back(0);
rep(i, 2, n) {
int u, v; cin >> u >> v;
h[u].push_back(v); h[v].push_back(u);
}
ST.init(n, h); ST.bfs(1);
rep(i, 1, m) cin >> x[i] >> y[i] >> w[i], z[i] = ST.lca(x[i], y[i]), c.push_back(w[i]);
sort(c.begin(), c.end()); c.erase(unique(c.begin(), c.end()), c.end());
rep(i, 1, m) {
w[i] = lower_bound(c.begin(), c.end(), w[i]) - c.begin();
bit.change(bit.rt[x[i]], 1, c.size() - 1, w[i], 1);
bit.change(bit.rt[y[i]], 1, c.size() - 1, w[i], 1);
bit.change(bit.rt[z[i]], 1, c.size() - 1, w[i], -1);
bit.change(bit.rt[ST.f[z[i]][0]], 1, c.size() - 1, w[i], -1);
}
dfs(1, 0);
rep(i, 1, n) cout << c[ans[i]] << '\n';
return 0;
}
⭐天天爱跑步
这道题之所以不需要权值动态线段树, 和雨天的尾巴不同, 是因为贡献具有可加性
struct STFrom {
int f[N][20], dep[N], lg[N], t;//N为节点的数量
vector<int> *h;
void init(int n, vector<int>* H) {
t = log2(n - 1) + 1; h = H; lg[0] = -1;
rep(i, 1, n) dep[i] = 0, lg[i] = lg[i >> 1] + 1;
}
void bfs(int s) {
queue<int> q; q.push(s); dep[s] = 1;
rep(i, 0, t) f[s][i] = 0;
while (!q.empty()) {
int x = q.front(); q.pop();
for (auto &y : h[x]) {
if (dep[y]) continue;
dep[y] = dep[x] + 1; f[y][0] = x; q.push(y);
for (int j = 1; j <= t; ++j) f[y][j] = f[f[y][j - 1]][j - 1];
}
}
}
int lca(int x, int y) {
if (dep[x] > dep[y]) swap(x, y);
for(int k = dep[y] - dep[x], i = lg[k]; ~i; --i) if (k >> i & 1) y = f[y][i];
if (x == y) return x;
per(i, lg[dep[y]], 0) if (f[x][i] ^ f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
int dist(int x, int y) { return dep[x] + dep[y] - (dep[lca(x, y)]<<1); }
} ST;
int n, m, w[N], s[N], ans[N], x[N], y[N << 1];
vector<pair<int, int>> a[N], b[N << 1];
vector<int> h[N];
void dfs(int u, int fa) {
int res = x[ST.dep[u] + w[u]] + y[ST.dep[u] - w[u] + n];
for (auto &v : h[u]) if (v != fa) dfs(v, u);
for (auto &i : a[u]) x[i.first] += i.second;
for (auto &i : b[u]) y[i.first] += i.second;
ans[u] = x[ST.dep[u] + w[u]] + y[ST.dep[u] - w[u] + n] - res;
}
int main() {
IOS; cin >> n >> m;
rep (i, 2, n) {
int u, v; cin >> u >> v;
h[u].push_back(v); h[v].push_back(u);
}
ST.init(n, h); ST.bfs(1);
rep (i, 1, n) cin >> w[i];
rep (i, 1, m) {
int u, v, z; cin >> u >> v; z = ST.lca(u, v);
a[u].emplace_back(ST.dep[u], 1);
a[ST.f[z][0]].emplace_back(ST.dep[u], -1);
b[v].emplace_back(2 * ST.dep[z] - ST.dep[u] + n, 1);
b[z].emplace_back(2 * ST.dep[z] - ST.dep[u] + n, -1);
}
dfs(1, 0);
rep (i, 1, n) cout << ans[i] << ' ';
return 0;
}
⭐异象石(时间戳妙用)
每次添加或删除x, 找到x的p, q(时间戳环上的前驱后继), 贡献为dist(x, p) + dist(x, q) - dist(p, q)
答案 / 2即可
struct STFrom {
int f[N][20], dep[N], lg[N], t;//N为节点的数量
vector<pair<int, int>> *h;
ll d[N];
void init(int n, vector<pair<int ,int>>* H) {
t = log2(n - 1) + 1; h = H; lg[0] = -1;
rep(i, 1, n) dep[i] = 0, lg[i] = lg[i >> 1] + 1;
}
void bfs(int s) {
queue<int> q; q.push(s); dep[s] = 1; d[s] = 0;
rep(i, 0, t) f[s][i] = 0;
while (!q.empty()) {
int x = q.front(); q.pop();
for (auto &y : h[x]) {
if (dep[y.first]) continue;
dep[y.first] = dep[x] + 1; f[y.first][0] = x;
q.push(y.first); d[y.first] = d[x] + y.second;
for (int j = 1; j <= t; ++j) f[y.first][j] = f[f[y.first][j - 1]][j - 1];
}
}
}
int lca(int x, int y) {
if (dep[x] > dep[y]) swap(x, y);
for(int k = dep[y] - dep[x], i = lg[k]; ~i; --i) if (k >> i & 1) y = f[y][i];
if (x == y) return x;
per(i, lg[dep[y]], 0) if (f[x][i] ^ f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
ll dist(int x, int y) { return d[x] + d[y] - (d[lca(x, y)]<<1); }
} ST;
int n, m, dfn[N], df;
vector<pair<int, int>> h[N];
set<pair<int, int>> st;
long long ans = 0;
void dfs(int x, int fa) {
dfn[x] = ++df;
for (auto &y : h[x]) if (y.first != fa) dfs(y.first, x);
}
ll get(int x) {
int p, q;
auto it = st.lower_bound({dfn[x], x});
if (it == st.end()) q = st.begin()->second;
else q = it->second;
if (it == st.begin()) p = st.rbegin()->second;
else p = (--it)->second;
return ST.dist(p, x) + ST.dist(q, x) - ST.dist(p, q);
}
int main() {
cin >> n;
rep (i, 2, n) {
int u, v, c; cin >> u >> v >> c;
h[u].emplace_back(v, c); h[v].emplace_back(u, c);
}
ST.init(n, h); ST.bfs(1); dfs(1, 0);
for (cin >> m; m; --m) {
char op; cin >> op;
if (op == '+') {
int x; cin >> x;
if (!st.empty()) ans += get(x);
st.insert({dfn[x], x});
} else if (op == '-') {
int x; cin >> x;
st.erase(st.find({dfn[x], x}));
if (!st.empty()) ans -= get(x);
}
else cout << ans / 2 << '\n';
}
return 0;
}
严格次小生成树
const int N = 1e5 + 5, M = 3e5 + 5;
struct STFrom {
int f[N][20], dep[N], lg[N], t;//N为节点的数量
ll d[N][20], b[N][20];
vector<PII> *h;
void init(int n, vector<PII> *H) {
t = log2(n - 1) + 1; h = H; lg[0] = -1;
rep(i, 1, n) dep[i] = 0, lg[i] = lg[i >> 1] + 1;
}
void bfs(int s) {
queue<int> q; q.push(s); dep[s] = 1;
rep(i, 0, t) f[s][i] = 0, d[s][i] = b[s][i] = 0;
while (!q.empty()) {
int x = q.front(); q.pop();
for (auto &y : h[x]) {
if (dep[y.fi]) continue;
dep[y.fi] = dep[x] + 1; f[y.fi][0] = x; q.push(y.fi);
d[y.fi][0] = y.se; b[y.fi][0] = -2e18;
for (int j = 1; j <= t; ++j) {
f[y.fi][j] = f[f[y.fi][j - 1]][j - 1];
if (d[f[y.fi][j - 1]][j - 1] > d[y.fi][j - 1])
b[y.fi][j] = max(d[y.fi][j - 1], b[f[y.fi][j - 1]][j - 1]),
d[y.fi][j] = d[f[y.fi][j - 1]][j - 1];
else if (d[f[y.fi][j - 1]][j - 1] == d[y.fi][j - 1])
b[y.fi][j] = max(b[y.fi][j - 1], b[f[y.fi][j - 1]][j - 1]),
d[y.fi][j] = d[y.fi][j - 1];
else b[y.fi][j] = max(b[y.fi][j - 1], d[f[y.fi][j - 1]][j - 1]),
d[y.fi][j] = d[y.fi][j - 1];
}
}
}
}
void work(PLL& ans, int y, int i) {
if (d[y][i] > ans.fi) ans.se = max(ans.fi, b[y][i]), ans.fi = d[y][i];
else if (d[y][i] == ans.fi) umax(ans.se, b[y][i]);
else umax(ans.se, d[y][i]);
}
PLL ask(int x, int y) {
PLL ans = {-2e18, -2e18};
if (dep[x] > dep[y]) swap(x, y);
for(int k = dep[y] - dep[x], i = lg[k]; ~i; --i) if (k >> i & 1)
work(ans, y, i), y = f[y][i];
if (x == y) return ans;
per(i, lg[dep[y]], 0) if (f[x][i] ^ f[y][i]) {
work(ans, x, i); work(ans, y, i);
x = f[x][i], y = f[y][i];
}
work(ans, x, 0); work(ans, y, 0);
return ans;
}
} ST;
struct edge {int x, y; ll c; bool f = 0; } e[M];
int n, m, _, k, cas;
int f[N];
ll res, ans = 2e18;
vector<PII> h[N];
int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); }
int main() {
IOS; cin >> n >> m;
rep (i, 1, m) cin >> e[i].x >> e[i].y >> e[i].c;
sort(e + 1 , e + 1 + m, [](edge& a, edge& b) { return a.c < b.c; });
rep (i, 1, n) f[i] = i;
rep (i, 1, m) {
int x = find(e[i].x), y = find(e[i].y);
if (x == y) continue;
res += e[i].c, e[i].f = 1; f[y] = x;
h[e[i].x].pb(e[i].y, e[i].c); h[e[i].y].pb(e[i].x, e[i].c);
}
ST.init(n, h); ST.bfs(1);
rep (i, 1, m) if (!e[i].f) {
auto cur = ST.ask(e[i].x, e[i].y);
if (cur.fi < e[i].c) umin(ans, res - cur.fi + e[i].c);
else if(cur.se != -2e18 && cur.se < e[i].c) umin(ans, res - cur.se + e[i].c);
}
cout << ans;
return 0;
}
疫情控制
AcWing t飞了, stl封装结构体死活过不去, 评测姬不太行, 建议牛客神机
const int N = 5e4 + 5;
int n, m, _, k;
int h[N], ne[N << 1], to[N << 1], co[N << 1], tot;
int f[N][20], dep[N], dist[N], fa[N], t;
bool v[N];
vector<PII> a, b;
VI c;
void add(int u, int v, int c) {
ne[++tot] = h[u]; h[u] = tot; to[tot] = v; co[tot] = c;
}
void bfs(int s) {
queue<int> q;
q.push(s); dep[s] = 1; dist[s] = 0;
while (!q.empty()) {
int x = q.front(); q.pop();
if (!ne[h[x]]) { c.pb(x); continue; }
for (int i = h[x]; i; i = ne[i]) {
int y = to[i];
if (dep[y]) continue;
dep[y] = dep[x] + 1;
fa[y] = x == s ? y : fa[x];
dist[y] = dist[x] + co[i];
f[y][0] = x;
for (int j = 1; j <= t; ++j)
f[y][j] = f[f[y][j - 1]][j - 1];
q.push(y);
}
}
}
int ask(int a, int b) {
per(i, t, 0)
if (dist[a] - dist[f[a][i]] <= b) b -= dist[a] - dist[a = f[a][i]];
return a;
}
void change(int k) {
if (f[k][0] == 1) return;
k = f[k][0];
for (int i = h[k]; i; i = ne[i])
if (!v[to[i]] && to[i] != f[k][0]) return;
v[k] = 1;
change(k);
}
bool check(int mid) {
vector<PII> s;
memset(v, 0, sizeof v);
for (PII i : a) {
int idx = i.se;
if (idx == 1) s.pb({ mid, 1 });
else if (mid <= dist[idx] + dist[fa[idx]]) {
if (mid < dist[idx] - dist[fa[idx]]) {
v[idx = ask(idx, mid)] = 1;
change(idx);
}
else if (!v[fa[idx]]) v[fa[idx]] = 1;
else if (mid > dist[idx]) s.pb({ mid - dist[idx], idx });
}
else s.pb({ mid - dist[idx], idx });
}
sort(all(s));
int j = -1;
for (PII i : b)
if (!v[i.se]) {
while (++j < s.size() && s[j].fi < i.fi);
if (j == s.size()) return 0;
}
return 1;
}
int main() {
IO; cin >> n;
t = log2(n - 1) + 1;
rep(i, 2, n) {
int u, v, c; cin >> u >> v >> c;
add(u, v, c); add(v, u, c);
}
bfs(1);
cin >> m; a.resize(m);
rep(i, 0, m - 1) cin >> a[i].se, a[i].fi = dist[fa[a[i].se]] - dist[a[i].se];
sort(all(a));
for (int i = h[1]; i; i = ne[i]) b.pb({ dist[to[i]], to[i] });
sort(all(b));
int l = 0, r = 0x7f7f7f7f;
while (l < r) {
int mid = (ll)l + r >> 1;
if (check(mid)) r = mid;
else
l = mid + 1;
}
cout << l;
return 0;
}
基环树
⭐岛屿
主要处理最长路径环的问题, 要用单调队列, 拆环不满足递增, 无法尺取
int h[N], ne[M], to[M], co[M], tot;
int q[N << 1];
long long d[N];
bool v[N], g[M];
vector<pair<int, long long>> cir;
void add(int u, int v, int c) { ne[++tot] = h[u]; to[h[u] = tot] = v; co[tot] = c; g[tot] = 1; }
int dfs(int x, int e) {
if (v[x]) return x;
int ed = 0; v[x] = 1;
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]]) if (g[i] && (i >> 1) != e) {
int cur = dfs(y, i >> 1);
if (cur) cir.emplace_back(y, co[i] + cir.back().second), ed = cur, g[i] = g[i ^ 1] = 0;
}
return ed == x ? 0 : ed;
}
void dfss(int x, int fa, long long& ans) {
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]]) if (g[i] && y != fa) {
dfss(y, x, ans); ans = max(ans, d[x] + d[y] + co[i]);
d[x] = max(d[x], d[y] + co[i]);
}
}
long long work(int x) {
vector<pair<int, long long>>(1).swap(cir);
long long ans = 0; dfs(x, 0);
for (int j = 1; j < cir.size(); ++j) dfss(cir[j].first, 0, ans);
for (int i = 1, sz = cir.size(); i < sz; ++i)
cir.emplace_back(cir[i]), cir.back().second += cir[sz - 1].second;
int h = 0, t = -1; q[++t] = 1;
for (int i = 2, sz = cir.size() >> 1; i < cir.size(); ++i) {
while (i - q[h] >= sz) ++h;
ans = max(ans, d[cir[i].first] + cir[i - 1].second + d[cir[q[h]].first] - cir[q[h] - 1].second);
while (h <= t && d[cir[q[t]].first] - cir[q[t] - 1].second <= d[cir[i].first] - cir[i - 1].second) --t;
q[++t] = i;
}
return ans;
}
int main() {
IOS; cin >> n; tot = 1; long long ans = 0;
for (int i = 1; i <= n; ++i) {
int v, c; cin >> v >> c;
add(i, v, c); add(v, i, c);
}
for (int i = 1; i <= n; ++i) if (!v[i]) ans += work(i);
cout << ans;
return 0;
}
⭐创世纪
考虑有向边(a[i], i)拆环之后就是普通的树形dp
所以我们在普通的树形dp之上在考虑拆掉环上的边(a[rt], rt)对答案的影响
无非是当选择 a[rt] 参与时, 需要有一个孩子不参与, 而我们把 rt 这个孩子参不参与忽略了
所以可以进行两边树形dp, 其中一次强制假设 rt 不参与,
则 f[a[rt]][1] 不需要有孩子不参与限制就好了(rt已经不选了, 这次只能取 f[rt][0], 舍去f[rt][1]选项即可)
int n, a[N], rt, f[N][2], ans;
int h[N], to[N], ne[N], tot;
bool v[N];
void add(int u, int v) { ne[++tot] = h[u]; to[h[u] = tot] = v; }
int solve(int u, bool t) {
f[u][0] = 0; v[u] = 1;
int res, c = 1e9;
for (int i = h[u], y = to[i]; i; y = to[i = ne[i]]) if (y != rt)
res = solve(y, t), c = min(c, res - f[y][0]), f[u][0] += res;
f[u][1] = f[u][0] - c + 1;
if (t && u == a[rt]) f[u][1] += c;
return max(f[u][0], f[u][1]);
}
int work(int u) {
for (rt = u; !v[a[rt]]; v[rt] = 1, rt = a[rt]);
int ans = solve(rt, 0); solve(rt, 1);
return max(ans, f[rt][0]);
}
int main() {
cin >> n;
for (int i = 1; i<= n; ++i) cin >> a[i], add(a[i], i);
for (int i = 1; i<= n; ++i) if (!v[i]) ans += work(i);
cout << ans;
return 0;
}
⭐Freda的传呼机
const int N = 1e4 + 5;
struct STFrom {
static const int N = 2e4 + 5;
int f[N][20], dep[N], lg[N], t, dis[N];//N为节点的数量
vector<pair<int, int>>* h;
void init(int n, vector<pair<int, int>>* H) {
t = log2(n - 1) + 1; h = H; lg[0] = -1;
rep(i, 1, n) dep[i] = 0, lg[i] = lg[i >> 1] + 1;
}
void bfs(int s) {
queue<int> q; q.push(s); dep[s] = 1; dis[s] = 0;
rep(i, 0, t) f[s][i] = 0;
while (!q.empty()) {
int x = q.front(); q.pop();
for (auto& [y, c] : h[x]) {
if (dep[y]) continue; dis[y] = dis[x] + c;
dep[y] = dep[x] + 1; f[y][0] = x; q.push(y);
for (int j = 1; j <= t; ++j) f[y][j] = f[f[y][j - 1]][j - 1];
}
}
}
int lca(int x, int y) {
if (dep[x] > dep[y]) swap(x, y);
for (int k = dep[y] - dep[x]; ~lg[k]; k ^= 1 << lg[k]) y = f[y][lg[k]];
if (x == y) return x;
per(i, lg[dep[y]], 0) if (f[x][i] ^ f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
int dist(int x, int d) {
for (; ~lg[d]; d ^= 1 << lg[d]) x = f[x][lg[d]];
return x;
}
} ST;
int n, m, _, k, cas;
int dfn[N], low[N], df, st[N], top;
int sum[N << 1], d[N], vcnt, fa[N];
vector<pair<int, int>> h[N], g[N << 1];
void work(int x, int y, int c) {
sum[y] = c; swap(sum[++vcnt + n], sum[x]);
for (int i = y; x ^ i; i = fa[i]) sum[fa[i]] = sum[i] + d[i];
swap(sum[x], sum[vcnt + n]);
g[vcnt + n].emplace_back(x, 0), g[x].emplace_back(vcnt + n, 0);
for (int i = y; x ^ i; i = fa[i]) {
int c = min(sum[i], sum[vcnt + n] - sum[i]);
g[vcnt + n].emplace_back(i, c), g[i].emplace_back(vcnt + n, c);
}
}
void tarjan(int x) {
dfn[x] = low[x] = ++df, st[++top] = x;
for (auto& [y, c] : h[x])
if (!dfn[y]) {
d[y] = c; fa[y] = x; tarjan(y); low[x] = min(low[x], low[y]);
if (dfn[x] <= low[y]) {
for (auto& [z, c] : h[x]) if (z == st[top]) work(x, z, c);
while (y != st[top--]);
}
}
else low[x] = min(low[x], dfn[y]);
}
int main() {
cin >> n >> m >> k;
for (int i = 1; i <= m; ++i) {
int u, v, c; cin >> u >> v >> c;
h[u].emplace_back(v, c); h[v].emplace_back(u, c);
}
tarjan(1); ST.init(vcnt + n, g); ST.bfs(1);
for (int i = 1; i <= k; ++i) {
int x, y, z; cin >> x >> y; z = ST.lca(x, y);
if (z <= n) cout << ST.dis[x] + ST.dis[y] - ST.dis[z] * 2 << '\n';
else {
int a = ST.dist(x, ST.dep[x] - ST.dep[z] - 1);
int b = ST.dist(y, ST.dep[y] - ST.dep[z] - 1);
int ans = min(abs(sum[a] - sum[b]), sum[z] - abs(sum[a] - sum[b]));
cout << ans + ST.dis[x] - ST.dis[a] + ST.dis[y] - ST.dis[b] << '\n';
}
}
return 0;
}
负环与差分约束
观光奶牛
bool check(int s, double mid) {
for (int i = 1; i <= n; ++i) d[i] = 2e9, v[i] = 0;
d[s] = 0; dep[s] = v[s] = 1;
stack<int> st; st.push(s);
while (!st.empty()) {
int x = st.top(); st.pop(); v[x] = 0;
for (int i= h[x], y = to[i]; i; y = to[i = ne[i]]) if (d[y] >= d[x] + mid * co[i] - f[x]) {
d[y] = d[x] + mid * co[i] - f[x], dep[y] = dep[x] + 1;
if (dep[y] > n) return 1;
if (!v[y]) st.push(y), v[y] = 1;
}
}
return 0;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> f[i];
for (int i = 0; i < m; ++i) {
int u, v, c; cin >> u >> v >> c;
add(u, v, c);
}
double l = 0, r = 1000;
while (r - l > 1e-6) {
double mid = (l + r) / 2;
if (check(1, mid)) l = mid;
else r = mid;
}
cout << setiosflags(ios::fixed) << setprecision(2) << l;
return 0;
}
区间
#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 5;
struct node { int a, b, c; } p[N];
int n, m, c[N], f[N];
void add(int x, int k) { for (; x <= 5e4; x += -x & x) c[x] += k; }
int ask(int x) { int ans = 0; for (; x; x -= -x & x) ans += c[x]; return ans; }
int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); }
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) cin >> p[i].a >> p[i].b >> p[i].c;
sort(p + 1, p + 1 + n, [](node& a, node& b) { return a.b ^ b.b ? a.b < b.b : a.c > b.c; });
for (int i = 1; i <= 5e4; ++i) f[i] = i;
for (int i = 1; i <= n; ++i) {
p[i].c -= ask(p[i].b) - ask(p[i].a - 1);
for (int j = find(p[i].b); p[i].c > 0; j = f[j], --p[i].c, ++m) add(j, 1), f[j] = find(j - 1);
}
cout << m;
return 0;
}
Tarjan算法与无向图连通性
B城
void tarjan(int x) {
dfn[x] = low[x] = ++df; int sum = sz[x] = 1, c = 0;
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]])
if (!dfn[y]) {
tarjan(y); low[x] = min(low[x], low[y]); sz[x] += sz[y];
if (low[y] >= dfn[x]) ans[x] += (long long)sz[y] * (n - sz[y]), ++c, sum += sz[y];
}
else low[x] = min(low[x], dfn[y]);
if (c > 1 || (c && x != 1)) ans[x] += (long long)sum * (n - sum) + n - 1;
else ans[x] = n - 1 << 1;
}
int main() {
IOS; cin >> n >> m; tot = 1;
for (int i = 1; i <= m; ++i) {
int u, v; cin >> u >> v;
if (u != v) add(u, v); add(v, u);
}
tarjan(1);
for (int i = 1; i <= n; ++i) cout << ans[i] << '\n';
return 0;
}
⭐网络
缩点建图之后爬树
struct STFrom {
int f[N][20], dep[N], lg[N], t;//N为节点的数量
int *h, *ne, *to;
void init(int n, int* H, int* Ne, int* To) {
t = log2(n - 1) + 1; h = H, ne = Ne, to = To; lg[0] = -1;
rep(i, 1, n) dep[i] = 0, lg[i] = lg[i >> 1] + 1;
}
void bfs(int s) {
queue<int> q; q.push(s); dep[s] = 1;
rep(i, 0, t) f[s][i] = 0;
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]]) {
if (dep[y]) continue;
dep[y] = dep[x] + 1; f[y][0] = x; q.push(y);
for (int j = 1; j <= t; ++j) f[y][j] = f[f[y][j - 1]][j - 1];
}
}
}
int lca(int x, int y) {
if (dep[x] > dep[y]) swap(x, y);
for(int k = dep[y] - dep[x], i = lg[k]; ~i; --i) if (k >> i & 1) y = f[y][i];
if (x == y) return x;
per(i, lg[dep[y]], 0) if (f[x][i] ^ f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
int dist(int x, int y) { return dep[x] + dep[y] - (dep[lca(x, y)]<<1); }
} ST;
int n, m, ecnt, c[N], f[N];
int h[N], to[M], ne[M], tot;
int nh[N], nto[M], nne[M], ntot;
int dfn[N], low[N], df, st[N], top;
void add(int u, int v, int* h, int* ne, int* to, int& tot) {
ne[++tot] = h[u]; to[h[u] = tot] = v;
}
void tarjan(int x, int bian) {
dfn[st[++top] = x] = low[x] = ++df;
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]])
if (!dfn[y]) tarjan(y, i), umin(low[x], low[y]);
else if (i != (bian ^ 1)) low[x] = min(low[x], dfn[y]);
if (low[x] == dfn[x]) {
++ecnt; int y;
do c[y = st[top--]] = ecnt; while (y != x);
}
}
int ff(int x) { return x == f[x] ? x : f[x] = ff(f[x]); }
int main() {
IOS; int cas = 0;
while (cin >> n >> m, n || m) {
ecnt = ntot = df = 0; tot = 1;
rep (i, 1, n) h[i] = nh[i] = dfn[i] = low[i] = 0;
rep (i, 1, m) {
int u, v; cin >> u >> v;
if (u == v) continue;
add(u, v, h, ne, to, tot); add(v, u, h, ne, to, tot);
}
tarjan(1, 0);
rep (i, 2, tot) {
int x = to[i ^ 1], y = to[i];
if (c[x] ^ c[y]) add(c[x], c[y], nh, nne, nto, ntot);
}
ST.init(n, nh, nne, nto); ST.bfs(1);
rep (i, 1, ecnt) f[i] = i;
cout << "Case " << ++cas << ":\n";
for (cin >> m; m; --m) {
int u, v, z; cin >> u >> v; u = ff(c[u]), v = ff(c[v]); z = ST.lca(u, v);
while (u ^ z) f[u] = ST.f[u][0], --ecnt, u = ff(u);
while (v ^ z) f[v] = ST.f[v][0], --ecnt, v = ff(v);
cout << ecnt - 1 << '\n';
}
cout << '\n';
}
return 0;
}
⭐圆桌骑士
点双联通分量中若存在奇环, 在此点双中任何两点都被至少一个奇环覆盖
void tarjan(int x) {
dfn[x] = low[x] = ++df; st[++top] = x;
for (int y = 1; y <= n; ++y) if (h[x][y])
if (!dfn[y]) {
tarjan(y); low[x] = min(low[x], low[y]);
if (dfn[x] <= low[y]) {
vcc.emplace_back(vector<int>(1, x)); int z;
do vcc.back().push_back(z = st[top--]); while (z != y);
}
}
else low[x] = min(low[x], dfn[y]);
}
bool dfs(int x, int c) {
col[x] = c;
for (int y = 1; y <= n; ++y) {
if (!h[x][y] || !g[y] || (col[y] && col[y] != c)) continue;
if (col[y] || dfs(y, 3 - c)) return 1;
}
return 0;
}
int main() {
IOS;
while (cin >> n >> m, n || m) {
for (int i = 1; i < n; ++i) for (int j = i + 1; j <= n; ++j) h[i][j] = h[j][i] = 1;
memset(dfn, 0, sizeof dfn); df = 0;
vector<vector<int>>().swap(vcc);
for (int i = 1; i <= m; ++i) {
int u, v; cin >> u >> v;
h[u][v] = h[v][u] = 0;
}
for (int i = 1; i <= n; ++i) if (!dfn[i]) top = 0, tarjan(i);
for (auto &i : vcc) {
for (auto &j : i) g[j] = 1, col[j] = 0;
bool f = dfs(i[0], 1);
for (auto &j : i) g[j] = 0, v[j] = v[j] | f;
}
for (int i = 1, j = n; i <= j; ++i) n -= v[i], v[i] = 0;
cout << n << '\n';
}
return 0;
}
看牛
int h[N], ne[M << 1], to[M << 1], tot, hc[N];
int st[M << 2], ans[M << 2], top, t;
bool vis[M << 1];
void add(int u, int v) { ne[++tot] = h[u]; to[h[u] = tot] = v; }
void eulerc() {
st[++top] = 1;
for (int i = 1; i <= n; ++i) hc[i] = h[i];
while (top) {
int x = st[top];
while (hc[x] && vis[hc[x]]) hc[x] = ne[hc[x]];
if (hc[x]) {
st[++top] = to[hc[x]];
vis[hc[x]] = 1;
hc[x] = ne[hc[x]];
}
else --top, ans[++t] = x;
}
}
int main() {
cin >> n >> m; tot = 1;
for (int i = 1; i <= m; ++i) {
int u, v; cin >> u >> v;
add(u, v); add(v, u);
}
eulerc();
for (int i = t; i; --i) cout << ans[i] << '\n';
return 0;
}
Tarjan算法与有向图连通性
学校网络
void tarjan(int x) {
dfn[x] = low[x] = ++df, inst[st[++top] = x] = 1;
for (auto &y : h[x])
if (!dfn[y]) tarjan(y), low[x] = min(low[x], low[y]);
else if (inst[y]) low[x] = min(low[x], dfn[y]);
if (dfn[x] == low[x]) {
++scnt; int z;
do inst[z = st[top--]] = 0, c[z] = scnt; while (z != x);
}
}
int main() {
cin >> n; int ans1 = 0, ans2 = 0;
for (int i = 1; i <= n; ++i) while (cin >> m, m) h[i].push_back(m);
for (int i = 1; i <= n; ++i) if (!dfn[i]) top = 0, tarjan(i);
for (int x = 1; x <= n; ++x) for (auto &y : h[x]) if (c[x] != c[y]) ++indeg[c[y]], ++outdeg[c[x]];
for (int i = 1; i <= scnt; ++i) { if (!indeg[i]) ++ans1; if (!outdeg[i]) ++ans2; }
cout << ans1 << '\n' << (scnt == 1 ? 0 : max(ans1, ans2));
return 0;
}
银河
void tarjan(int x) {
dfn[x] = low[x] = ++df, inst[st[++top] = x] = 1;
for (auto &[y, c] : h[x])
if (!dfn[y]) tarjan(y), low[x] = min(low[x], low[y]);
else if (inst[y]) low[x] = min(low[x], dfn[y]);
if (dfn[x] == low[x]) {
++scnt; int z;
do inst[z = st[top--]] = 0, c[z] = scnt; while (z != x);
}
}
int main() {
IOS; cin >> n >> m; long long ans = 0;
for (int i = 0; i < m; ++i) {
int u, v, c; cin >> c >> u >> v;
switch (c) {
case 1 : h[u].emplace_back(v, 0), h[v].emplace_back(u, 0); break;
case 2 : h[u].emplace_back(v, 1); break;
case 3 : h[v].emplace_back(u, 0); break;
case 4 : h[v].emplace_back(u, 1); break;
case 5 : h[u].emplace_back(v, 0); break;
}
}
for (int i = 1; i <= n; ++i) h[n + 1].emplace_back(i, 1); tarjan(n + 1);
for (int x = 1; x <= n + 1; ++x) for (auto &[y, co] : h[x])
if (c[x] == c[y] && co) return cout << -1, 0;
else if (c[x] != c[y]) g[c[x]].emplace_back(c[y], co), ++deg[c[y]];
st[top = 1] = c[n + 1];
for (int x = st[top--]; ~top; x = st[top--])
for (auto &[y, c] : g[x]) {
d[y] = max(d[y], d[x] + c);
if (--deg[y] == 0) st[++top] = y;
}
for (int i = 1; i <= n; ++i) ans += d[c[i]]; cout << ans;
return 0;
}
⭐北大ACM队的远足
#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define pb push_back
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
using namespace std;
typedef long long ll;
typedef vector<int> VI;
const int N = 1e5 + 5, M = 2e5 + 5, mod = 999983;
int n, m, _, k;
int h[N], ne[M], to[M], co[M], tot;
int ph[N], pn[M], pt[M];
int indeg[N], outdeg[N], pre[N], st, ed, q;
ll fs[N], ft[N], dis[N];
bool cut[N], edge[M];
VI path;
int ds[N], dt[N], g[N << 1], d[N << 1];
bool bri[M];
void add(int u, int v, int c) {
ne[++tot] = h[u]; to[h[u] = tot] = v; co[tot] = c;
pn[tot] = ph[v]; pt[ph[v] = tot] = u;
}
void topsort(int s, int h[], int ne[], int to[], ll f[], int deg[]) {
queue<int> q; f[s] = 1;
rep (i, 1, n) if (!deg[i]) q.push(i);
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = h[x]; i; i = ne[i]) {
int y = to[i], w = co[i];
if (s == st && dis[y] > dis[x] + w) dis[y] = dis[x] + w, pre[y] = i;
f[y] = (f[y] + f[x]) % mod;
if (!--deg[y]) q.push(y);
}
}
}
void findedge() {
rep(i, 1, tot) {
int x = pt[i], y = to[i];
edge[i] = fs[x] * ft[y] % mod == fs[ed];
}
}
void getpath() {
VI(1, ed).swap(path);
for (int i = pre[ed]; to[i]; i = pre[pt[i]]) path.pb(pt[i]);
reverse(all(path));
}
void solve() {
getpath();
per(i, path.size(), 1) d[i] = dis[path[i - 1]];
rep(i, 2, path.size())
bri[i] = edge[pre[path[i - 1]]], g[i] = g[i - 1] + (bri[i] ? co[pre[path[i - 1]]] : 0);
int k = 1;
rep(i, 2, path.size()) {
ds[i] = min(g[i], ds[i - 1] + g[i] - g[i - 1]);
while (k < i && d[i] - d[k] > q) ++k;
ds[i] = min(ds[i], g[k] - (bri[k] ? q - d[i] + d[k] : 0));
}
dt[k = path.size()] = 0;
per(i, path.size() - 1, 1) {
dt[i] = min(g[path.size()] - g[i], dt[i + 1] + g[i + 1] - g[i]);
while (k > i && d[k] - d[i] > q) --k;
dt[i] = min(dt[i], g[path.size()] - g[k] - (bri[k + 1] ? q - d[k] + d[i] : 0));
}
int ans = 2e9;
rep(i, 1, path.size()) ans = min(ans, ds[i] + dt[i]);
k = 1;
rep(i, 2, path.size()) {
while (k < i && d[i] - d[k] > 2 * q) ++k;
ans = min(ans, g[path.size()] - g[i] + g[k] - (bri[k] ? 2 * q - d[i] + d[k] : 0));
}
cout << ans << '\n';
}
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n >> m >> st >> ed >> q; tot = 0; ++st, ++ed;
rep(i, 1, n) {
ph[i] = h[i] = indeg[i] = outdeg[i] = pre[i] = 0;
cut[i] = fs[i] = ft[i] = 0; dis[i] = 2e9;
}
dis[st] = 0;
rep(i, 1, m) {
int u, v, c; cin >> u >> v >> c;
add(++u, ++v, c); ++indeg[v], ++outdeg[u];
}
topsort(st, h, ne, to, fs, indeg);
if (dis[ed] == 2e9) { cout << -1 << '\n'; continue; }
topsort(ed, ph, pn, pt, ft, outdeg);
findedge(); solve();
}
return 0;
}
卡图难题
#include <bits/stdc++.h>
using namespace std;
const int N = 2e3 + 5, M = 1e6 + 5;
int n, m, _, k, h[N][N];
int dfn[N], low[N], df, st[N], top;
int c[N], scnt;
bool inst[N];
char s[5];
void tarjan(int x) {
dfn[x] = low[x] = ++df, inst[st[++top] = x] = 1;
for (int y = 1; y <= m; ++y) if (h[x][y])
if (!dfn[y]) tarjan(y), low[x] = min(low[x], low[y]);
else if (inst[y]) low[x] = min(low[x], dfn[y]);
if (low[x] == dfn[x]) {
++scnt; int y;
do inst[y = st[top--]] = 0, c[y] = scnt; while (y != x);
}
}
int main() {
cin >> n >> m;
for (int i = 1; i <= m; ++i) {
int a, b, c; cin >> a >> b >> c >> s;
switch (s[0]) {
case 'X' : if (c) h[a][b + n] = h[a + n][b] = h[b][a + n] = h[b + n][a] = 1;
else h[a][b] = h[a + n][b + n] = h[b][a] = h[b + n][a + n] = 1; break;
case 'O' : if (c) h[a][b + n] = h[b][a + n] = 1;
else h[a][a + n] = h[b][b + n] = 1; break;
case 'A' : if (c) h[a + n][a] = h[b + n][b] = 1;
else h[a + n][b] = h[b + n][a] = 1; break;
}
} m = n << 1;
for (int i = 1; i <= n; ++i) if (!dfn[i]) top = 0, tarjan(i);
for (int i = 1; i <= n; ++i) if (c[i] == c[i + n]) return cout << "NO", 0;
cout << "YES";
return 0;
}
⭐牧师约翰最忙碌的一天
#include <bits/stdc++.h>
using namespace std;
const int N = 2e3 + 5;
int n, m, _, k, h[N][N];
int dfn[N], low[N], df, st[N], top;
int c[N], scnt, opp[N], val[N];
bool inst[N];
pair<int, int> t[N];
void tarjan(int x) {
dfn[x] = low[x] = ++df, inst[st[++top] = x] = 1;
for (int y = 1; y <= m; ++y) if (h[x][y])
if (!dfn[y]) tarjan(y), low[x] = min(low[x], low[y]);
else if (inst[y]) low[x] = min(low[x], dfn[y]);
if (low[x] == dfn[x]) {
++scnt; int y;
do inst[y = st[top--]] = 0, c[y] = scnt; while (y != x);
}
}
void _print(int c) {
int h = c / 60, m = c % 60;
if (h < 10) printf("0%d:", h);
else printf("%d:", h);
if (m < 10) printf("0%d", m);
else printf("%d", m);
}
void print(int x) { _print(t[x].first); printf(" "); _print(t[x].second); puts(""); }
int main() {
scanf("%d", &n); bool f = 1; m = n << 1;
for (int i = 1; i <= n; ++i) {
int a, b, c, d, e; opp[i] = i + n, opp[i + n] = i;
scanf("%d:%d %d:%d %d", &a, &b, &c, &d, &e);
t[i] = { a * 60 + b, a * 60 + b + e }; t[i + n] = { c * 60 + d - e, c * 60 + d };
if (t[i].first > t[i].second || t[i + n].first > t[i + n].second) f = 0;
}
for (int i = 1; i < m; ++i) for (int j = i + 1; j <= m; ++j)
if (i == j || j == i + n) continue;
else if (t[i].second > t[j].first && t[i].first < t[j].second) h[i][opp[j]] = h[j][opp[i]] = 1;
for (int i = 1; i <= m; ++i) if (!dfn[i]) top = 0, tarjan(i);
for (int i = 1; i <= n; ++i) if (c[i] == c[i + n]) return puts("NO"), 0;
puts("YES");
for (int i = 1; i <= m; ++i) val[i] = c[i] > c[opp[i]];
for (int i = 1; i <= n; ++i) print(val[i] ? opp[i] : i);
return 0;
}
二分图的匹配
棋盘覆盖
bool dfs(int x, int y) {
for (int i = 0; i < 4; ++i) {
int nx = x + d[i][0], ny = y + d[i][1];
if (max(nx, ny) > n || min(nx, ny) < 1 || v[nx][ny] || b[nx][ny]) continue;
v[nx][ny] = 1;
if (!a[nx][ny].first || dfs(a[nx][ny].first, a[nx][ny].second)) return a[nx][ny] = { x, y }, 1;
}
return 0;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= m; ++i) {
int x, y; cin >> x >> y;
b[x][y] = 1;
}
for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) if (!b[i][j] && i + j & 1)
memset(v, 0, sizeof v), k += dfs(i, j);
cout << k;
return 0;
}
車的放置
#include <bits/stdc++.h>
using namespace std;
const int N = 2e2 + 5;
int n, m, k, match[N];
bool g[N][N], v[N];
bool dfs(int x) {
for (int i = 1; i <= m; ++i) if (!g[x][i] && !v[i]) {
v[i] = 1;
if (!match[i] || dfs(match[i])) return match[i] = x, 1;
}
return 0;
}
int main() {
cin >> n >> m;
for (cin >> k; k; --k) {
int x, y; cin >> x >> y;
g[x][y] = 1;
}
for (int i = 1; i <= n; ++i) memset(v, 0, sizeof v), k += dfs(i);
cout << k;
return 0;
}
⭐导弹系统
double dis(int x, int y) { return sqr(a[x].first - b[y].first) + sqr(a[x].second - b[y].second); }
bool dfs(int x, double mid) {
for (int i = n * c; i; --i) if (!v[i]) {
if (dis(x, (i - 1) / c + 1) > sqr(sp) * sqr(mid - (i - 1) % c * (t1 + t2) - t1)) continue;
v[i] = 1; if (!match[i] || dfs(match[i], mid)) { match[i] = x; return 1; }
}
return 0;
}
bool check(double mid) {
c = (int)min((mid + t2) / (t1 + t2), (double)m); memset(match, 0, sizeof match);
for (int i = 1; i <= m; ++i) { memset(v, 0, sizeof v); if (!dfs(i, mid)) return 0; }
return 1;
}
int main() {
cin >> n >> m >> t1 >> t2 >> sp; t1 /= 60;
for (int i = 1; i <= m; ++i) cin >> a[i].first >> a[i].second;
for (int i = 1; i <= n; ++i) cin >> b[i].first >> b[i].second;
double l = 0, r = 2e6;
while (r - l >= 1e-7) {
double mid = (l + r) / 2;
if (check(mid)) r = mid;
else l = mid;
}
cout << setiosflags(ios::fixed) << setprecision(6) << r;
return 0;
}
⭐蚂蚁
#include <bits/stdc++.h>
#define sqr(n) ((n)*(n))
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define per(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
template<class T1, class T2> bool umin(T1& a, T2 b) { return a > b ? (a = b, true) : false; }
template<class T1, class T2> bool umax(T1& a, T2 b) { return a < b ? (a = b, true) : false; }
const int N = 1e2 + 5;
int n, match[N];
pair<int, int> a[N], b[N];
double la[N], lb[N], delta, w[N][N];
bool va[N], vb[N];
bool dfs(int x) {
va[x] = 1;
rep(y, 1, n) if (!vb[y])
if (fabs(la[x] + lb[y] - w[x][y]) < 1e-6) {
vb[y] = 1;
if (!match[y] || dfs(match[y])) { match[y] = x; return 1; }
}
else umin(delta, la[x] + lb[y] - w[x][y]);
return 0;
}
void KM() {
rep(i, 1, n) {
la[i] = -2e9; lb[i] = 0;
rep(j, 1, n) umax(la[i], w[i][j]);
}
rep(i, 1, n)
while (1) {
rep(j, 1, n) va[j] = vb[j] = 0;/*;*/delta = 2e9; if (dfs(i)) break;
rep (x, 1, n) if (va[x]) rep (y, 1, n) if (!vb[y]) delta = min(delta, la[x] + lb[y] - w[x][y]);
rep(j, 1, n) la[j] -= va[j] ? delta : 0, lb[j] += vb[j] ? delta : 0;
}
rep(i, 1, n) cout << match[i] << '\n';
}
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) cin >> b[i].first >> b[i].second;
for (int i = 1; i <= n; ++i) cin >> a[i].first >> a[i].second;
for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j)
w[i][j] = -sqrt(sqr(a[i].first - b[j].first) + sqr(a[i].second - b[j].second));
KM();
return 0;
}
二分图的覆盖与独立集
机器任务
int n, m, _, k, match[N], ans;
vector<int> h[N];
bool v[N];
bool dfs(int x) {
for (auto &y : h[x]) if (!v[y]) {
v[y] = 1;
if (!match[y] || dfs(match[y])) return match[y] = x, 1;
}
return 0;
}
int main() {
while (cin >> n, n) {
cin >> m >> k; memset(match, 0, sizeof match); int ans = 0;
for (int i = 1; i <= n + m; ++i) vector<int>().swap(h[i]);
for (int i = 1; i <= k; ++i) {
int u, v, c; cin >> c >> u >> v;
if (u && v) h[u].push_back(v + n);
}
for (int i = 1; i <= n; ++i) memset(v, 0, sizeof v), ans += dfs(i);
cout << ans << '\n';
}
return 0;
}
⭐泥泞的区域
int n, m, _, k;
vector<int> h[N * N];
int match[N * N], ans;
int a[N][N], b[N][N], cnt1, cnt2;
bool v[N * N];
char s[N][N];
bool dfs(int x) {
for (auto &y : h[x]) if (!v[y]) {
v[y] = 1;
if (!match[y] || dfs(match[y])) return match[y] = x;
}
return 0;
}
int main() {
cin >> n >> m;
rep (i, 1, n) rep (j, 1, m) {
cin >> s[i][j];
if (s[i][j] == '.') continue;
if (s[i][j - 1] == '*') a[i][j] = a[i][j - 1];
else a[i][j] = ++cnt1;
if (s[i - 1][j] == '*') b[i][j] = b[i - 1][j];
else b[i][j] = ++cnt2;
}
rep (i, 1, n) rep (j, 1, m) h[a[i][j]].push_back(b[i][j]);
rep (i, 1, cnt1) memset(v, 0, sizeof v), ans += dfs(i);
cout << ans;
return 0;
}
⭐骑士放置
棋盘匹配问题一般将 编号奇数作为左点, 偶数为右点
int n, m, _, k;
vector<int> h[N * N];
int match[N * N], ans;
bool v[N * N], a[N][N];
bool dfs(int x) {
for (auto &y : h[x]) if (!v[y]) {
v[y] = 1;
if (!match[y] || dfs(match[y])) return match[y] = x;
}
return 0;
}
int get(int x, int y) { return (x - 1) * m + y; }
bool check(int x, int y) { return (min(x, y) > 0 && x <= n && y <= m && !a[x][y]); }
int main() {
cin >> n >> m >> k;
rep (i, 1, k) {
int x, y; cin >> x >> y;
a[x][y] = 1;
}
rep (i, 1, n) rep (j, 1, m) if (!a[i][j]) {
int id = get(i, j);
if (check(i + 1, j + 2)) h[id].push_back(get(i + 1, j + 2)), h[get(i + 1, j + 2)].push_back(id);
if (check(i + 2, j + 1)) h[id].push_back(get(i + 2, j + 1)), h[get(i + 2, j + 1)].push_back(id);
if (check(i - 1, j + 2)) h[id].push_back(get(i - 1, j + 2)), h[get(i - 1, j + 2)].push_back(id);
if (check(i - 2, j + 1)) h[id].push_back(get(i - 2, j + 1)), h[get(i - 2, j + 1)].push_back(id);
}
rep (i, 1, n) rep (j, 1, m) if (!a[i][j] && i + j & 1) memset(v, 0, sizeof v), ans += dfs(get(i, j));
cout << n * m - k - ans;
return 0;
}
⭐捉迷藏
选择的藏身点, 即dfs(i) 失败的的i点
int n, m, _, k, match[N];
bool h[N][N], v[N];
bool dfs(int x) {
rep (y, 1, n) if (h[x][y] && !v[y]) {
v[y] = 1;
if (!match[y] || dfs(match[y])) return match[y] = x, 1;
}
return 0;
}
int main() {
cin >> n >> m; int ans = n;
rep (i, 1, m) {
int u, v; cin >> u >> v;
h[u][v] = 1;
}
rep (k, 1, n) rep (i, 1, n) rep (j, 1, n) h[i][j] |= h[i][k] & h[k][j];
rep (i, 1, n) memset(v, 0, sizeof v), ans -= dfs(i);
cout << ans;
return 0;
}
网络流初步
⭐舞动的夜晚
对于有向边边 1~m
co[i << 1 | 1] 无残余流量且链接不同连通分量为无用边
co[i << 1] 无残余流量且链接不相同连通分量为必要边
其他边为可行边
int n, m, _, k;
int h[N], ne[M], to[M], co[M], id[M], now[N], tot;
int d[N], s, t, c[N], scnt;
int dfn[N], low[N], df, st[N], top;
bool inst[N];
int indeg[N], outdeg[N];
void add(int u, int v, int c, int idx) {
ne[++tot] = h[u]; to[h[u] = tot] = v; co[tot] = c; id[tot] = idx;
ne[++tot] = h[v]; to[h[v] = tot] = u; co[tot] = 0; id[tot] = idx;
}
bool bfs() {
memset(d, 0, sizeof d); memcpy(now, h, sizeof h);
queue<int> q; q.push(s); d[s] = 1;
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = h[x]; i; i = ne[i]) {
if (!co[i]) continue;
int y = to[i];
if (d[y]) continue;
d[y] = d[x] + 1; q.push(y);
if (y == t) return 1;
}
}
return 0;
}
int dinic(int x, int flow) {
if (x == t) return flow;
int rest = flow, k;
for (int &i = now[x]; i && rest; i = ne[i]) {
if (!co[i]) continue;
int y = to[i];
if (d[y] != d[x] + 1) continue;
k = dinic(y, min(rest, co[i]));
if (!k) d[y] = 0;
co[i] -= k, co[i ^ 1] += k; rest -= k;
}
return flow - rest;
}
void tarjan(int x) {
dfn[x] = low[x] = ++df; inst[st[++top] = x] = 1;
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]]) if (co[i])
if (!dfn[y]) tarjan(y), low[x] = min(low[x], low[y]);
else if (inst[y]) low[x] = min(low[x], dfn[y]);
if (low[x] == dfn[x]) {
++scnt; int y;
do inst[y = st[top--]] = 0, c[y] = scnt; while (y != x);
}
}
int main() {
IOS; cin >> n >> m >> k; vector<int> ans;
tot = 1; s = n + m + 1, t = s + 1;
rep (i, 1, k) {
int u, v; cin >> u >> v;
add(u, v + n, 1, i);
}
rep (i, 1, n) add(s, i, 1, 0);
rep (i, 1, m) add(i + n, t, 1, 0);
while (bfs()) while (dinic(s, inf));
rep (i, 1, n + m + 2) if (!dfn[i]) top = 0, tarjan(i);
rep (i, 1, k) if (!co[i << 1 | 1]) {
int x = to[i << 1 | 1], y = to[i << 1];
if (c[x] != c[y]) ans.push_back(id[i << 1]);
}
cout << ans.size() << '\n';
for (auto &i : ans) cout << i << ' ';
cout << '\n';
return 0;
}
⭐有线电视网络
点化边之后枚举s和t, 而不是人为添加s 和 t
int n, m, _, k;
int h[N], ne[M], to[M], co[M], now[N], tot;
int d[N], s, t, maxflow, e[M];
void add(int u, int v, int c) {
ne[++tot] = h[u]; to[h[u] = tot] = v; co[tot] = c;
ne[++tot] = h[v]; to[h[v] = tot] = u; co[tot] = 0;
}
bool bfs() {
rep(i, 1, m) d[i] = 0, now[i] = h[i];
queue<int> q; q.push(s); d[s] = 1;
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]]) if (co[i] && !d[y]) {
d[y] = d[x] + 1; q.push(y);
if (y == t) return 1;
}
}
return 0;
}
int dinic(int x, int flow) {
if (x == t) return flow;
int rest = flow, k;
for (int &i = now[x], y = to[i]; i && rest; y = to[i = ne[i]]) if (co[i] && d[y] == d[x] + 1)
if (!(k = dinic(y, min(rest, co[i])))) d[y] = 0;
else co[i] -= k, co[i ^ 1] += k, rest -= k;
return flow - rest;
}
int main() {
while (~scanf("%d%d", &n, &m)) {
tot = 1; k = n;
rep(i, 1, n) h[i] = h[n + i] = 0, add(i, i + n, 1);
rep(i, 1, m) {
int u, v; scanf(" (%d,%d)", &u, &v);
add(++u + n, ++v, inf); add(v + n, u, inf);
} m = n << 1;
rep (i, 2, tot) e[i] = co[i];
for (s = n + 1; s <= m; ++s) for (t = s - n + 1; t <= n; ++t) {
int flow = maxflow = 0;
rep (i, 2, tot) co[i] = e[i];
while (bfs()) while (flow = dinic(s, inf)) maxflow += flow;
k = min(k, maxflow);
}
printf("%d\n", k);
}
return 0;
}
k取方格数
const int N = 5e3 + 5, M = 4e4 + 5, inf = 1 << 30;
int n, m, _, k;
int h[N], to[M], ne[M], co[M], ed[M], tot;
int v[N], incf[N], pre[N], s, t, maxflow, d[N], ans;
int a[N][N];
void add(int u, int v, int e, int c) {
ne[++tot] = h[u]; to[h[u] = tot] = v; co[tot] = c, ed[tot] = e;
ne[++tot] = h[v]; to[h[v] = tot] = u; co[tot] = -c; ed[tot] = 0;
}
bool bfs() {
rep (i, 1, n) v[i] = 0, d[i] = -inf;
queue<int> q; q.push(s); v[s] = 1; d[s] = 0;
incf[s] = inf; //增广路上各边的最小剩余容量
while (!q.empty()) {
int x = q.front(); q.pop(); v[x] = 0;
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]]) if (ed[i] && d[y] < d[x] + co[i]) {
d[y] = d[x] + co[i]; pre[y] = i;
incf[y] = min(incf[x], ed[i]);
if (!v[y]) q.push(y), v[y] = 1;
}
}
return d[t] != -inf;
}
void update() {
for (int x = t, i = pre[x]; x != s; i = pre[x = to[i ^ 1]])
ed[i] -= incf[t], ed[i ^ 1] += incf[t];
maxflow += incf[t]; ans += d[t];
}
int get(int x, int y) { return n * (x - 1) + y; }
int main() {
IOS; cin >> n >> k; tot = 1; s = 1, t = n * n * 2;
rep (i, 1, n) rep (j, 1, n) {
cin >> m, add(get(i, j), get(i, j) + n * n, 1, m);
add(get(i, j), get(i, j) + n * n, k - 1, 0);
if (i - 1) add(get(i - 1, j) + n * n, get(i, j), k, 0);
if (j - 1) add(get(i, j - 1) + n * n, get(i, j), k, 0);
}
n = n * n * 2;
while (bfs()) update(); cout << ans;
return 0;
}
总结与练习
⭐观光
注意更新最小值的时候, 最小值也要更新次小值
int n, m, _, k, ans;
int d[2][N], cnt[2][N], s, t, v[N];
vector<vector<PII>> h, g;
void dij(int s) {
priority_queue<PII> q; q.push({ 0, s }); memset(v, 0, sizeof v);
d[0][s] = 0, cnt[0][s] = 1;
while (!q.empty()) {
int x = q.top().se; q.pop();
if (v[x]) continue; v[x] = 1;
for (auto& [y, c] : h[x]) {
if (d[0][y] > d[0][x] + c) {
if (umin(d[1][y], d[0][y])) cnt[1][y] = cnt[0][y];
q.push({ -(d[0][y] = d[0][x] + c), y }), cnt[0][y] = cnt[0][x];
}
else if (d[0][y] == d[0][x] + c) cnt[0][y] += cnt[0][x];
if (d[0][y] == d[0][x] + c) continue;
if (umin(d[1][y], d[0][x] + c)) cnt[1][y] = cnt[0][x];
else if (d[1][y] == d[0][x] + c) cnt[1][y] += cnt[0][x];
}
}
rep(i, 1, n)
if (d[1][i] != d[0][i] + 1) cnt[1][i] = 0, d[1][i] = d[0][i] + 1;
else q.push({ -d[1][i], i });
while (!q.empty()) {
int x = q.top().se; q.pop();
if (v[x] == 2) continue; v[x] = 2;
for (auto& [y, c] : h[x]) if (d[1][y] == d[1][x] + c)
cnt[1][y] += cnt[1][x], q.push({ -d[1][y], y });
}
}
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n >> m; vector<vector<PII>>(n + 1).swap(h); ans = 0;
rep(i, 1, m) { int u, v, c; cin >> u >> v >> c; h[u].pb(v, c); }
cin >> s >> t; memset(d, 0x3f, sizeof d); memset(cnt, 0, sizeof cnt);
dij(s); cout << cnt[1][t] + cnt[0][t] << '\n';
}
return 0;
}
升降电梯上
int n, m, _, k;
vector<pair<int, int>> h[N];
int d[N], s, t, a[21];
bool v[N];
void dji(int s) {
priority_queue<pair<int, int>> q;
memset(d, 0x3f, sizeof d); q.push({ d[s] = 0, s });
while (!q.empty()) {
int x = q.top().second; q.pop();
if (v[x]) continue; v[x] = 1;
for (auto &[y, c] : h[x]) if (d[y] > d[x] + c) q.push({-(d[y] = d[x] + c), y});
}
}
int main() {
cin >> n >> m;
rep (i, 1, m) { cin >> a[i]; if (!a[i]) k = i; }
memset(d, 0x3f, sizeof d);
rep (i, 1, n) rep(j, 1, m) rep(t, 1, m) if (a[t] && i + a[t] > 0 && i + a[t] <= n)
h[(i - 1) * m + j].emplace_back((i + a[t] - 1) * m + t, abs(a[t]) * 2 + abs(j - t));
dji(k);
int ans = d[0];
rep(i, (n - 1) * m + 1, n * m) ans = min(ans, d[i]);
cout << (ans == d[0]? - 1 : ans);
return 0;
}
GF和猫咪的玩具
int main() {
cin >> n >> m; memset(d, 0x3f, sizeof d);
rep (i, 0, n) d[i][i] = 0;
rep (i, 1, m) {
int u, v; cin >> u >> v;
d[u][v] = d[v][u] = min(d[u][v], 1);
}
rep (k, 1, n) rep (i, 1, n) rep (j, 1, n)
d[i][j] = min(d[i][k] + d[k][j], d[i][j]);
rep (i, 1, n) rep (j, 1, n) d[0][0] = max(d[0][0], d[i][j]);
cout << d[0][0];
return 0;
}
社交网络
int main() {
cin >> n >> m; memset(d, 0x3f, sizeof d);
rep (i, 1, n) d[i][i] = 0;
rep (i, 1, m) {
int u, v, c; cin >> u >> v >> c;
if (d[u][v] > c) d[u][v] = d[v][u] = c, a[u][v] = a[v][u] = 1;
else if (d[u][v] == c) ++a[u][v], ++a[v][u];
}
rep (k, 1, n) rep (i, 1, n) rep (j, 1, n) if (j != k && i != k)
if (d[i][j] > d[i][k] + d[k][j]) d[i][j] = d[i][k] + d[k][j], a[i][j] = a[i][k] * a[k][j];
else if (d[i][j] == d[i][k] + d[k][j]) a[i][j] += a[i][k] * a[k][j];
rep (k, 1, n) rep (i, 1, n) rep (j, 1, n) if (i != k && j != k && a[i][j])
if (d[i][k] + d[k][j] == d[i][j]) c[k] += (double)a[i][k] * a[k][j] / a[i][j];
rep (i, 1, n) cout << setiosflags(ios::fixed) << setprecision(3) << c[i] << '\n';
return 0;
}
北极网络
int ff(int x) { return x == f[x] ? x : f[x] = ff(f[x]); }
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n >> m; int k = 0;
for (int i = 1; i <= m; ++i) cin >> a[i].first >> a[i].second;
for (int i = 1; i < m; ++i) for (int j = 1; j <= m; ++j) d[i][j] = d[j][i] = 1e9;
for (int i = 1; i < m; ++i) for (int j = i + 1; j <= m; ++j)
d[i][j] = d[j][i] = sqrt(sqr(a[i].first - a[j].first) + sqr(a[i].second - a[j].second));
for (int k = 1; k <= m; ++k) for (int i = 1; i <= m; ++i) for (int j = 1; j <= m; ++j)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
for (int i = 1; i < m; ++i) for (int j = i + 1; j <= m; ++j) e[++k] = { i, j, d[i][j] };
sort(e + 1, e + k + 1, [](node& a, node& b) { return a.c < b.c; });
for (int i = 1; i <= m; ++i) f[i] = i;
for (int i = 1; i <= k; ++i) {
int x = ff(e[i].x), y = ff(e[i].y);
if (x == y) continue; --m; f[y] = x;
if (m == n) { cout << setiosflags(ios::fixed) << setprecision(2) << e[i].c << '\n'; break; }
}
}
return 0;
}
⭐四叶草魔杖
int cul(int d, int c) {
int ans = 0;
for (int i = 0; i < n; ++i) f[i] = i;
for (int i = 0; i < m && c; ++i) {
int x = ff(e[i].x), y = ff(e[i].y);
if (x == y || !(d >> x & 1) || !(d >> y & 1)) continue;
--c, f[y] = x, ans += e[i].c;
}
return c ? 0x3f3f3f3f : ans;
}
int main() {
cin >> n >> m; memset(ans, 0x3f, sizeof ans);
for (int i = 0; i < n; ++i) cin >> a[i];
for (int i = 0; i < m; ++i) cin >> e[i].x >> e[i].y >> e[i].c;
sort(e, e + m, [](node& a, node& b) { return a.c < b.c; });
for (int i = 1; i < 1 << n; ++i) {
int s = 0, c = 0; bool f = 0;
for (int j = 0; j < n; ++j) if (i >> j & 1) ++c, s += a[j], f = f | s;
if (!f) ans[i] = 0;
else if (s == 0)
if ((ans[i] = cul(i, c - 1)) == 0x3f3f3f3f) continue;
else for (int j = 1; j <= i >> 1; ++j) if ((i | j) == i)
ans[i] = min(ans[i], ans[i ^ j] + ans[j]);
}
if (ans[(1 << n) - 1] == 0x3f3f3f3f) cout << "Impossible";
else cout << ans[(1 << n) - 1];
return 0;
}
⭐直径
int n, m, cnt, las;
vector<pair<int, int>> h[N];
long long d[N], ans;
int dfs(int x, int fa, int dep) {
int res = dep;
for (auto& [y, c] : h[x]) if (y != fa) {
int cur = dfs(y, x, dep + 1);
if (ans < d[x] + d[y] + c)
ans = d[x] + d[y] + c, las = dep, cnt = res + cur - dep * 2;
else if (ans == d[x] + d[y] + c) {
if (d[y] + c >= d[x]) cnt = cur - las;
else cnt = res - las;
}
if (d[x] < d[y] + c) d[x] = d[y] + c, res = cur;
else if (d[x] == d[y] + c) res = dep;
}
return res;
}
int main() {
IOS; cin >> n;
for (int i = 1; i < n; ++i) {
int u, v, c; cin >> u >> v >> c;
h[u].emplace_back(v, c); h[v].emplace_back(u, c);
}
dfs(1, 0, 1); cout << ans << '\n' << cnt;
return 0;
}
逃课的小孩
void dfs(int u, int fa) {
for (int i = h[u], y = to[i]; i; y = to[i = ne[i]]) if (y ^ fa) {
f[y] = u; d[y] = d[u] + co[i]; dfs(y, u);
if (d[0] < d[y]) d[0] = d[y], f[0] = y;
}
}
void work(int& p, int& q) {
d[0] = -1; d[1] = 0; dfs(1, 0); p = f[0];
d[0] = -1; d[p] = 0; dfs(p, 0); q = f[0];
}
void dfss(int u, int fa) {
for (int i = h[u], y = to[i]; i; y = to[i = ne[i]]) if (y != fa) {
dfss(y, u);
fd[u] = max(fd[u], fd[y] + co[i]);
if (!st.count(u)) continue;
ans = max(ans, min(d[u], d[q] - d[u]));
if (st.count(y)) continue;
ans = max(ans, fd[y] + co[i] + min(d[u], d[q] - d[u]));
}
}
int main() {
IOS; cin >> n >> m;
rep (i, 1, m) {
int u, v, c; cin >> u >> v >> c;
add(u, v, c); add(v, u, c);
}
work(p, q); st.insert(p);
for (int i = q; i != p; st.insert(i), i = f[i]);
dfss(p, 0); cout << ans + d[q];
return 0;
}
聚会
const int N = 5e5 + 5;
struct STFrom {
int f[N][20], dep[N], lg[N], t;//N为节点的数量
vector<int> *h;
void init(int n, vector<int>* H) {
t = log2(n - 1) + 1; h = H; lg[0] = -1;
rep(i, 1, n) dep[i] = 0, lg[i] = lg[i >> 1] + 1;
}
void bfs(int s) {
queue<int> q; q.push(s); dep[s] = 1;
rep(i, 0, t) f[s][i] = 0;
while (!q.empty()) {
int x = q.front(); q.pop();
for (auto &y : h[x]) {
if (dep[y]) continue;
dep[y] = dep[x] + 1; f[y][0] = x; q.push(y);
for (int j = 1; j <= t; ++j) f[y][j] = f[f[y][j - 1]][j - 1];
}
}
}
int lca(int x, int y) {
if (dep[x] > dep[y]) swap(x, y);
for (int k = dep[y] - dep[x]; ~lg[k]; k ^= 1 << lg[k]) y = f[y][lg[k]];
if (x == y) return x;
per(i, lg[dep[y]], 0) if (f[x][i] ^ f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
int dist(int x, int y) { return dep[x] + dep[y] - (dep[lca(x, y)]<<1); }
} ST;
int n, m;
vector<int> h[N];
int main() {
IOS; cin >> n >> m;
rep (i, 2, n) {
int u, v; cin >> u >> v;
h[u].push_back(v); h[v].push_back(u);
}
ST.init(n, h); ST.bfs(1);
rep (i, 1, m) {
int x, y, z, xy, xz, yz, lc, p; cin >> x >> y >> z;
xy= ST.lca(x, y), xz = ST.lca(x, z), yz = ST.lca(y, z), lc = ST.lca(xy, z);
int ans = 1e9, d = ST.dep[x] + ST.dep[y] + ST.dep[z] - ST.dep[lc] * 2;
if (umin(ans, d - ST.dep[xy])) p = xy;
if (umin(ans, d - ST.dep[xz])) p = xz;
if (umin(ans, d - ST.dep[yz])) p = yz;a
cout << p << ' ' << ans << '\n';
}
return 0;
}
会合
struct STFrom {
int f[N][20], dep[N], lg[N], t;//N为节点的数量
int *h, *ne, *to, *fa;
bool *v;
void init(int n, int* H, int* Ne, int* T, int* F, bool* V) {
t = log2(n - 1) + 1; h = H, ne = Ne, to = T, fa = F, v = V; lg[0] = -1;
rep(i, 1, n) dep[i] = 0, lg[i] = lg[i >> 1] + 1;
}
void bfs(int s) {
queue<int> q; q.push(s); dep[s] = 1; fa[s] = s;
rep(i, 0, t) f[s][i] = 0;
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]]) if (!v[y] && !dep[y]) {
fa[y] = s; dep[y] = dep[x] + 1; f[y][0] = x; q.push(y);
for (int j = 1; j <= t; ++j) f[y][j] = f[f[y][j - 1]][j - 1];
}
}
}
int lca(int x, int y) {
if (dep[x] > dep[y]) swap(x, y);
for (int k = dep[y] - dep[x]; ~lg[k]; k ^= 1 << lg[k]) y = f[y][lg[k]];
if (x == y) return x;
per(i, lg[dep[y]], 0) if (f[x][i] ^ f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
} ST;
int n, m, _, k, cas;
int h[N], ne[N << 1], to[N << 1], tot;
int id[N], fa[N], st[N], top, d[N], cir[N];
bool v[N], vis[N];
void add(int u, int v) { ne[++tot] = h[u]; to[h[u] = tot] = v; }
int dfs(int x, int e) {
int s = 0;
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]]) if (i ^ e)
if (!vis[y]) vis[y] = 1, id[y] = id[x], s = s ^ dfs(y, i ^ 1);
else st[++top] = y, s = i & 1 ? y : -y;
if (s) st[++top] = x, v[x] = 1;
if (abs(s) == x) {
if (s == x) rep (i, 2, top) d[st[i]] = d[st[i - 1]] + 1, ST.bfs(st[i]);
else if (s == -x) per (i, top - 1, 1) d[st[i]] = d[st[i + 1]] + 1, ST.bfs(st[i]);
return cir[id[x]] = d[x], d[x] = 0;
}
return s;
}
int main() {
IOS; cin >> n >> m; tot = 1;
rep (i, 2, n) { int a; cin >> a; add(i, a); add(a, i); }
ST.init(n, h, ne, to, fa, v);
rep (i, 1, n) if (!vis[i]) vis[i] = 1, id[i] = i, top = 0, dfs(i, 0);
rep (i, 1, m) {
int x, y; cin >> x >> y;
if (id[x] ^ id[y]) cout << "-1 -1\n";
else if (fa[x] == fa[y]) {
int lc = ST.dep[ST.lca(x, y)];
cout << ST.dep[x] - lc << ' ' << ST.dep[y] - lc << '\n';
} else {
int a = ST.dep[x] - 1, b = ST.dep[y] - 1; x = fa[x], y = fa[y];
int c = (d[y] - d[x] + cir[id[x]]) % cir[id[x]], d = cir[id[x]] - c;
if (max(a + c, b) < max(a, b + d)) cout << a + c << ' ' << b << '\n';
else if (max(a + c, b) > max(a, b + d) || min(a + c, b) > min(a, b + d))
cout << a << ' ' << b + d << '\n';
else cout << a + c << ' ' << b << '\n';
}
}
return 0;
}
⭐雇佣收银员
看题目, 又是一堆不等式约束, 就想差分约束
老套路 设s[i] 表示 [0, i] 时间段内正在工作和已经工作完的总人数,
考虑到, 差分约束, 要从个入点开始, 也就是-1,
所以我们右移, 将 0~23 小时变为 1~24 小时, 0为入点且s[0] ≡ 0;
然而这是个环, 我们要拆环, 如果从 昨天工作到今天凌晨的不算入 s[1],
所以对 每小时的工作人数, 可这样获得(每个人工作8小时)
i >= 8, s[i] - s[i- 8] >= R[i - 1] ps:时间被我们右移了
i <= 7, s[i] + s[24] - s[24 - 8 + i] >= R[i - 1]
我们要将所有节点(小时)连接起来, 设b[i], 表示 在第i小时(平移过的)有多少人可以开始工作
s[i] - s[i - 1] >= 0
s[i] - s[i - 1] <= b[i]
s[24] - s[0] <= n
s[24] - s[0] >= 0
整理得
s[0] = 0
s[i] >= s[i- 1]
s[i - 1] >= s[i] - b[i]
i >= 8, s[i] >= s[i - 8] + R[i - 1]
i <= 7, s[i] >= s[16 + i] - s[24] + R[i - 1]
s[0] >= s[24] - n
s[24] >= s[0]
问题来了, (1)对于 i<= 7 的不等式, 怎么和两个点有关
再仔细一看, s[24]正是我们所求, 且s[24]是个与i无关的数, 即"常数"
所以我们可以枚举 s[24] 为 s24, 然后使得 s[24] - s[0] <= s24, s[24] - s[0] >= s24, 强制约束
由于求最小值, 从小到大枚举即可,
思考的, s[24]是单调的, 那么就可以二分
然后就是建边问题, 我们按照
s[i] >= s[i- 1]
s[i - 1] >= s[i] - b[i]
i >= 8, s[i] >= s[i - 8] + R[i - 1]
i <= 7, s[i] >= s[16 + i] -+ R[i - 1]
s[0] >= s[24]
s[24] >= s[0]
对于 边的序号 > 65的边 在搜索时取花费时额外 减去当前枚举的 s24, 并且 左后一条边的花费预先 加上 s24 * 2(取的时候 -s24)
int n, m, _, k;
int h[N], ne[3 * N], to[3 * N], co[3 * N], tot;
int a[N], b[N], dis[N], dep[N];
bool v[N];
void add(int u, int v, int c) { ne[++tot] = h[u]; to[h[u] = tot] = v; co[tot] = c; }
bool sfpa(int mid) {
memset(v, 0, sizeof v); memset(dis, 0xcf, sizeof dis);
stack<int> st; st.push(dep[0] = dis[0] = 0);
while (!st.empty()) {
int x = st.top(); st.pop(); v[x] = 0;
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]]) {
int c = co[i] - (i > 65) * mid;
if (dis[y] >= dis[x] + c) continue;
dis[y] = dis[x] + c; dep[y] = dep[x] + 1;
if (dep[y] >= 25) return 0;
if (!v[y]) v[y] = 1, st.push(y);
}
}
return 1;
}
int main() {
IOS;
for (cin >> _; _; --_) {
rep (i, 1, 24) cin >> a[i]; cin >> n; tot = 0;
memset(h, 0, sizeof h); memset(b, 0, sizeof b);
rep (i, 1, n) cin >> m, ++b[++m];
rep (i, 1, 24) add(i, i - 1, -b[i]), add(i - 1, i, 0);
rep (i, 8, 24) add(i - 8, i, a[i]);
rep (i, 1, 7) add(i + 16, i, a[i]);
add (24, 0, 0); add(0, 24, 0);
int l = 0, r = n + 1;
while (l < r) {
int mid = l + r >> 1; co[tot] = mid << 1;
if (sfpa(mid)) r = mid;
else l = mid + 1;
}
if (r == n + 1) cout << "No Solution\n";
else cout << r << '\n';
}
return 0;
}
⭐最优高铁环
二分不解释, 注意有向图遍历负环环的技巧
int n, m, _, k, f[N], dep[N];
vector<pair<int, int>> h[N];
unordered_map<ull, int> st;
double dis[N];
bool v[N];
int get(int x) {
switch (x) {
case 'S': return 1000;
case 'G': return 500;
case 'D': return 300;
case 'T': return 200;
default: return 150;
}
}
bool dfs(int x, double mid) {
v[x] = 1;
for (auto &[y, c] : h[x]) {
if (dis[y] > dis[x] + mid - c) {
dis[y] = dis[x] + mid - c;
if (v[y] || dfs(y, mid)) return 1;
}
}
return v[x] = 0;
}
bool check(double mid) {
rep (i, 1, n) dis[i] = 2e4, v[i] = 0;
rep (i, 1, n) if(dfs(i, mid)) return 1;
return 0;
}
int main() {
IOS; cin >> m;
rep(i, 1, m) {
string s; cin >> s; ull u = 0, v = 0; int co = 0;
for (char& c : s)
if (c == '-') u = (u ? u : v), v = 0;
else co += (v ? 0 : get(c)), v = v * p + c;
if (!st.count(u)) st[u] = st.size() + 1;
if (!st.count(v)) st[v] = st.size() + 1;
h[st[u]].emplace_back(st[v], co);
} n = st.size();
double l = 0, r = 2e4, ans = -1;
while (r - l > 1e-2) {
double mid = (r + l) / 2;
if (check(mid)) l = ans = mid;
else r = mid;
}
cout << round(ans);
return 0;
}
冗余路径
int n, m, _, k;
int h[N], to[M << 1], ne[M << 1], tot;
int dfn[N], low[N], df, st[N], top;
int ecc[N], ecnt, deg[N];
void add(int u, int v) {
ne[++tot] = h[u]; to[h[u] = tot] = v;
}
void tarjan(int x, int e) {
dfn[x] = low[x] = ++df; st[++top] = x;
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]]) if (i ^ e)
if (!dfn[y]) tarjan(y, i ^ 1), low[x] = min(low[x], low[y]);
else low[x] = min(low[x], dfn[y]);
if (low[x] == dfn[x]) {
++ecnt; int y;
do ecc[y = st[top--]] = ecnt; while (y ^ x);
}
}
int main() {
IOS; cin >> n >> m; tot = 1;
rep (i, 1, m) {
int u, v; cin >> u >> v;
add(u, v); add(v, u);
}
rep (i, 1, n) if (!dfn[i]) top = 0, tarjan(i, 0);
for (int i = 2; i <= tot; i += 2) {
int x = to[i ^ 1], y = to[i];
if (ecc[x] == ecc[y]) continue;
++deg[ecc[x]], ++deg[ecc[y]];
}
rep (i, 1, ecnt) if (deg[i] == 1) ++k;
cout << (k + 1) / 2;
return 0;
}
⭐矿场搭建
对于缩完点的一颗树,
对于单点, 只能在这个点建, 这个点塌了, 正好
对于单缩点, 任意选两个点, 一个点塌了, 还能到另一个
对于树形结构, 塌一个割点, 将树分成两部分
对于dcc连接多个dcc(有多个割点), 不管塌哪个割点, 都能从其他的割点逃离
对于只有一个割点的, 选dcc内除了割点的任意一点, 割点塌了, 能直达, 这个点塌了, 从割点逃离
int n, m, _, k;
vector<int> h[N];
int dfn[N], low[N], df, st[N], top, root;
vector<vector<int>> dcc;
bool cut[N];
void tarjan(int x) {
dfn[x] = low[x] = ++df;
if (h[x].empty()) { dcc.push_back(vector<int>(1, x)); return; }
st[++top] = x; int cnt = 0;
for (auto &y : h[x])
if (!dfn[y]) {
tarjan(y); low[x] = min(low[x], low[y]);
if (dfn[x] <= low[y]) {
++cnt; dcc.push_back(vector<int>(1, x)); int z;
if (x != root || cnt > 1) cut[x] = 1;
do dcc.back().push_back(z = st[top--]); while (z ^ y);
}
}
else low[x] = min(low[x], dfn[y]);
}
int main() {
IOS;
while (cin >> m, n = df = 0, m) {
rep(i, 1, m) {
int u, v; cin >> u >> v;
if (u > v) swap(u, v);
while (n < v) ++n, vector<int>().swap(h[n]), dfn[n] = cut[n] = 0;
h[u].push_back(v); h[v].push_back(u);
}
int ans = 0; long long sum = 1;
rep(i, 1, n) if (!dfn[i]) {
vector<vector<int>>().swap(dcc); tarjan(root = i);
if (dcc.size() == 1)
if (dcc[0].size() == 1) ans += 1;
else ans += 2, sum *= dcc[0].size() * (dcc[0].size() - 1) >> 1;
else for (auto& ve : dcc) {
int cnt = 0;
for (auto& i : ve) if (cut[i]) ++cnt;
if (cnt == 1) ++ans, sum *= ve.size() - 1;
}
}
cout << "Case " << ++_ << ": " << ans << ' ' << sum << '\n';
}
return 0;
}
逃不掉的路
void add(int u, int v) { ne[++tot] = h[u]; to[h[u] = tot] = v; }
void add_c(int u, int v) { nc[++totc] = hc[u]; tc[hc[u] = totc] = v; }
void bfs(int s) {
queue<int> q; q.push(s); dep[s] = 1;
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = hc[x], y = tc[i]; i; y = tc[i = nc[i]]) if (!dep[y]) {
dep[y] = dep[x] + 1; f[y][0] = x;
for (int j = 1; j <= t; ++j) f[y][j] = f[f[y][j - 1]][j - 1];
q.push(y);
}
}
}
int lca(int x, int y) {
if (dep[x] > dep[y]) swap(x, y);
per (i, t, 0) if (dep[f[y][i]] >= dep[x]) y = f[y][i];
if (x == y) return x;
per (i, t, 0) if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
int dist(int x, int y) { return dep[x] + dep[y] - 2 * dep[lca(x, y)]; }
void tarjan(int x, int bian) {
dfn[x] = low[x] = ++df;
st[++top] = x;
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]])
if (!dfn[y]) {
tarjan(y, i); low[x] = min(low[x], low[y]);
if (dfn[x] < low[y]) edge[i] = edge[i ^ 1] = 1;
}
else if (i != (bian ^ 1)) low[x] = min(low[x], dfn[y]);
if (low[x] == dfn[x]) {
++ecnt; int y;
do ecc[y = st[top--]] = ecnt; while (y ^ x);
}
}
int main() {
IOS; cin >> n >> m; tot = 1;
rep (i, 1, m) {
int u, v; cin >> u >> v;
add(u, v); add(v, u);
}
rep (i, 1, n) if (!dfn[i]) top = 0, tarjan(i, 0);
rep (i, 2, tot) { //可能有重边
int x = to[i ^ 1], y = to[i];
if (ecc[x] ^ ecc[y]) add_c(ecc[x], ecc[y]);
}
t = log2(ecnt - 1) + 1; bfs(1); cin >> m;
rep (i, 1, m) {
int u, v; cin >> u >> v; u = ecc[u], v = ecc[v];
cout << dist(u, v) << '\n';
}
return 0;
}
⭐交通实时查询系统
const int N = 1e4 + 5, M = 2e5 + 5;
struct STFrom {
static const int N = 2e4 + 5;
int f[N][20], dep[N], lg[N], t;//N为节点的数量
int* h, * ne, * to;
void init(int n, int* H, int* Ne, int* To) {
t = log2(n - 1) + 1; h = H, ne = Ne, to = To; lg[0] = -1;
rep(i, 1, n) dep[i] = 0, lg[i] = lg[i >> 1] + 1;
}
void bfs(int s) {
queue<int> q; q.push(s); dep[s] = 1;
rep(i, 0, t) f[s][i] = 0;
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]]) {
if (dep[y]) continue;
dep[y] = dep[x] + 1; f[y][0] = x; q.push(y);
for (int j = 1; j <= t; ++j) f[y][j] = f[f[y][j - 1]][j - 1];
}
}
}
int lca(int x, int y) {
if (dep[x] > dep[y]) swap(x, y);
for (int k = dep[y] - dep[x]; ~lg[k]; k ^= 1 << lg[k]) y = f[y][lg[k]];
if (x == y) return x;
per(i, lg[dep[y]], 0) if (f[x][i] ^ f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
int dist(int x, int y) { return dep[x] + dep[y] - (dep[lca(x, y)] << 1); }
} ST;
int n, m, _, q;
int h[N], ne[M], to[M], tot, bl[M >> 1];
int dfn[N], low[N], df, st[N], top, c[N];
vector<vector<int>> vcc;
bool cut[N], root;
int newid[N << 1];
int nh[N << 1], nne[N << 2], nto[M << 2], ntot;
void add(int u, int v) { ne[++tot] = h[u]; to[h[u] = tot] = v; }
void add_c(int u, int v) { nne[++ntot] = nh[u]; nto[nh[u] = ntot] = v; }
void tarjan(int x) {
dfn[x] = low[x] = ++df, st[++top] = x; int cnt = 0;
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]])
if (!dfn[y]) {
tarjan(y); low[x] = min(low[x], low[y]);
if (dfn[x] <= low[y]) {
vcc.push_back(vector<int>(1, x));
if (++cnt > 1 || x != root) cut[x] = 1;
for (int z = 0; z ^ y; z = st[top--]) vcc.back().push_back(st[top]);
}
}
else low[x] = min(low[x], dfn[y]);
}
int main() {
IOS;
while (cin >> n >> m, n || m) {
vcc.resize(0);
rep(i, 1, n) h[i] = dfn[i] = cut[i] = newid[i] = 0;
df = ntot = 0; tot = 1;
rep(i, 1, m) {
int u, v; cin >> u >> v;
add(u, v); add(v, u);
}
rep(i, 1, n) if (!dfn[i]) top = 0, root = i, tarjan(i);
int num = vcc.size();
rep (i, 1, n) if (cut[i]) newid[i] = ++num;
rep(i, 1, num) nh[i] = 0;
rep(i, 1, vcc.size())
for (auto& x : vcc[i - 1]) {
c[x] = i;
if (cut[x]) add_c(newid[x], i), add_c(i, newid[x]);
for (int j = h[x]; j; j = ne[j]) if (c[to[j]] == i) bl[j >> 1] = i;
}
ST.init(num, nh, nne, nto);
rep(i, 1, num) if (!ST.dep[i]) ST.bfs(i);
for (cin >> q; q; --q) {
int x, y; cin >> x >> y; x = bl[x], y = bl[y];
cout << (ST.dist(x, y) + 1 >> 1) << '\n';
}
}
return 0;
}
约翰的旅行
bool eulerc(int s) {
for (auto& i : edge)
if (i.size() & 1) return 0;
else sort(all(i), greater<PII>());
top = t = 0; st[++top] = 0; st[++top] = s;
while (top) {
int x = st[top];
while (!edge[x].empty() && vis[edge[x].back().fi]) edge[x].pop_back();
if (!edge[x].empty()) {
st[++top] = edge[x].back().fi;
st[++top] = edge[x].back().se;
vis[st[top - 1]] = 1; edge[x].pop_back();
}
else ans[++t] = st[(--top)--];
}
return 1;
}
int main() {
while (1) {
edge.resize(0); k = n = 0;
while (cin >> u >> v, u && v) {
if (u > v) swap(u, v);
if (!n) n = u;
cin >> z; ++k; vis[z] = 0;
per(i, v - edge.size() + 1, 1) edge.pb(vector<PII>(0));
edge[u].pb(z, v); edge[v].pb(z, u);
}
if (!n) break;
if (eulerc(n)) per(i, t - 1, 1) cout << ans[i] << ' ';
else cout << "Round trip does not exist.";
cout << '\n';
}
return 0;
}
⭐太鼓达人
注意到最多有\(2^k\)个01串, 构造是不太可能的
代码不难, 转换图的思想却很难想到(不放专题里, 我是想不到转换图做)
注意到任何一个串可以通向两个另外的串, 也由两个串可以到达, 故每个串的入度和出度都为2
注意到这\(2^k\)串组成的图是个欧拉图, 那么必定存在欧拉回路, 之后就是怎么走路径最小了
int n, m, _, k, a, ans[2050];
bool v[2050];
bool dfs(int x, int k) {
if (k == (1 << n)) return 1; v[x] = 1;
if (!v [(x << 1) & a]) if (dfs((x << 1) & a, k + 1)) return ans[k] = 0, 1;
if (!v[(x << 1 | 1) & a]) if (dfs((x << 1 | 1) & a, k + 1)) return ans[k] = 1;
return v[x] = 0;
}
int main() {
cin >> n; a = 1 << n;
cout << a-- << ' '; dfs(0, 1);
for (int i = 1; i <= n; ++i) cout << 0;
for (int i = 1; i <= a - n + 1; ++i) cout << ans[i];
return 0;
}
⭐从u到v还是从v到u?
void tarjan(int x) {
dfn[x] = low[x] = ++df; inst[st[++top] = x] = 1;
for (auto& y : h[x])
if (!dfn[y]) tarjan(y), low[x] = min(low[x], low[y]);
else if (inst[y]) low[x] = min(low[x], dfn[y]);
if (low[x] == dfn[x]) {
++scnt;
for (int y = 0; y ^ x; y = st[top--]) c[st[top]] = scnt, inst[st[top]] = 0;
}
}
int main() {
for (cin >> _; _; --_) {
cin >> n >> m; df = scnt = top = 0;
for (int i = 1; i <= n; ++i) h[i].resize(0), dfn[i] = inst[i] = 0;
for (int i = 1; i <= m; ++i) {
int u, v; cin >> u >> v;
h[u].push_back(v); ++deg[v];
}
int f = 0, id = 1; for (int i = 1; i <= n; ++i) if (!deg[i]) ++f, id = i; else deg[i] = 0;
if (f > 1) { cout << "No\n"; continue; } tarjan(id); id = f = 0;
vector<set<int>> g(scnt + 1);
for (int x = 1; x <= n; ++x) for (auto& y : h[x])
if ((c[y] ^ c[x]) && !g[c[x]].count(c[y])) g[c[x]].insert(c[y]), ++deg[c[y]];
for (int i = 1; i <= scnt; ++i) if (!deg[i]) ++f, id = i;
if (f > 1) { cout << "No\n"; continue; } f = 0;
st[top = 1] = id;
while (top) {
int x = st[top--];
for (auto& y : g[x]) if (--deg[y] == 0) st[++top] = y;
if (top > 1) f = 1, top = 0;
}
for (int i = 1; i <= scnt; deg[i++] = 0) if (deg[i] > 1) ++f;
cout << (f ? "No\n" : "Yes\n");
}
return 0;
}
⭐杀人游戏
考虑孤点
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
using namespace std;
const int N = 1e5 + 5, M = 3e5 + 5;
int n, m, _, k;
vector<int> h[N], g[N];
int dfn[N], low[N], df, st[N], top;
int c[N], scnt;
vector<vector<int>> scc;
bool inst[N], f;
int indeg[N];
void tarjan(int x) {
dfn[x] = low[x] = ++df; inst[st[++top] = x] = 1;
for (auto &y : h[x])
if (!dfn[y]) tarjan(y), low[x] = min(low[x], low[y]);
else if (inst[y]) low[x] = min(low[x], dfn[y]);
if (low[x] == dfn[x]) {
++scnt; int y; scc.push_back(vector<int>());
do inst[y = st[top--]] = 0, c[y] = scnt, scc.back().push_back(y); while (y ^ x);
}
}
int dfs(int x) {
int ans = scc[x - 1].size();
for (auto &y : g[x]) ans += dfs(y);
return ans;
}
int main() {
IOS; cin >> n >> m;
rep (i, 1, m) {
int u, v; cin >> u >> v;
h[u].push_back(v);
}
rep (i, 1, n) if (!dfn[i]) top = 0, tarjan(i);
rep (i, 1, n) for (auto &y : h[i])
if (c[i] ^ c[y]) g[c[i]].push_back(c[y]), ++indeg[c[y]];
int x = 0;
rep (i, 1, scnt) if (!indeg[i]) {
++x;
if (scc[i - 1].size() > 1 || f) continue;
f = 1;
for (auto &y : g[i]) if (indeg[y] == 1) f = 0;
}
double res = ((double)n - x + f) / n;
cout << setiosflags(ios::fixed) << setprecision(6) << res;
return 0;
}
⭐平面
平面图:设无向图G,若能将G画在一个平面上,使得任何两条边仅在顶点处相交,则称G是具有平面性质的图,简称平面图,否则称G是非平面图。
在平面图G中,G的边将其所在的平面划分成的区域称为面,有限的区域称为有限面或内部面,无线的区域称为无限面或外部面,
包围面的边称为该面的边界,包围每个面的所有边组成的回路长度称为该面的次数(桥计算两次)。
那么有, 平面图G所有面的次数之和等于边数的两倍(类似于握手定理)。
欧拉定理: 对于一个简单通平面图, 设G是一个面数为 f 的(n,m)平面图,则 n-m+f=2.(归纳法证)
推论1, 设G是一个面数为 f 的(n,m)平面图,且有p个连通分支,则 n-m+f=p+1(所有连通分支共用一个无限面)
推论2, 假设G是一个面数为 f 的(n,m)连通简单平面图,n≥3,每个面的次数至少是 p(p≥3),则m≤(n-2)*p/(p-2)。//n>=3, 则边数 m>=2,无限面的次数至少为2*2
有定义出发, 面的次数之和等于边数两倍, 故 f*p ≤ 2 * m, 带入欧拉公式可得上式
int n, m, _, k;
PII e[M];
int f[M << 1], id[N];
int ff(int x) { return x == f[x] ? x : f[x] = ff(f[x]); }
bool check(int a, int b, int c) {
if(id[a] > id[b]) swap(a, b);
return id[a] < id[c] && id[b] > id[c];
}
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n >> m;
rep (i, 1, m) cin >> e[i].fi >> e[i].se, f[i] = i, f[i + m] = i + m;
rep (i, 1, n) cin >> k, id[k] = i;
if (m > 3 * n - 6) { cout << "NO\n"; continue; }
rep (i, 1, m) rep (j, i + 1, m) {
if (e[i].fi == e[j].fi || e[i].fi == e[j].se || e[i].se == e[j].fi || e[i].se == e[j].se) continue;
if (check(e[i].fi, e[i].se, e[j].fi) == check(e[i].fi, e[i].se, e[j].se)) continue;
f[ff(i)] = ff(j + m), f[ff(j)] = ff(i + m);
}
bool f = 1;
rep (i, 1, m) if (ff(i) == ff(i + m)) { f = 0; break; }
cout << (f ? "YES\n" : "NO\n");
}
return 0;
}
⭐婚礼
按照题意, 分为新郎 和 新娘列, 然而新郎列出了gay佬, (新郎不介意出现百合)
此问题就是如何决策新郎那列座位问题
即新郎那列\(a_i\)这个位置坐第i对的新郎还是新娘的问题
设\(a_i=0\)代表这个位置坐新娘, 反之为新郎,
那直接并查集?
然而不行, 并查集解决的是无向的取值问题,
而这题关系是单向的(新娘列不关注有无通奸者)
那就只能2-sat了,
而这题比较特殊, 新郎列第0个位置必须为新郎(强制排除了一些答案)
根据2-sat逆序拓扑取值问题, 我们人为加边 (0, n-1) 强制 n-1 在 1拓扑序的后面
最后求完一组可行解, 是新郎列的, 我们还要把性别取反, 变成新娘列
void tarjan(int x) {
dfn[x] = low[x] = ++df; inst[st[++top] = x] = 1;
rep(y, 1, k) if (h[x][y])
if (!dfn[y]) tarjan(y), low[x] = min(low[x], low[y]);
else if (inst[y]) low[x] = min(low[x], dfn[y]);
if (low[x] == dfn[x]) {
++scnt; int y;
do inst[y = st[top--]] = 0, c[y] = scnt; while (y != x);
}
}
bool check() {
rep(i, 1, n) if (c[i] == c[i + n]) return puts("bad luck"), 1;
return 0;
}
int main() {
while (~scanf("%d%d", &n, &m), n || m) {
k = n << 1; scnt = df = 0;
rep(i, 1, n) opp[i] = i + n, opp[i + n] = i;
rep(i, 1, k) dfn[i] = inst[i] = 0;
rep(i, 1, k) rep(j, 1, k) h[i][j] = 0;
h[1][n + 1] = 1;
rep(i, 1, m) {
int a, b; char s, t; scanf("%d%c %d%c", &a, &s, &b, &t);
if (s == 'h') a += n;
if (t == 'h') b += n;
++a, ++b, h[a][opp[b]] = h[b][opp[a]] = 1;
}
rep(i, 1, k) if (!dfn[i]) top = 0, tarjan(i);
if (check()) continue;
rep(i, 2, n) printf("%d%c ", i - 1, c[i] > c[i + n] ? 'w' : 'h'); puts("");
}
return 0;
}
⭐将他们分好队
并查集还要再去判断并查集内部是否不矛盾, 然后不同祖先的两个集合也要去判断, 集合内部是否矛盾
直接染色, 去跑图
将图每次分成3部分, 必须和i同时在一个组的, 必须和i不能再同一个组的, 和自由选择的
保证和i同组的能随便选自由的吗不和i同组也可选自由的, 直接跑dp即可
int n, m, _, k;
int h[N][N], v[N], f[N][N << 1];
VI a, b;
vector<pair<VI, VI>> ans;
bool dfs(int x, int c) {
if (c == 1) v[x] = 1, ans.back().fi.pb(x);
else v[x] = 2, ans.back().se.pb(x);
rep(y, 1, n) if (h[x][y] && v[y] != 3 - c)
if (v[y] == c || dfs(y, 3 - c)) return 1;
return 0;
}
void work(int n, int k) {
if (!n) return;
int c = ans[n - 1].fi.size() - ans[n - 1].se.size();
if (f[n][k] == 1) {
a.insert(a.end(), all(ans[n - 1].fi));
b.insert(b.end(), all(ans[n - 1].se));
work(n - 1, k - c);
} else {
a.insert(a.end(), all(ans[n - 1].se));
b.insert(b.end(), all(ans[n - 1].fi));
work(n - 1, k + c);
}
}
int main() {
IOS; cin >> n;
rep(i, 1, n) rep(j, i + 1, n) h[i][j] = h[j][i] = 1;
rep(i, 1, n) while (cin >> m, m) h[i][m] = 0;
rep(i, 1, n) rep(j, 1, n) if (h[i][j]) h[j][i] = 1;
rep(i, 1, n) if (!v[i]) {
ans.pb({ VI(), VI() });
if (dfs(i, 1)) return cout << "No solution", 0;
}
memset(f, -1, sizeof f); f[0][n] = 0;
rep(i, 1, ans.size()) rep(j, 0, n << 1) {
int c = ans[i - 1].fi.size() - ans[i - 1].se.size();
if (f[i - 1][j] != -1) f[i][j + c] = 1, f[i][j - c] = 2;
}
rep(j, 0, n)
if (f[ans.size()][j + n] != -1) { work(ans.size(), j + n); break; }
else if (f[ans.size()][n - j] != -1) { work(ans.size(), n - j); break; }
sort(all(a)); sort(all(b));
cout << a.size(); for (auto& i : a) cout << ' ' << i;
cout << '\n' << b.size(); for (auto& i : b) cout << ' ' << i;
return 0;
}
放置机器人
bool dfs(int x) {
for (auto &y : h[x]) {
if (v[y]) continue; v[y] = 1;
if (!match[y] || dfs(match[y])) return match[y] = x, 1;
}
return 0;
}
int main() {
IOS; int cas = 0;
for (cin >> _; _; --_) {
cin >> n >> m; h.resize(1); match.resize(1);
rep (i, 1, n) {
cin >> s[i] + 1; match.pb(0);
rep (j, 1, m)
if (s[i][j] == '#') match.pb(0);
else idx[i][j] = match.size() - 1;
}
rep (j, 1, m) {
h.pb(VI());
rep (i, 1, n)
if (s[i][j] == '#') h.pb(VI());
else if (s[i][j] == 'o') h.back().pb(idx[i][j]);
}
int ans = 0;
rep (i, 1, h.size() - 1) { vector<bool>(match.size()).swap(v); ans += dfs(i); }
cout << "Case :" << ++cas << '\n' << ans << '\n';
}
return 0;
}
稳定的牛分配
bool dfs(int x, int l, int r) {
rep(i, l, r) if (cnt[ls[x][i]] < g[ls[x][i]]) return match[ls[x][i]][++cnt[ls[x][i]]] = x, 1;
rep (i, l, r) rep (j, 1, g[ls[x][i]]) if (!v[ls[x][i]][j]) {
v[ls[x][i]][j] = 1;
rep (j, 1, g[ls[x][i]]) if (dfs(match[ls[x][i]][j], l, r)) return match[ls[x][i]][j] = x, 1;
}
return 0;
}
int main() {
cin >> n >> m; k = inf;
rep (i, 1, n) rep (j, 1, m) cin >> ls[i][j];
rep (i, 1, m) cin >> g[i];
for (int l = 1, r = 1; l <= m; ++l) for (; r <= m; ++r) {
rep (i, 1, m) cnt[i] = 0; bool f = 1;
rep (i, 1, n) { memset(v, 0, sizeof v); if (!(f = dfs(i, l, r))) { f = 0; break; } }
if (f) { k = min(k, r - l + 1); break; }
}
cout << k;
return 0;
}
回家
int n, m, _, k;
int h[N], to[M], ne[M], co[M], ed[M], tot;
int v[N], incf[N], pre[N], s, t, maxflow, d[N], ans;
vector<PII> person, house;
void add(int u, int v, int e, int c) {
ne[++tot] = h[u]; to[h[u] = tot] = v; co[tot] = c, ed[tot] = e;
ne[++tot] = h[v]; to[h[v] = tot] = u; co[tot] = -c; ed[tot] = 0;
}
bool bfs() {
rep (i, 1, n) v[i] = 0, d[i] = inf;
queue<int> q; q.push(s); v[s] = 1; d[s] = 0;
incf[s] = inf; //增广路上各边的最小剩余容量
while (!q.empty()) {
int x = q.front(); q.pop(); v[x] = 0;
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]]) {
if (!ed[i] || d[y] <= d[x] + co[i]) continue;
d[y] = d[x] + co[i]; pre[y] = i;
incf[y] = min(incf[x], ed[i]);
if (!v[y]) q.push(y), v[y] = 1;
}
}
return d[t] != inf;
}
void update() {
for (int x = t, i = pre[x]; x != s; i = pre[x = to[i ^ 1]])
ed[i] -= incf[t], ed[i ^ 1] += incf[t];
maxflow += incf[t]; ans += d[t] * incf[t];
}
int dis(int x, int y) {
return abs(person[x].fi - house[y].fi) + abs(person[x].se - house[y].se);
}
void init() {
clear(person); clear(house);
rep (i, 1, n) rep (j, 1, m) {
char c; cin >> c;
if (c == 'm') person.pb({ i, j });
else if (c == 'H') house.pb({ i, j });
}
n = person.size() + house.size();
s = ++n; t = ++n; tot = 1; maxflow = ans = 0;
rep (i, 1, n) h[i] = 0;
rep(i, 0, person.size() - 1) rep(j, 0, house.size() - 1)
add(i + 1, j + 1 + person.size(), 1, dis(i, j));
rep (i, 0, person.size() - 1) add(s, i + 1, 1, 0);
rep (i, 0, house.size() - 1) add(person.size() + i + 1, t, 1, 0);
}
int main() {
IOS;
while (cin >> n >> m, n || m) {
init(); while (bfs()) update();
cout << ans << '\n';
}
return 0;
}
空袭
void add(int u, int v) { ne[++tot] = h[u]; to[h[u] = tot] = v; }
bool dfs(int x) {
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]]) if (!v[y]) {
v[y] = 1;
if (!match[y] || dfs(match[y])) return match[y] = x;
}
return 0;
}
int main() {
IOS;
for (cin >> _; _; --_) {
cin >> n >> m; tot = 2;
rep (i, 1, n) match[i] = h[i] = 0;
rep (i, 1, m) { int u, v; cin >> u >> v; add(u, v); }
ans = n;
rep (i, 1, n) { rep (i, 1, n) v[i] = 0; ans -= dfs(i); }
cout << ans << '\n';
}
return 0;
}
排版幻灯片
int n, m, _, k;
vector<int> h[N];
int id[N >> 1], ans, deg[N];
bool v[N >> 1];
pair<PII, PII> paper[N >> 1];
bool check(int i, int x, int y) {
return x >= paper[i].fi.fi && x <= paper[i].fi.se && y >= paper[i].se.fi && y <= paper[i].se.se;
}
int main() {
IOS;
while (cin >> n, m = 0, n) {
rep(i, 1, n) h[i].resize(0), h[i + n].resize(0), id[i] = deg[i] = deg[i + n] = v[i + n] = 0;
rep(i, 1, n) cin >> paper[i].fi.fi >> paper[i].fi.se >> paper[i].se.fi >> paper[i].se.se;
rep(i, 1, n) {
int x, y; cin >> x >> y;
rep(j, 1, n) if (check(j, x, y)) h[i + n].push_back(j), h[j].push_back(i + n), ++deg[j], ++deg[i + n];
}
while (1) {
int c = 0;
rep(i, 1, n << 1) if (deg[i] == 1) { c = i; break; }
if (!c) break; --deg[c]; ++m;
if (c <= n) for (auto &y : h[c]) { if (!v[y]) { id[c] = y - n, v[c = y] = 1; break; } }
else for (auto &y : h[c]) if (!id[y]) { id[y] = c - n, v[c = y] = 1; break; }
for (auto &y : h[c]) --deg[y];
}
cout << "Heap " << ++_ << '\n';
if (m) rep(i, 1, n) { if (id[i]) cout << '(' << char('A' + i - 1) << ',' << id[i] << ") "; }
else cout << "none"; cout << '\n' << '\n';
}
return 0;
}
国王的任务
int n, m, _, k;
vector<int> h[N];
int dfn[N], low[N], df, st[N], top;
int c[N], scnt;
bool inst[N];
void tarjan(int x) {
dfn[x] = low[x] = ++df; inst[st[++top] = x] = 1;
for (auto &y : h[x])
if (!dfn[y]) tarjan(y), low[x] = min(low[x], low[y]);
else if (inst[y]) low[x] = min(low[x], dfn[y]);
if (low[x] == dfn[x]) {
++scnt; int y;
do inst[y = st[top--]] = 0, c[y] = scnt; while (y != x);
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) for (cin >> _; _; --_) cin >> m, h[i].emplace_back(m + n);
for (int i = 1; i <= n; ++i) cin >> m, h[m + n].emplace_back(i);
for (int i = 1; i <= n; ++i) if (!dfn[i]) top = 0, tarjan(i);
for (int i = 1; i <= n; ++i) {
vector<int> ans;
for (auto &y : h[i]) if (c[i] == c[y]) ans.emplace_back(y - n);
sort(ans.begin(), ans.end()); cout << ans.size();
for (auto &j : ans) cout << ' ' << j; cout << '\n';
}
return 0;
}
排水沟
int n, m, _, k;
int h[N], ne[M], to[M], co[M], now[N], tot;
int d[N], s, t, maxflow;
void add(int u, int v, int c) {
ne[++tot] = h[u]; to[h[u] = tot] = v; co[tot] = c;
ne[++tot] = h[v]; to[h[v] = tot] = u; co[tot] = 0;
}
bool bfs() {
memset(d, 0, sizeof d); memcpy(now, h, sizeof h);
queue<int> q; q.push(s); d[s] = 1;
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = h[x], y = to[i]; i; y = to[i = ne[i]]) if (co[i] && !d[y]) {
d[y] = d[x] + 1; q.push(y);
if (y == t) return 1;
}
}
return 0;
}
int dinic(int x, int flow) {
if (x == t) return flow;
int rest = flow, k;
for (int &i = now[x], y = to[i]; i && rest; y = to[i = ne[i]]) if (co[i] && d[y] == d[x] + 1)
if (!(k = dinic(y, min(rest, co[i])))) d[y] = 0;
else co[i] -= k, co[i ^ 1] += k, rest -= k;
return flow - rest;
}
int main() {
IOS; cin >> m >> n; tot = 1; s = 1, t = n;
rep (i, 1, m) {
int u, v, c; cin >> u >> v >> c;
add(u, v, c);
}
int flow = 0;
while (bfs()) while (flow = dinic(s, inf)) maxflow += flow;
cout << maxflow;
return 0;
}