\(\mathscr{A}\sim\) 二分图排列

  定义一个数列 \(\{a_n\}\) 合法, 当且仅当无向图 \(G=(\{1..n\},\{(i,j)\mid i<j\land a_i>a_j\})\) 是二分图. 现给定 \(1\sim n\) 的排列 \(\{a_n\}\), 你可以将其中任意多个数取相反数得到 \(\{a_n'\}\), 求所有合法的 \(\{a_n'\}\) 中字典序最小的一个.

  多测, \(\sum n\le10^6\).


  Tags:「A.DP-序列 DP」「C.性质/结论」

  显然, 若 \(G\) 中存在大小为 \(k\) 的环, 则一定存在大小为 \(k-1\) 的环. 因而合法条件等价于不存在三元环, 也即是不存在 \(i<j<k\) 使得 \(a_i'>a_j'>a_k'\).

  先来看看怎么判断合法. 我们从左到右扫描 \(\{a_n'\}\), 扫描到 \(i\) 时, 维护出一个数对 \((u,d)\), 其中 \(u=\max_{j<i}\{a_j'\}\), \(d=\max_{j<i}\{a_j'\mid \exists k<j,~a_k'>a_j'\}\). 可见, \(d>a_i\) 意味着非法三元组的出现; 若 \(a_i>u\), 则 \(u\gets a_i\), 否则 \(d\gets a_i\). 如果扫描顺利完成, 这个序列就是合法的.

  现在, 我们想要构造字典序最小的 \(\{a_n'\}\), 求解过程中, 我们会尝试确定一段前缀 \(a_{1..i-1}'\), 并决策当前的数取 \(+a_i\) 或 \(-a_i\), 同时检查后缀能否在此基础上取出合法序列. 那么, 对应到合法判断方式, 我们会将扫描到 \(a_{1..i}'\) 时获得的 \((u,d)\) 作为后缀的输入数对, 判断这个输入数对能否在后缀中通过判断.

  接下来就是状态设计. 最原始的自然是 \(f(i,u,d)\) 表示从 \(i\) 开始, 输入数对为 \((u,d)\) 时, 后缀是否有合法解; 注意到 \(u,d\) 在对方固定时, 自己越大越劣, 所以可以优化成形如 \(f(i,u)\) 表示从 \(i\) 开始, 输入数对为 \((u,d_0)\), \(d_0\le f(i,u)\) 时才有合法解; 再进一步, 注意在完成 \(i\) 上的判断后, \((u,d)\) 必然有一者为 \(+a_i\) 或者 \(-a_i\), 所以状态可以简化为: \(f(i,0\sim3)\) 表示从 \(i\) 开始, 输入数对的 \(u/d\) 能够被替换为 \(+a_i/-a_i\) 时, \(d/u\) 的最大可行值. 暴力讨论 \(4^2\) 种转移对应的条件即可 \(\mathcal O(n)\) 转移.

/*+Rainybunny+*/

#include <bits/stdc++.h>

#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i) inline char fgc() {
static char buf[1 << 17], *p = buf, *q = buf;
return p == q && (q = buf + fread(p = buf, 1, 1 << 17, stdin), p == q) ?
EOF : *p++;
} template <typename Tp = int>
inline Tp rint() {
Tp x = 0, s = fgc(), f = 1;
for (; s < '0' || '9' < s; s = fgc()) f = s == '-' ? -f : f;
for (; '0' <= s && s <= '9'; s = fgc()) x = x * 10 + (s ^ '0');
return x * f;
} template <typename Tp>
inline void wint(Tp x) {
if (x < 0) putchar('-'), x = -x;
if (9 < x) wint(x / 10);
putchar(x % 10 ^ '0');
} template <typename Tp>
inline void chkmin(Tp& u, const Tp& v) { v < u && (u = v, 0); }
template <typename Tp>
inline void chkmax(Tp& u, const Tp& v) { u < v && (u = v, 0); }
template <typename Tp>
inline Tp imin(const Tp& u, const Tp& v) { return u < v ? u : v; }
template <typename Tp>
inline Tp imax(const Tp& u, const Tp& v) { return u < v ? v : u; } const int MAXN = 1e6, IINF = 0x3f3f3f3f;
int n, a[MAXN + 5]; /**
* 0: max available U when D=-a[i]
* 1: max available D when U=-a[i]
* 2: max available U when D=a[i]
* 3: max available D when U=a[i]
*/
int f[MAXN + 5][4]; #define chkif(a, b, c) void((c) && (chkmax(a, b), 0)) int main() {
for (int T = rint(); T--;) {
n = rint();
rep (i, 1, n) a[i] = rint(); f[n][0] = f[n][2] = IINF, f[n][1] = -a[n], f[n][3] = a[n];
per (i, n - 1, 1) {
rep (j, 0, 3) f[i][j] = -IINF; chkif(f[i][0], f[i + 1][0], -a[i] < -a[i + 1]);
chkif(f[i][0], -a[i + 1], -a[i] <= f[i + 1][1]);
chkif(f[i][0], f[i + 1][2], -a[i] < a[i + 1]);
chkif(f[i][0], a[i + 1], -a[i] <= f[i + 1][3]); chkif(f[i][1], -a[i + 1], -a[i] <= f[i + 1][0]);
chkif(f[i][1], f[i + 1][1], -a[i] < -a[i + 1]);
chkif(f[i][1], a[i + 1], -a[i] <= f[i + 1][2]);
chkif(f[i][1], f[i + 1][3], -a[i] < a[i + 1]); chkif(f[i][2], f[i + 1][0], a[i] < -a[i + 1]);
chkif(f[i][2], -a[i + 1], a[i] <= f[i + 1][1]);
chkif(f[i][2], f[i + 1][2], a[i] < a[i + 1]);
chkif(f[i][2], a[i + 1], a[i] <= f[i + 1][3]); chkif(f[i][3], -a[i + 1], a[i] <= f[i + 1][0]);
chkif(f[i][3], f[i + 1][1], a[i] < -a[i + 1]);
chkif(f[i][3], a[i + 1], a[i] <= f[i + 1][2]);
chkif(f[i][3], f[i + 1][3], a[i] < a[i + 1]); chkmin(f[i][1], -a[i]), chkmin(f[i][3], a[i]);
if (f[i][0] < -a[i]) f[i][0] = -IINF;
if (f[i][2] < a[i]) f[i][2] = -IINF; // printf("%d: %d %d %d %d\n",
// i, f[i][0], f[i][1], f[i][2], f[i][3]);
} bool sol = false;
rep (i, 0, 3) sol |= f[1][i] != -IINF;
if (!sol) { puts("NO"); continue; } puts("YES");
int u = -IINF, d = -IINF;
rep (i, 1, n) {
int x;
if ((d <= -a[i] && u <= f[i][0])
|| (u <= -a[i] && d <= f[i][1])) {
x = -a[i];
} else {
x = a[i];
}
if (x > u) u = x;
else d = x;
wint(x), putchar(' ');
}
putchar('\n');
}
return 0;
}

\(\mathscr{B}\sim\) 最短路问题 V3

  给定含有 \(n\) 个点 \(m\) 条边的带权连通无向图, \(q\) 次询问两点最短路.

  \(n,q\le10^5\), \(m\le n+20\).


  Tag:「水题无 tag」

  拿树边之外的 \(40\) 个点暴力 Dijkstra. 复杂度 \(40\times\mathcal O(n\log n)\).

/*+Rainybunny+*/

#include <bits/stdc++.h>

#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i) typedef long long LL;
typedef std::pair<LL, int> PLI;
#define fi first
#define se second inline char fgc() {
static char buf[1 << 17], *p = buf, *q = buf;
return p == q && (q = buf + fread(p = buf, 1, 1 << 17, stdin), p == q) ?
EOF : *p++;
} template <typename Tp = int>
inline Tp rint() {
Tp x = 0, s = fgc(), f = 1;
for (; s < '0' || '9' < s; s = fgc()) f = s == '-' ? -f : f;
for (; '0' <= s && s <= '9'; s = fgc()) x = x * 10 + (s ^ '0');
return x * f;
} template <typename Tp>
inline void wint(Tp x) {
if (x < 0) putchar('-'), x = -x;
if (9 < x) wint(x / 10);
putchar(x % 10 ^ '0');
} const int MAXN = 1e5, MAXLG = 16;
const LL LINF = 1ll << 60;
int n, m, ecnt = 1, head[MAXN + 5];
int stc, dep[MAXN + 5], stn[MAXN + 5], st[MAXLG + 3][MAXN * 2 + 5];
bool ontr[MAXN + 25];
LL dow[MAXN + 5], dis[45][MAXN + 5];
struct Edge { int to, cst, nxt; } graph[(MAXN + 20) * 2 + 5];
std::vector<int> key; inline void link(const int u, const int v, const int w) {
graph[++ecnt] = { v, w, head[u] }, head[u] = ecnt;
graph[++ecnt] = { u, w, head[v] }, head[v] = ecnt;
} struct DSU {
int fa[MAXN + 5];
inline void init() { rep (i, 1, n) fa[i] = i; }
inline int find(const int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
inline bool unite(int x, int y) {
if ((x = find(x)) == (y = find(y))) return false;
return fa[x] = y, true;
}
} dsu; inline void init(const int u, const int fa) {
st[0][stn[u] = ++stc] = u, dep[u] = dep[fa] + 1;
for (int i = head[u], v; i; i = graph[i].nxt) {
if (ontr[i >> 1] && (v = graph[i].to) != fa) {
dow[v] = dow[u] + graph[i].cst, init(v, u), st[0][++stc] = u;
}
}
} inline void initST() {
rep (i, 1, 31 - __builtin_clz(stc)) {
rep (j, 1, stc - (1 << i) + 1) {
st[i][j] = dep[st[i - 1][j]] < dep[st[i - 1][j + (1 << i >> 1)]]
? st[i - 1][j] : st[i - 1][j + (1 << i >> 1)];
}
}
} inline int lca(int u, int v) {
if ((u = stn[u]) > (v = stn[v])) std::swap(u, v);
int k = 31 - __builtin_clz(v - u + 1);
return dep[st[k][u]] < dep[st[k][v - (1 << k) + 1]] ?
st[k][u] : st[k][v - (1 << k) + 1];
} inline LL dist(const int u, const int v) {
return dow[u] + dow[v] - 2 * dow[lca(u, v)];
} inline void dijkstra(const int s, LL* ds) {
std::priority_queue<PLI, std::vector<PLI>, std::greater<PLI>> heap;
rep (i, 1, n) ds[i] = LINF;
heap.emplace(ds[s] = 0, s);
while (heap.size()) {
PLI p(heap.top()); heap.pop();
if (p.fi != ds[p.se]) continue;
for (int i = head[p.se], v; i; i = graph[i].nxt) {
LL d = p.fi + graph[i].cst;
if (ds[v = graph[i].to] > d) heap.emplace(ds[v] = d, v);
}
}
} int main() {
n = rint(), m = rint(), dsu.init();
rep (i, 1, m) {
int u = rint(), v = rint(), w = rint();
link(u, v, w);
if (!(ontr[i] = dsu.unite(u, v))) key.push_back(u), key.push_back(v);
} init(1, 0), initST();
std::sort(key.begin(), key.end());
key.resize(std::unique(key.begin(), key.end()) - key.begin());
rep (i, 0, int(key.size()) - 1) dijkstra(key[i], dis[i]); for (int q = rint(); q--;) {
int u = rint(), v = rint();
LL ans = dist(u, v);
rep (i, 0, int(key.size()) - 1) {
ans = std::min(ans, dis[i][u] + dis[i][v]);
}
wint(ans), putchar('\n');
}
return 0;
}

\(\mathscr{C}\sim\) 捡石子游戏

  给定一棵含有 \(n\) 个点的树, 点 \(u\) 有点权 \(w_u\). Alice 和 Bob 博弈, Alice 选择一个起点 \(s\), 此后 Alice 和 Bob 轮流操作:

  1. 令 \(w_s\gets w_s-1\);

  2. 取一个 \(s\) 的邻接点 \(t\), 令 \(s\gets t\). 若此时 \(w_t=0\), 则当前操作者获胜.

  求出使得 Alice 必胜的所有起点或声明无解.

  \(n\le3\times10^3\).


  Tag:「C.性质/结论」

  注意一个必败情况: Alice 陷入了一个 "山谷" \(u\), \(\forall (u,v)\in E,~w_v\ge w_u\). 那么不管 Alice 怎么挣扎, Bob 只需要在自己的回合将 \(s\) 移回 \(u\), Alice 就不可能先于 Bob 取胜.

  进一步讨论发现, 双方都不可能将 \(s\) 移动向 \(t\), 使得 \(w_s\le w_t\), 因为这样的移动肯定会被对手反向移动消除, 而 \(w_s\) 的减小更可能让自己陷入 "山谷". 换句话说, 从 \(s\) 开始的移动必然走向使得 \(w_t<w_s\) 的 \(t\).

  这里就能直接 DP 了. 按点权升序枚举点, 检查四周能走到的点的胜负态情况. 除排序外可以做到 \(\mathcal O(n)\).

/*+Rainybunny+*/

#include <bits/stdc++.h>

#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i) const int MAXN = 3e3;
int n, val[MAXN + 5], ecnt, head[MAXN + 5], ord[MAXN + 5], sg[MAXN + 5];
struct Edge { int to, nxt; } graph[MAXN * 2 + 5]; inline void link(const int u, const int v) {
graph[++ecnt] = { v, head[u] }, head[u] = ecnt;
graph[++ecnt] = { u, head[v] }, head[v] = ecnt;
} int main() {
scanf("%d", &n);
rep (i, 1, n) scanf("%d", &val[i]);
rep (i, 2, n) { int u, v; scanf("%d %d", &u, &v), link(u ,v); } std::iota(ord + 1, ord + n + 1, 1);
std::sort(ord + 1, ord + n + 1,
[](const int u, const int v) { return val[u] < val[v]; }
); rep (i, 1, n) {
int u = ord[i];
static std::bitset<MAXN + 5> vis; vis.set();
for (int j = head[u], v; j; j = graph[j].nxt) {
if (val[v = graph[j].to] < val[u]) {
vis.reset(sg[v]);
}
}
sg[u] = vis._Find_first();
} bool exi = false;
rep (i, 1, n) if (sg[i]) {
if (exi) putchar(' ');
exi = true, printf("%d", i);
}
puts(exi ? "" : "-1");
return 0;
}

\(\mathscr{D}\sim\) 凹函数 *

  求严格单增凹函数 \(f:[0,n]\to[0,m]\) 最多过多少个整点.

  询问次数 \(q\le10^4\), \(n,m\le3\times10^3\).


  Tags:「A.DP-杂项」「B.Tricks」

  稍作简化, 我们要求最大的一组 \(\{(x,y)_k\}\) 使得 \(x_i\perp y_i\), \(\sum x\le n,\sum y\le m\).

  直接 DP 是 \(\mathcal O(n^4)\) 左右的, 注意到凸包大小是 \(\mathcal O(n^{2/3})\) 的, 因此可以记 \(f(i,j)\) 表示 \(\sum x=i\), 向量组数为 \(j\) 时 \(\sum y\) 的最小值. 到此可以做到 \(\mathcal O(n^{3+2/3})\).

  考虑从最优性上继续剪枝. 注意选出 \((x,y)\) 时, 一定已经选掉了所有合法的 \((x',y')<(x,y)\). 进而可以用 \(\sum x',\sum y'\) 进一步限制 \((x,y)\) 的可选性. 可以证明, 此时被用来更新背包的向量只有 \(\mathcal O(n^{2/3})\) 个, 因此最终复杂度为 \(\mathcal O(n^{7/3})\).

Proof

  设总向量数量为 $C$, 那么
$$
\begin{aligned}
C &\le \sum_{x=1}^n\sum_{y=1}^n[x\perp y]\left[\sum_{x'=1}^x\sum_{y'=1}^y[x'\perp y'](x'+y')\le2n\right]\\
&\le \sum_{x=1}^n\sum_{y=1}^n\left[\sum_{x'=1}^x\sum_{y'=1}^y[x'\perp y'](x'+y')\le2n\right]\\
&\sim \sum_{x=1}^n\sum_{y=1}^n\left[\sum_{d}\mu(d)\cdot y/d\cdot d\sum_{x'=1}^{x/d}x'\le n\right]\\
&\sim \sum_{x=1}^{n}\sum_{y=1}^n\left[y\sum_{d}\mu(d)(x/d)^2\le n\right]\\
&\sim \sum_{x=1}^n\left[\sum_{y=1}^nyx^2\cdot\frac{\pi^2}{6}\le n\right]\\
&= \mathcal O(n^{2/3}).
\end{aligned}
$$

/*+Rainybunny+*/

#include <bits/stdc++.h>

#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i) template <typename Tp>
inline void chkmin(Tp& u, const Tp& v) { v < u && (u = v, 0); }
template <typename Tp>
inline void chkmax(Tp& u, const Tp& v) { u < v && (u = v, 0); }
template <typename Tp>
inline Tp imin(const Tp& u, const Tp& v) { return u < v ? u : v; }
template <typename Tp>
inline Tp imax(const Tp& u, const Tp& v) { return u < v ? v : u; } const int N = 3e3, IINF = 0x3f3f3f3f;
std::vector<int> ans[N + 5]; inline void update(const int x, const int y) {
// printf("%d %d\n", x, y);
per (i, N, x) {
rep (j, 0, int(ans[i - x].size()) - 1) {
if (ans[i - x][j] + y > N) break;
if (ans[i].size() == j + 1) ans[i].push_back(IINF);
chkmin(ans[i][j + 1], ans[i - x][j] + y);
}
}
} inline void solve() {
static int sum[N + 5][2];
rep (i, 0, N) ans[i].push_back(0);
rep (i, 1, N) {
int s[2] = {};
rep (j, 1, N) {
s[0] += sum[j][0], s[1] += sum[j][1];
if (s[0] > N || s[1] > N) break;
if (std::__gcd(i, j) == 1) {
s[0] += i, s[1] += j, sum[j][0] += i, sum[j][1] += j;
if (s[0] > N || s[1] > N) break;
update(i, j);
}
}
}
} int main() {
solve(); int q; scanf("%d", &q);
while (q--) {
int n, m; scanf("%d %d", &n, &m);
printf("%d\n", int(std::upper_bound(ans[n].begin(),
ans[n].end(), m) - ans[n].begin()));
}
return 0;
}

Solution Set -「NOIP Simu.」20221003的更多相关文章

  1. 「NOIP 2017」列队

    题目大意:给定一个 $n times m$ 的方阵,初始时第 $i$ 行第 $j$ 列的人的编号为 $(i-1) times m + j$,$q$ 次给出 $x,y$,让第 $x$ 行 $y$ 列的人 ...

  2. 「NOIP 2020」微信步数(计数)

    「NOIP 2020」微信步数(Luogu P7116) 题意: 有一个 \(k\) 维场地,第 \(i\) 维宽为 \(w_i\),即第 \(i\) 维的合法坐标为 \(1, 2, \cdots, ...

  3. Diary / Solution Set -「WC 2022」线上冬眠做噩梦

      大概只有比较有意思又不过分超出能力范围的题叭.   可是兔子的"能力范围" \(=\varnothing\) qwq. 「CF 1267G」Game Relics   任意一个 ...

  4. Solution Set -「ARC 107」

    「ARC 107A」Simple Math   Link.   答案为: \[\frac{a(a+1)\cdot b(b+1)\cdot c(c+1)}{8} \] 「ARC 107B」Quadrup ...

  5. 「NOIP 2013」 货车运输

    题目链接 戳我 \(Solution\) 这一道题直接用\(kruskal\)重构树就好了,这里就不详细解释\(kruskal\)重构树了,如果不会直接去网上搜就好了.接下来讲讲详细过程. 首先构建\ ...

  6. Solution Set -「ABC 217」

      大家好屑兔子又来啦! [A - Lexicographic Order]   说个笑话,\(\color{black}{\text{W}}\color{red}{\text{alkingDead} ...

  7. Note -「动态 DP」学习笔记

    目录 「CF 750E」New Year and Old Subsequence 「洛谷 P4719」「模板」"动态 DP" & 动态树分治 「洛谷 P6021」洪水 「S ...

  8. Note -「Lagrange 插值」学习笔记

    目录 问题引入 思考 Lagrange 插值法 插值过程 代码实现 实际应用 「洛谷 P4781」「模板」拉格朗日插值 「洛谷 P4463」calc 题意简述 数据规模 Solution Step 1 ...

  9. Solution -「ARC 104E」Random LIS

    \(\mathcal{Description}\)   Link.   给定整数序列 \(\{a_n\}\),对于整数序列 \(\{b_n\}\),\(b_i\) 在 \([1,a_i]\) 中等概率 ...

  10. LOJ #2026「JLOI / SHOI2016」成绩比较

    很好的锻炼推柿子能力的题目 LOJ #2026 题意 有$n$个人$ m$门学科,第$ i$门的分数为不大于$U_i$的一个正整数 定义A「打爆」B当且仅当A的每门学科的分数都不低于B的该门学科的分数 ...

随机推荐

  1. css动画效果(边框流光闪烁阴影效果)

    1.整体效果 https://mmbiz.qpic.cn/sz_mmbiz_gif/EGZdlrTDJa7odDQYuaatklJUMc5anU10PWLAt14rNnNUD6oHJG9U63fc0y ...

  2. DP 详解

    DP 概述 DP(Dynamic programming,全称动态规划),是一种基于分治,将原问题分解为简单子问题求解复杂问题的方法. 动态规划的耗时往往远少于朴素(爆搜)解法. 动态规划 and 递 ...

  3. Uniswap V2 核心 合约代码

    Uniswap V2 核心 UniswapV2Factory UniswapV2Pair UniswapV2ERC20 IUniswapV2Router02 1. UniswapV2Factory 合 ...

  4. Ros环境创建相关!超级简单!!超级详细!!

    1.创建工作空间workspace 其中catkin_ws后面的ws是work_space的简写,指代工作空间 <catkin_ws是你的工作空间的名字,随便取> mkdir -p ~/c ...

  5. Nuxt.js 应用中的 webpack:compile 事件钩子

    title: Nuxt.js 应用中的 webpack:compile 事件钩子 date: 2024/11/22 updated: 2024/11/22 author: cmdragon excer ...

  6. Dell 塔式t440 安装centos (Non-Raid 成功版)

    前情提要 这篇文章是2021年我发布在csdn上,最近搬到博客园了,我把这篇文章重新整理发布下.有的图带有水印 csdn@at_the_Moment正常的,这就是我在csdn的账号. 提前声明一下这是 ...

  7. 根据Xml节点名获取Xpath

    我们经常使用Xpath去获取Xml中某个节点的值,但是有时候我们需要反过来,根据Xml的节点名来获取对应的Xpath. 找了一下,几乎所有的Xml库都没有提供类似的功能,这里我们就简单说一说这玩意咋实 ...

  8. ThreeJs-04详解材质与纹理

    一.matcap材质 这个材质不会受到光照影响,但是如果图片本身有光就可以一直渲染这个图片本来的样子,用来将一个图片纹理渲染到物体上的材质 代码实现 加载模型后,开启纹理渲染,并把它的材质变为这个材质 ...

  9. 前端17号学习(html完结)

    一.路径 1.目录文件夹和跟目录 实际工作中需要创建一个文件夹来管理他们. 目录文件夹,就是普通文件夹,里面存放页面相关素材,如html文件.图片等. 根目录,打开目录文件夹的第一层就是根目录. 2. ...

  10. 给我2分钟,保证教会你在Vue3中实现一个定高的虚拟列表

    前言 虚拟列表对于大部分一线开发同学来说是一点都不陌生的东西了,有的同学是直接使用第三方组件.但是面试时如果你简历上面写了虚拟列表,却给面试官说是通过三方组件实现的,此时空气可能都凝固了.所以这篇文章 ...