2025.8.5 测试
P12710 [KOI 2021 Round 1] 两个团队
\(f_u:\) 以 \(u\) 为根的连通块最优值。
\(g_u:\) \(u\) 子树内除了以 \(u\) 为根的连通块最优值。
\(h_u:\) \(u\) 子树内连通块最优值。
转移是容易的。
点击查看
#include <bits/stdc++.h>
#define lep(i, a, b) for (int i = a; i <= b; ++i)
#define rep(i, a, b) for (int i = a; i >= b; --i)
const int _ = 2e5 + 7;
typedef long long ll;
const ll inf = 1e17;
int n, fa[_], val[_]; ll f[_], g[_], h[_], ans(-inf);
std::vector <int> e[_];
void Solve(int u) { ll fir = -inf, sec = -inf;
g[u] = h[u] = -inf;
for (int v : e[u]) {
Solve(v); h[u] = std::max(h[u], h[v]);
if (f[v] > 0) f[u] += f[v], g[u] = std::max(g[u], g[v]);
else g[u] = std::max(g[u], h[v]);
if (h[v] >= fir) sec = fir, fir = h[v];
else if (h[v] >= sec) sec = h[v];
}
f[u] += val[u], h[u] = std::max(h[u], f[u]);
ans = std::max(ans, f[u] + g[u]);
ans = std::max(ans, fir + sec);
}
int main() {
#ifndef DEBUG
freopen("chain.in", "r", stdin);
freopen("chain.out","w",stdout);
#endif
scanf("%d", & n);
lep(i, 1, n) {
scanf("%d%d", val + i, fa + i);
if (~fa[i]) e[fa[i]].push_back(i);
}
Solve(1);
printf("%lld\n", ans);
return 0;
}
CF1041F Ray in the tube
发现如果反射的距离 \(L\) 存在一个非 \(1\) 的奇因数,完全可以将 \(L\) 除以这个因数,经过的点一定会变多。
所以 \(L\) 一定是 \(2\) 的整次幂。
枚举每个 \(2\) 的次幂 \(2^k\) 。
然后考虑答案,发现我们只在乎 \(\bmod 2^k\) 的值,开个 \(map\) 统计即可。
点击查看
#include <bits/stdc++.h>
#define lep(i, a, b) for (int i = a; i <= b; ++i)
#define rep(i, a, b) for (int i = a; i >= b; --i)
const int _ = 2e5 + 7;
const int V = 50;
typedef long long ll;
int n, m, ans; ll a[_], b[_];
std::map<ll, int> S;
int main() {
scanf("%d%*lld", & n);
lep(i, 1, n) scanf("%lld", a + i);
scanf("%d%*lld", & m);
lep(i, 1, m) scanf("%lld", b + i);
rep(j, V, 0) { ll Sn = (1ll << j + 1) - 1, L = 1ll << j;
lep(i, 1, n) ++S[(a[i] + L) & Sn];
lep(i, 1, m) ++S[b[i] & Sn];
for (auto t : S) ans = std::max(ans, t.second);
S.clear();
}
lep(i, 1, n) ++S[a[i]];
lep(i, 1, m) ++S[b[i]];
for (auto t : S) ans = std::max(ans, t.second);
printf("%d\n", ans);
return 0;
}
AT_arc069_d [ARC069F] Flags
二分转化为判定性问题,每个点有两个位置可选,\(2-SAT\) 建模。
连边形如 \(i\rightarrow [l,i)\vee (i,r]\) ,线段树优化建图。
点击查看
#include <bits/stdc++.h>
#define lep(i, a, b) for (int i = a; i <= b; ++i)
#define rep(i, a, b) for (int i = a; i >= b; --i)
const int _ = 2e6 + 7;
typedef long long ll;
int n, tot, x[_], id[_];
int bel[_], stk[_], scc, top, idx, dfn[_], low[_]; bool vis[_];
int ls[_ << 2], rs[_ << 2], rt;
std::vector <int> e[_];
void add(int u, int v) { e[u].push_back(v); }
inline int trn(int u) { return u > n ? u - n : u + n; }
#define md ((s + t) >> 1)
void bd(int s, int t, int& p) { p = ++tot;
if (s == t) return add(p, trn(id[s]));
bd(s, md, ls[p]), bd(md + 1, t, rs[p]);
add(p, ls[p]), add(p, rs[p]);
}
void upd(int l, int r, int s, int t, int x, int p) {
if (r < s or t < l or l > r) return;
if (l <= s and t <= r) return add(x, p);
upd(l, r, s, md, x, ls[p]), upd(l, r, md + 1, t, x, rs[p]);
}
#undef md
void tarjan(int u) {
dfn[u] = low[u] = ++idx, stk[++top] = u, vis[u] = true;
for (int v : e[u]) {
if (!dfn[v]) tarjan(v), low[u] = std::min(low[u], low[v]);
else if (vis[v]) low[u] = std::min(low[u], dfn[v]);
}
if (low[u] == dfn[u]) { int x; ++scc;
while (stk[top] != u) x = stk[top--], vis[x] = false, bel[x] = scc;
x = stk[top--], vis[x] = false, bel[x] = scc;
}
}
bool ck(ll d) {
tot = 2 * n;
bd(1, 2 * n, rt);
int l = 1, r = 0;
lep(i, 1, 2 * n) {
while (l <= 2 * n and x[id[l]] < x[id[i]] + 1 - d) ++l;
while (r < 2 * n and x[id[r + 1]] <= x[id[i]] + d - 1) ++r;
if (l <= r and r <= 2 * n) {
upd(l, i - 1, 1, 2 * n, id[i], rt),
upd(i + 1, r, 1, 2 * n, id[i], rt);
}
}
lep(i, 1, tot) if (!dfn[i]) tarjan(i);
bool res = true;
lep(i, 1, n) if (bel[i] == bel[i + n]) { res = false; break; }
lep(i, 1, tot) e[i].clear(), dfn[i] = 0; scc = idx = top = 0;
return res;
}
int main() {
scanf("%d", & n);
lep(i, 1, n) scanf("%d%d", x + i, x + n + i),
id[i] = i, id[i + n] = i + n;
std::sort(id + 1, id + 1 + 2 * n, [](const int&a, const int&b)
{ return x[a] < x[b]; });
ll l = 0, r = 1e9;
while (l < r) { ll md = (l + r + 1) >> 1;
if (ck(md)) l = md;
else r = md - 1;
}
printf("%lld\n", l);
return 0;
}
CF1037H Security
假设没有 \(l,r\) 的限制怎么做,考虑按位贪心。
我们希望答案串比询问串字典序大又要尽可能小,所以肯定是尽可能地贴合原串。
比如 abbacb ,最理想的肯定是 abbacba ,如果不存在这个串呢,我们就回退,考虑接一个别的字符。
一直不存在就一直回退尝试,比如判断 abbacc 是否存在。
现在加上 \(l,r\) 的限制如何做呢?
考虑 \(Right\) 集合,如果长度为 \(len\) 的判断串 \(Right\) 集合与 \([l+len-1,r]\) 有交,即存在。
维护 \(Right\) 集合可用 \(parent\) 树上线段树合并解决,定位节点走转移边即可。
注意,每个节点的线段树都是有用的,所以合并时需要新建节点来保证每棵线段树的结构都没有被破坏。
点击查看代码
#include <bits/stdc++.h>
#define lep(i, a, b) for (int i = a; i <= b; ++i)
#define rep(i, a, b) for (int i = a; i >= b; --i)
const int _ = 4e5 + 7;
typedef long long ll;
int n, m, q, last = 1, idx = 1, lk[_], len[_]; char s[_], t[_];
int rt[_], sum[_ << 6], ls[_ << 6], rs[_ << 6], tot;
std::map<int, int> ch[_];
std::vector <int> e[_];
int Extend(int c) {
int np = ++idx, p = last; len[np] = len[p] + 1, last = idx;
while (p and !ch[p].count(c)) ch[p][c] = np, p = lk[p];
if (!p) lk[np] = 1;
else {
int q = ch[p][c];
if (len[q] == len[p] + 1) lk[np] = q;
else {
int nq = ++idx; ch[nq] = ch[q], len[nq] = len[p] + 1;
lk[nq] = lk[q], lk[q] = lk[np] = nq;
while (p and ch[p][c] == q) ch[p][c] = nq, p = lk[p];
}
}
return np;
}
#define md ((s + t) >> 1)
void mdy(int d, int s, int t, int& p) {
if (!p) p = ++tot; ++sum[p];
if (s == t) return;
d <= md ? mdy(d, s, md, ls[p]) : mdy(d, md + 1, t, rs[p]);
}
int mrg(int&x, int&y, int s, int t) {
if (!x or !y) return x | y;
if (s == t) return sum[x] += sum[y], x;
int p = ++tot;
ls[p] = mrg(ls[x], ls[y], s, md), rs[p] = mrg(rs[x], rs[y], md + 1, t);
sum[p] = sum[ls[p]] + sum[rs[p]];
return p;
}
bool qry(int l, int r, int s, int t, int p) {
if (r < s or t < l or !p) return false;
if (l <= s and t <= r) return sum[p] > 0;
if (qry(l, r, s, md, ls[p])) return true;
if (qry(l, r, md + 1, t, rs[p])) return true;
return false;
}
#undef md
void Dfs(int u) { for (int v : e[u]) Dfs(v), rt[u] = mrg(rt[u], rt[v], 1, n); }
int Solve(int p, int u, int l, int r, bool flag) {
if (!qry(l + p - 2, r, 1, n, rt[u])) return false;
if (flag) return p - 1;
if (p == m + 2) return m + 1;
int d = (p == m + 1) ? 0 : s[p] - 'a', res;
t[p] = 'a' + d;
if (res = Solve(p + 1, ch[u][d], l, r, false)) return res;
lep(i, d + 1, 25) {
t[p] = 'a' + i;
if (res = Solve(p + 1, ch[u][i], l, r, true)) return res;
}
return 0;
}
int main() {
scanf("%s", s + 1); n = std::strlen(s + 1);
lep(i, 1, n) mdy(i, 1, n, rt[Extend(s[i] - 'a')]);
lep(i, 2, idx) e[lk[i]].push_back(i); Dfs(1);
scanf("%d", & q); int l, r;
while (q--) {
scanf("%d%d%s", & l, & r, s + 1); m = std::strlen(s + 1);
int pos = Solve(1, 1, l, r, false);
if (pos) lep(i, 1, pos) putchar(t[i]);
else putchar('-'), putchar('1');
putchar('\n');
}
return 0;
}
时间仓促,如有错误欢迎指出,欢迎在评论区讨论,如对您有帮助还请点个推荐、关注支持一下

树形DP+因数/mod+2-SAT+SAM/贪心
浙公网安备 33010602011771号