2026.07.29 模拟赛 比赛总结
2026.07.29 模拟赛 比赛总结
| T1 | T2 | T3 | T4 | sum | rk |
|---|---|---|---|---|---|
| 100 AC | 24 WA | 24 RE | 8 WA | 156 | 18/78 |
打的最基础的部分分,莼菜。
T1 能量管理
观察发现不是很能 dp 状物,考虑贪心。
按 \(v_i\) 从大到小考虑每个活动,容易证明较大的 \(v_i\) 的 \(i\) 尽可能填满是一定不劣的。于是得到贪心思路。
随意维护即可。我采用的是 set 维护。时间复杂度 \(O(n \log n)\)。
LEWISAK 疑似有 \(O(n)\) 的分治做法。
点击查看代码
#include <bits/stdc++.h>
#define il inline
#define int long long
using namespace std;
bool Beg;
namespace Zctf1088 {
namespace IO {
const int bufsz = 1 << 20;
char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
il int read() {
int x = 0; char ch = getchar(); bool t = 0;
while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
return t ? -x : x;
}
char obuf[bufsz], *p3 = obuf, stk[50];
#define flush() (fwrite(obuf, 1, p3 - obuf, stdout), p3 = obuf)
#define putchar(ch) (p3 == obuf + bufsz && flush(), *p3++ = (ch))
il void write(int x, bool t = 0) {
int top = 0;
x < 0 ? putchar('-'), x = -x : 0;
do {stk[++top] = x % 10 | 48; x /= 10;} while(x);
while (top) putchar(stk[top--]);
t ? putchar(' ') : putchar('\n');
}
struct FL {
~FL() {flush();}
} fl;
}
using IO::read; using IO::write;
const int N = 1e4 + 10;
const int INF = 0x3f3f3f3f3f3f3f3f;
int E, R, n;
struct node {
int p, v;
il bool operator < (const node & c) const {
return v != c.v ? v > c.v : p < c.p;
}
} a[N];
struct nd {
int l, r, val1, val2;
il bool operator < (const nd c) const {
return l < c.l;
}
};
set<nd> st;
il int solve() {
E = read(), R = read(), n = read();
for (int i = 1; i <= n; i++)
a[i].p = i, a[i].v = read();
if (R >= E) {
int sum = 0;
for (int i = 1; i <= n; i++)
sum += E * a[i].v;
write(sum);
return 0;
}
sort(a + 1, a + 1 + n);
st.clear();
st.insert({1, n, E, 0});
int ans = 0;
for (int i = 1; i <= n; i++) {
int p = a[i].p;
nd tmp; tmp.l = p;
set<nd>::iterator it = st.upper_bound(tmp); it--;
nd c = *it;
st.erase(it);
int own = min(c.val1 + R * (p - c.l + 1), E);
int kep = max(c.val2 - R * (c.r - p + 1), 0ll);
ans += (own - kep) * a[i].v;
if (c.l < p) st.insert({c.l, p - 1, c.val1, own});
if (p < c.r) st.insert({p + 1, c.r, kep, c.val2});
}
write(ans);
return 0;
}
signed main() {
freopen("energy.in", "r", stdin);
freopen("energy.out", "w", stdout);
int qq = read();
while (qq--) solve();
return 0;
}}
bool End;
il void Usd() {cerr << "\nUse: " << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n";}
signed main() {
Zctf1088::main();
Usd();
return 0;
}
T2 比赛配对
正解是高超图论建模。这里给出一种比较亲民的做法。
考虑正难则反,不妨令每个 \((A_{2i-1},A_{2i})\) 的代价都为 \(2\),现在对于一些组减去一些代价。具体地:
- \((x,x) \rightarrow (x,x)\)。花费 \(0\) 的代价,即减去 \(2\)。
- \((x,x) \rightarrow(z,z)\)。花费 \(2\) 的代价,即减去 \(0\)。
- \((x,y)\rightarrow (x,x)\)。花费 \(1\) 的代价,即减去 \(1\)。
- \((x,y)\rightarrow (y,y)\)。花费 \(1\) 的代价,即减去 \(1\)。
- \((x,y)\rightarrow (z,z)\)。花费 \(2\) 的代价,即减去 \(0\)。
考虑对于每个 \(x\),所有原始的 \((x,x)\) 的组最多只能保留一个,且保留一个肯定是最优的。
于是只需要考虑形如 \((x,y)\) 的组。
考虑图论建模。考虑对于每个 \(x\) 建立一个虚点。考虑对于每个 \((x,y)\) 建一个点,并分别向 \(x\) 和 \(y\) 的虚点连边。于是得到一张二分图。不难发现,该图的最大匹配即为最大的可减去的代价。
稍微卡常即可通过此题。此处使用 dinic 跑二分图最大匹配。
时间复杂度 \(O(n \sqrt n)\)。
点击查看代码
#include <bits/stdc++.h>
#define il inline
using namespace std;
bool Beg;
namespace Zctf1088 {
namespace IO {
const int bufsz = 1 << 20;
char ibuf[bufsz], *p1 = ibuf, *p2 = ibuf;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, bufsz, stdin), p1 == p2) ? EOF : *p1++)
il int read() {
int x = 0; char ch = getchar(); bool t = 0;
while (ch < '0' || ch > '9') {t ^= ch == '-'; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
return t ? -x : x;
}
char obuf[bufsz], *p3 = obuf, stk[50];
#define flush() (fwrite(obuf, 1, p3 - obuf, stdout), p3 = obuf)
#define putchar(ch) (p3 == obuf + bufsz && flush(), *p3++ = (ch))
il void write(int x, bool t = 0) {
int top = 0;
x < 0 ? putchar('-'), x = -x : 0;
do {stk[++top] = x % 10 | 48; x /= 10;} while(x);
while (top) putchar(stk[top--]);
t ? putchar(' ') : putchar('\n');
}
il void wrt() {putchar('\n');}
struct FL {
~FL() {flush();}
} fl;
}
using IO::read; using IO::write; using IO::wrt;
const int INF = 0x3f3f3f3f;
const int N = 1e6 + 10, M = 2e6;
int n, qq, typ, a[N];
int t[N], p[N], st[N], tot;
struct Edge {
int nxt, to, w;
} edge[M];
int head[N], cur[N], etot = 1;
il void addEdge(int x, int y, int w) {
edge[++etot] = {head[x], y, w};
head[x] = etot;
}
il void addEdge1(int x, int y, int w) {
addEdge(x, y, w);
addEdge(y, x, 0);
}
int dis[N], S, T;
queue<int> q;
il bool bfs(int n) {
for (int i = 1; i <= n; i++) cur[i] = head[i], dis[i] = 0;
while (!q.empty()) q.pop();
dis[S] = 1; q.push(S);
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = head[x]; i; i = edge[i].nxt) {
int y = edge[i].to, w = edge[i].w;
if (w > 0 && !dis[y]) {
dis[y] = dis[x] + 1;
if (y == T) return true;
q.push(y);
}
}
}
return false;
}
il int dfs(int x, int flow) {
if (x == T) return flow;
int rest = flow;
for (int i = cur[x]; i && rest; i = edge[i].nxt) {
cur[x] = i;
int y = edge[i].to, w = edge[i].w;
if (w > 0 && dis[y] == dis[x] + 1) {
int k = dfs(y, min(rest, w));
if (k == 0) dis[y] = 0;
rest -= k;
edge[i].w -= k;
edge[i ^ 1].w += k;
}
}
return flow - rest;
}
il int dinic(int n, int s, int t) {
S = s, T = t;
int res = 0;
while (bfs(n)) res += dfs(S, INF);
return res;
}
int id[N], id1[N], id2[N], vis[N];
il int solve() {
for (int i = 1; i <= etot; i++) edge[i] = {0, 0, 0};
etot = 1, tot = 0;
n = read();
for (int i = 1; i <= n; i++) t[i] = p[i] = vis[i] = 0;
for (int i = 1; i <= n + n + 2; i++) head[i] = 0;
for (int i = 1; i <= 2 * n; i++) a[i] = read();
int ss = n + n + 1, tt = n + n + 2;
for (int i = 1; i <= 2 * n; i += 2) {
if (a[i] == a[i + 1]) t[a[i]]++, p[a[i]] = 1;
else {
addEdge1(a[i], n + (i + 1) / 2, 1); id1[i] = etot;
addEdge1(a[i + 1], n + (i + 1) / 2, 1); id2[i] = etot;
addEdge1(n + (i + 1) / 2, tt, 1);
}
}
int cnt = 0;
for (int i = 1; i <= n; i++) {
if (t[i] == 0) addEdge1(ss, i, 1), id[i] = etot;
else cnt++;
}
write(n * 2 - cnt * 2 - dinic(n + n + 2, ss, tt));
for (int i = 1; i <= n; i++) {
if (t[i] == 0 && edge[id[i]].w != 0) p[i] = 1;
if (!p[i]) st[++tot] = i;
}
for (int i = 1, j = 0; i <= 2 * n; i += 2) {
if (a[i] == a[i + 1]) {
if (!vis[a[i]]) write(a[i], 1), write(a[i + 1], 1), vis[a[i]] = 1;
else j++, write(st[j], 1), write(st[j], 1);
} else {
if (edge[id1[i]].w != 0) write(a[i], 1), write(a[i], 1);
else if (edge[id2[i]].w != 0) write(a[i + 1], 1), write(a[i + 1], 1);
else j++, write(st[j], 1), write(st[j], 1);
}
}
wrt();
return 0;
}
signed main() {
freopen("pair.in", "r", stdin);
freopen("pair.out", "w", stdout);
typ = read(), qq = read();
while (qq--) solve();
return 0;
}}
bool End;
il void Usd() {cerr << "\nUse: " << (&Beg - &End) / 1024.0 / 1024.0 << "MB " << (double)clock() * 1000.0 / CLOCKS_PER_SEC << "ms\n";}
signed main() {
Zctf1088::main();
Usd();
return 0;
}
T3 清仓甩卖
这是一道纯 counting。
累了。剩下的先咕着。

浙公网安备 33010602011771号