第八届图灵杯趣味网络国际邀请赛 - 初级组/中级组部分题解。
初级组T1机器人每次跳正整数距离若一共跳了 $k$ 次距离分别为 $x_1,x_2,\ldots x_k$则 $x_1 x_2\cdotsx_k n$。消耗的总电量为$\sum_{i 1}^{k}|a-x_i|$。对于固定的 $k$最小消耗就是 $|n - ka|$。因为理想情况下每次都跳 $a$总距离为 $ka$。为了把总距离调整成 $n$至少需要修改 $|n - ka|$ 的距离而这个下界一定能够达到。所以问题变成选择一个正整数 $k$使 $|n - ka|$ 最小也就是寻找距离 $n$ 最近的 $a$ 的正整数倍。分类讨论。当 $n a$ 时 不能选择 $k 0$只能至少跳一次。直接跳 $n$$\text{ans}a - n$。当 $n\ge a$ 时令$rn\bmod a$。有两种方法跳 ($\left\lfloor\dfrac na\right\rfloor$) 次把其中一次增加 $r$消耗 $r$。跳 ($\left\lceil\dfrac na \right\rceil$) 次把其中一次减少 $a - r$消耗 $a - r$。因此 $\text{ans}\min(r, a-r)$。代码#includebits/stdc.h using namespace std; typedef long long ll; int main() { int T; cin T; while (T--) { ll n, a; cin n a; if (n a) cout a - n; else { ll r n % a; cout min(r, a - r); } cout \n; } }时间复杂度$O(T)$。T2设相邻两次到达的节点距离为$$d_i\operatorname{dist}(p_i,p_{i1})。$$题目的条件就是$d_1d_2\cdotsd_{k-1}。$也就是说每次移动的距离必须严格递增。设树的直径长度为 $D$。树上任意两点之间的距离都不超过 $D$而每次移动距离都是正整数因此严格递增的距离序列最多是$$1,2,\ldots,D。$$所以最多有 $D$ 次移动即$$k\le D1。$$取树上的一条直径依次记直径上的节点为$$v_0,v_1,\ldots,v_D。$$因为它们在同一条路径上所以$$\operatorname{dist}(v_x,v_y)|x-y|。$$接下来只要排列下标 $0,1,\ldots,D$使相邻下标差依次为 $1,2,\ldots,D$。先考虑排列$$0,D,1,D-1,2,D-2,\ldots$$它的相邻差依次为$$D,D-1,\ldots,1。$$将这个排列倒过来相邻差就变成$$1,2,\ldots,D。$$因此一定能选出直径上的全部 $D1$ 个节点达到上界。# 如何求直径在树上进行两次 BFS1. 从节点 $1$ 出发找到最远点 $s$。2. 从 $s$ 出发找到最远点 $t$同时记录每个节点的父亲。3. 从 $t$ 沿父亲一直回到 $s$得到一条直径。# 代码#includebits/stdc.h using namespace std; typedef long long ll; const int N 2e6 5; int h[N], to[N 1], nx[N 1], cnt; int q[N], d[N], fa[N], p[N]; void add(int u, int v) { to[cnt] v, nx[cnt] h[u], h[u] cnt; } int bfs(int s, int n) { memset(d, -1, (n 1)* sizeof (int)); int l 0, r 0, t s; q[r] s; d[s] 0; fa[s] 0; while (l r) { int u q[l]; if (d[u] d[t]) t u; for (int i h[u]; i; i nx[i]) { int v to[i]; if (d[v] ! -1) continue; d[v] d[u] 1; fa[v] u; q[r] v; } } return t; } int main() { int n; cin n; for (int i 1, u, v; i n; i) { cin u v; add(u, v), add(v, u); } int s bfs(1, n), t bfs(s, n); int m 0; for (int x t;; x fa[x]) { p[m] x; if (x s) break; } cout m endl; int mm m - 1; for (int i mm; i 0; i--) { int x (i % 2) ? mm - (i 1) : (i 1); cout p[x] ; } }时间复杂度$O(n)$T3/T1(中级组 :设某个人属于小组 $g$。由于每个小组的座位构成连续区间所以其他小组相对于 $g$ 只有两种- 整个小组位于 $g$ 的左边。- 整个小组位于 $g$ 的右边。当这个人进入时设- $L$ 表示已经进入且小组位于 $g$ 左边的人数。- $R$ 表示已经进入且小组位于 $g$ 右边的人数。的下界无论给这个人安排小组内的哪个座位- 左边至少有 $L$ 个已入座的人。- 右边至少有 $R$ 个已入座的人。所以这个人至少需要跨过 $\min(L,R)$ 个已经有人坐下的座位。如果 $L\le R$就让这个人的座位位于所有已经入座的同组成员左边。此时他的左边没有已经入座的同组成员因此从左边进入只会跨过 $L$ 个座位。如果 $LR$就让这个人的座位位于所有已经入座的同组成员右边。此时从右边进入只会跨过 $R$ 个座位。因此每个人的最优代价都可以独立达到答案就是 $\sum\min(L, R)$。对于每个人记录一种选择- 若 $L\le R$记为向同组已有成员的左边插入。- 否则记为向右边插入。对于一个小组最终的座位顺序为1. 所有向左插入的人按照进入顺序倒序排列。2. 所有向右插入的人按照进入顺序正序排列。例如某组成员依次选择右 右 左 左最终的相对顺序为第 4 人 第 3 人 第 1 人 第 2 人因此只需统计每组有多少人向左插入就能直接算出每个人的座位。用树状数组维护各个小组已经进入的人数。把每个小组的区间左端点作为它在树状数组中的位置。设小组 $g$ 的区间左端点为 $s_g$$L\operatorname{sum}(s_g-1)$。而$Ri-1-\operatorname{sum}(s_g)$。其中 $i-1$ 是当前已经进入的总人数$\operatorname{sum}(s_g)$ 包括左侧小组与当前小组已经进入的人。时间复杂度为$O(n\log n)$。# 代码#include bits/stdc.h using namespace std; typedef long long ll; const int N 1e6 5; int n, l[N], a[N], c[N], tr[N]; unsigned char d[N]; struct IO { static const int S 1 20; int p 0, q 0; char b[S]; char gc() { if (p q)q fread(b, 1, S, stdin), p 0; return p q ? 0 : b[p]; } int rd() { int x 0; char ch gc(); while (ch 0 || ch 9)ch gc(); while (ch 0 ch 9)x x * 10 ch - 0, ch gc(); return x; } } io; struct OUT { static const int S 1 20; int p 0; char b[S]; ~OUT() { fl(); } void fl() { fwrite(b, 1, p, stdout); p 0; } void pc(char ch) { if (p S)fl(); b[p] ch; } void wt(ll x) { if (x 10) wt(x / 10); pc(x % 10 0); } } out; int sum(int x) { int s 0; for (; x; x - x -x) s tr[x]; return s; } void add(int x) { for (; x n; x x -x) tr[x]; } int main() { n io.rd(); for (int i 1, x; i n; i) { x io.rd(); if (!l[x])l[x] i; } ll ans 0; for (int i 1, x, L, R; i n; i) { x io.rd(); a[i] x; L sum(l[x] - 1); R i - 1 - sum(l[x]); if (L R) d[i] 0, c[x], ans L; else d[i] 1, ans R; add(l[x]); } for (int i 1; i n; i) if (l[i]) c[i] l[i], l[i] c[i] - 1; out.wt(ans); out.pc(\n); for (int i 1, x; i n; i) { x a[i]; if (!d[i]) a[i] l[x]--; else a[i] c[x]; out.wt(a[i]); out.pc( ); } return 0; }T4/T2(中级组需要利用一个性质**能走至少 $k$ 个钉子的起点一定构成一个前缀和一个后缀。 中间已经失效的点以后永远不会重新有效因此后续不再扫描它们。同时去掉复制数组的第三遍循环直接交换两个 DP 数组。设当前要求还能碰撞 $k$ 个钉子点 $j$ 对应的最小限制为 $f_j$。点 $i$ 可以向左走当且仅当存在 $ji$ 满足$a_j f_j\le a_i$。只要某个 $i$ 满足那么所有更靠右的点也满足所以向左转移可行的点构成一个后缀。同理向右转移可行的点构成一个前缀。因此每一层的有效点都是$[1,l]\cup[r, n]$。并且一条长度为 $k 1$ 的路径删去最后一个点后就是长度为 $k$ 的路径所以有效集合只会不断缩小。# 代码#includebits/stdc.h using namespace std; #define ll long long const int N 1e6 5; const ll I 4e18; ll a[N], f0[N], f1[N], v[N]; ll *f f0, *g f1; int s[N], n; unsigned char ans[N]; struct IO { static const int S 1 20; int p 0, l 0; char b[S]; char gc() { if (p l)l fread(b, 1, S, stdin), p 0; return p l ? 0 : b[p]; } ll rd() { ll x 0; char c gc(); while (c 0 || c 9)c gc(); while (c 0 c 9)x x * 10 c - 0, c gc(); return x; } } io; struct OUT { static const int S 1 20; int p 0; char b[S]; ~OUT() { fl(); } void fl() { fwrite(b, 1, p, stdout); p 0; } void pc(char c) { if (p S)fl(); b[p] c; } void wt(int x) { if (x 10)wt(x / 10); pc(x % 10 0); } } out; int main() { n io.rd(); for (int i 1; i n; i)a[i] io.rd(); if (n 1) { out.wt(1); out.pc(\n); return 0; } ll d I; for (int i 1; i n; i)d min(d, a[i 1] - a[i]); for (int i 1; i n; i) { ll x I; if (i 1)x min(x, a[i] - a[i - 1]); if (i n)x min(x, a[i 1] - a[i]); f[i] x 1; ans[i] 2; } ll z (a[n] - a[1]) / d; int lim 2 63 - __builtin_clzll(z); int l n, r n 1; for (int k 3; k lim; k) { int t 0, q 0, pre 0; for (int o 0; o 2; o) { int L o ? r : 1, R o ? n : l; for (int i L; i R; i) { if (pre) { ll x a[pre] f[pre]; while (t v[t] x)t--; if (q t)q t; s[t] pre; v[t] x; } while (q t v[q 1] a[i])q; g[i] q ? (a[i] - a[s[q]]) 1 : I; pre i; } } t q pre 0; int nl 0, nr n 1; bool suf 1, ok 0; for (int o 0; o 2; o) { int L o ? l : n, R o ? 1 : r; if (o l 1 r)suf 0; for (int i L; i R; i--) { if (pre) { ll x a[pre] - f[pre]; while (t v[t] x)t--; if (q t)q t; s[t] pre; v[t] x; } while (q t v[q 1] a[i])q; if (q) { ll x (a[s[q]] - a[i]) 1; if (x g[i])g[i] x; } if (g[i] I) { ans[i] k; ok 1; if (suf)nr i; else if (!nl)nl i; } else suf 0; pre i; } } if (!ok)break; swap(f, g); if (nr 1)l n, r n 1; else l nl, r nr; } for (int i 1; i n; i) { out.wt(ans[i]); out.pc( ); } return 0; }时间复杂度为 $O\left(\sum_k|S_k|\right)$其中 $S_k$ 是能够碰撞至少 $k$ 个钉子的起点集合。T3中级组## 思路先考虑一次释放复仇之魂能做什么。若当前要击杀第 $i$ 个怪物设它的位置为 $q_i$其中 $q$ 为 $p$ 的逆排列。向左释放或向右释放本质上要求后续被杀怪物的位置单调。因此可以预处理最长单调段求出从每个怪物开始释放最多能连续击杀到哪里。于是每次释放对应一个区间 $[l,r]$ 表示从第 $l$ 个怪物开始释放可以一次杀到第 $r$ 个怪物。---如果全部使用骨针攻击需要攻击 $n$ 次。对于一个区间 $[l,r]$释放复仇之魂可以减少$$r-l$$ 次攻击。但是释放一次需要消耗 $1$ 点灵魂而少打 $x$ 次骨针会使之后可用的灵魂少 $x1$ 点所以一个收益为 $x$ 的方案实际占用 $x2$点容量。因此问题转化为 有若干个任务每个任务有截止时间 $r$。选择若干任务使总收益最大并满足所有前缀中的总占用容量不超过截止时间。---按照右端点从小到大处理任务。维护当前选择的任务- 总收益。- 总占用容量。- 一个小根堆存当前收益最小的任务。当加入一个新区间导致容量超过限制时- 如果删除收益最小的任务可以解决超限就删除它。- 如果只需要减少部分容量就缩短该任务的收益。由于每次删除收益最小的任务一定最优因此可以通过贪心得到最大收益。最后答案为$$n-\text{最大减少的攻击次数}$$。总时间复杂度为 $O(n\log n)$#includebits/stdc.h using namespace std; typedef long long ll; const int N 1e6 5; int n, p[N], q[N], a[N], b[N], u[N], d[N], f[N]; int m, hs, h[N], ps[N], y[N]; bool z[N], t[N]; int ky(int x) { return y[x] - (x m t[x 1] z[x 1]); } bool cp(int x, int v) { int a ky(x), b ky(v); return a b || (a b x v); } void sw(int x, int v) { swap(h[x], h[v]); ps[h[x]] x; ps[h[v]] v; } void up(int x) { while (x 1 cp(h[x], h[x 1])) sw(x, x 1), x 1; } void dn(int x) { while (1) { int v x, l x 1, r l | 1; if (l hs cp(h[l], h[v])) v l; if (r hs cp(h[r], h[v])) v r; if (v x) return; sw(x, v); x v; } } void ins(int x) { h[hs] x; ps[x] hs; up(hs); } void fix(int x) { if (!ps[x]) return; int v ps[x]; up(v); dn(ps[x]); } int pop() { int x h[1]; ps[x] 0; if (hs 1) { hs 0; return x; } h[1] h[hs--]; ps[h[1]] 1; dn(1); return x; } int main() { ios::sync_with_stdio(false); cin.tie(0); cin n; for (int i 1; i n; i) cin p[i], q[p[i]] i; for (int i 1; i n; i) a[i] max(a[i - 1], p[i]); for (int i n; i 1; i--) b[i] max(b[i 1], p[i]); u[n] d[n] n; for (int i n - 1; i 1; i--) { u[i] q[i] q[i 1] ? u[i 1] : i; d[i] q[i] q[i 1] ? d[i 1] : i; } for (int i 1; i n; i) { int r a[q[i]]; if (r i r d[i]) f[i] r; r b[q[i]]; if (r i r u[i]) f[i] r; } int i 1, lr -1; ll sm 0, ans 0; while (i n) { if (!f[i]) { i; continue; } int l i, r f[i], w r - l; m; t[m] m 1 l lr; int v w - (t[m] z[m - 1]); if (v 0) { z[m] 1; y[m] v; sm v 2; ans v; ins(m); if (t[m] z[m - 1]) fix(m - 1); } while (hs) { int x h[1], k ky(x); if (k || sm r) { if (k sm r) break; ll e sm - r; if (k e k) { y[x] - e; sm - e; ans - e; fix(x); break; } } x pop(); bool nx x m t[x 1] z[x 1]; bool pr x 1 t[x] z[x - 1]; int v y[x]; z[x] 0; y[x] 0; sm - v 2; ans - v; if (nx) { y[x 1]; sm; ans; fix(x 1); } if (pr) fix(x - 1); } lr r; i r; } cout n - ans \n; }

相关新闻

Godot脚本编辑器进阶:打造IDE级智能编码体验的插件配置指南

Godot脚本编辑器进阶:打造IDE级智能编码体验的插件配置指南

1. 项目概述:为什么我们需要一个“IDE级”的脚本编辑器? 如果你和我一样,是从Unity、Unreal Engine或者其他大型商业引擎转向Godot的开发者,那么你大概率会对Godot内置的脚本编辑器产生一种复杂的感情。一方面,它简洁、…

2026/7/31 8:26:41 阅读更多 →
虚拟电厂博弈与碳交易优化的Python实现

虚拟电厂博弈与碳交易优化的Python实现

1. 项目概述:多虚拟电厂博弈与碳交易优化这个项目本质上是在解决一个电力行业的前沿问题——如何让多个虚拟电厂(VPP)在碳交易机制下实现最优协同运行。虚拟电厂作为分布式能源的聚合体,其调度优化一直是个复杂问题,而引入碳交易机制后&#…

2026/7/31 8:26:41 阅读更多 →
Armbian系统从基础配置到深度调优:打造高效开发与服务器环境

Armbian系统从基础配置到深度调优:打造高效开发与服务器环境

1. 项目概述:从“能用”到“好用”的系统调优刚给设备刷上Armbian,看着命令行界面成功启动,心里那块石头总算落了地。但先别急着庆祝,这仅仅是万里长征的第一步。一个刚刷好的Armbian系统,就像一间刚刚交付的毛坯房&am…

2026/7/31 8:26:41 阅读更多 →

最新新闻

Transformer在工业预测中的回归模型优化实践

Transformer在工业预测中的回归模型优化实践

1. 项目背景与核心价值 在工业预测和金融分析领域,数据回归预测一直是个经典难题。传统的时间序列预测方法(如ARIMA、Prophet)在处理非线性关系时表现乏力,而常规的LSTM神经网络又存在长期依赖捕捉不足的问题。Transformer架构凭借…

2026/7/31 9:05:56 阅读更多 →
Linux C++系统编程入门:从核心概念到实战应用

Linux C++系统编程入门:从核心概念到实战应用

1. 项目概述:为什么要在Linux上搞C系统编程?如果你是一个C开发者,并且你的工作环境是Linux,那么“系统编程”这四个字,对你来说可能既熟悉又陌生。熟悉的是,你每天都在和Linux打交道,用着它的命…

2026/7/31 9:05:56 阅读更多 →
工业互联网服务平台发展提速:2026-2032年复合增长率达12.2%

工业互联网服务平台发展提速:2026-2032年复合增长率达12.2%

作为深耕产业数字化30年的分析师,我可以明确告诉所有制造企业CEO、市场负责人和投资人:当下工业互联网服务平台早已不是PPT里的概念风口,而是能直接落地降本提效、重构制造业核心竞争力的确定性赛道。所有核心数据均严格对齐QYResearch官方发…

2026/7/31 9:05:56 阅读更多 →
“金融拥军”的样本——建行广东省茂名市分行:戎归桑梓育新苗

“金融拥军”的样本——建行广东省茂名市分行:戎归桑梓育新苗

清晨六点,广东省茂名高州沙田镇的薄雾还未散尽,潘伟华已经站在广东弘地农业开发有限公司(以下简称“弘地农业”)的种苗培育车间里,看着一排排嫩绿的圣女果种苗在恒温恒湿的环境中舒展新叶。这些优质种苗不仅要供应本地…

2026/7/31 9:05:56 阅读更多 →
工厂越忙越不赚钱?毁掉利润的从来不是订单少,是低效内耗

工厂越忙越不赚钱?毁掉利润的从来不是订单少,是低效内耗

很多中小工厂都逃不开一个扎心怪圈:车间机器不停转、员工天天加班、订单排得满满当当,看似生意红火,月底对账却发现利润微薄,甚至忙完白干、倒贴成本。不少老板把问题归咎于原材料涨价、订单单价低、市场内卷。但深耕制造行业就会…

2026/7/31 9:05:56 阅读更多 →
SVPWM五段式与七段式Simulink建模:从原理到代码生成的电机控制实战

SVPWM五段式与七段式Simulink建模:从原理到代码生成的电机控制实战

1. 项目概述:从SPWM到SVPWM,我们到底在追求什么?如果你正在做电机控制、三相逆变器或者新能源并网,那么“SVPWM”这个词你一定不陌生。它全称是“空间矢量脉宽调制”,听起来有点玄乎,但说白了,它…

2026/7/31 9:04:56 阅读更多 →

日新闻

物理复制比逻辑复制好在哪?数据库复制原理详解

物理复制比逻辑复制好在哪?数据库复制原理详解

数据库复制是把主库数据同步到备库的机制,分为逻辑复制和物理复制两种。逻辑复制传输的是 SQL 语句或行变更事件,物理复制传输的是存储引擎底层的物理日志。阿里云 PolarDB(云原生数据库)采用物理复制,在同步延迟、数据…

2026/7/31 0:00:34 阅读更多 →
BilibiliDown:3分钟学会B站视频下载的终极指南

BilibiliDown:3分钟学会B站视频下载的终极指南

BilibiliDown:3分钟学会B站视频下载的终极指南 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_mirrors/bi/Bilib…

2026/7/31 0:00:34 阅读更多 →
有哪些游戏数据AI平台?游戏行业Data+AI融合方案盘点

有哪些游戏数据AI平台?游戏行业Data+AI融合方案盘点

当前,游戏行业的“DataAI融合”已从概念验证进入价值落地阶段。根据IDC 2025年数据,中国AI游戏云市场规模已达18.6亿元;同时,游戏研发环节AI渗透率高达86%,生成式AI内容普及率超过50%。面对庞大的市场,游戏…

2026/7/31 0:00:34 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/31 1:03:03 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/29 14:34:28 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/31 4:19:39 阅读更多 →

月新闻