第八届图灵杯趣味网络国际邀请赛 - 初级组/中级组部分题解。
初级组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/9/30 22:33:57 阅读更多 →
虚拟电厂博弈与碳交易优化的Python实现

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

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

2026/10/11 18:20:11 阅读更多 →
Armbian系统从基础配置到深度调优:打造高效开发与服务器环境

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

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

2026/10/8 9:38:33 阅读更多 →

最新新闻

豆瓣影评情感分析:朴素贝叶斯文本分类实战

豆瓣影评情感分析:朴素贝叶斯文本分类实战

简介:面向人工智能与自然语言处理初学者的情感分析实践项目,聚焦豆瓣Top250影评数据,基于朴素贝叶斯分类器完成正负面情感判别。资料涵盖Scrapy爬虫采集的约5万条影评语料,好评差评比例均衡,并按照4:1划分训练集与测试…

2026/10/12 13:43:55 阅读更多 →
操作系统T1考题解析:进程状态迁移与上下文切换双线推演

操作系统T1考题解析:进程状态迁移与上下文切换双线推演

1. 项目概述:这是一份面向操作系统的教学实操型考题解析,不是试卷搬运工“第2单元进程的描述与控制考试T1”——光看标题,你可能以为这只是某高校《操作系统原理》课程的一道普通期中题。但作为带过十几届系统课实验的从业者,我得…

2026/10/12 13:43:55 阅读更多 →
Java中extends与implements的区别:从语法到设计选型

Java中extends与implements的区别:从语法到设计选型

1. 为什么这两个关键字总让人犯迷糊刚入行那会儿,我在一个后台管理系统里写代码,需要定义一个订单服务类。当时脑子里想的是“订单服务是一种服务,那就用 extends 继承一个基础服务类吧”,结果写着写着发现基础服务类里有一堆跟订…

2026/10/12 13:43:55 阅读更多 →
C语言浮点数精度陷阱与避坑指南:从IEEE 754到工程实践

C语言浮点数精度陷阱与避坑指南:从IEEE 754到工程实践

1. 从"整数思维"到"浮点思维"的认知切换很多人学C语言学到浮点数这一块,都会有一种"好像懂了但又好像没懂"的感觉。声明一个float变量、打印用%f、做做加减乘除,看起来和整数没什么区别。但一旦程序跑出0.1 0.2 ! 0.3这种…

2026/10/12 13:43:55 阅读更多 →
运动估计实验从零到一:块匹配原理、实现与调参避坑指南

运动估计实验从零到一:块匹配原理、实现与调参避坑指南

1. 运动估计到底在解决一个什么问题很多人第一次接触运动估计,脑子里冒出来的画面是摄像头追踪一个跑来跑去的人。这个理解不算错,但只看到了冰山一角。运动估计真正要回答的核心问题其实非常朴素:同一场景在相邻两帧画面里,像素点…

2026/10/12 13:43:55 阅读更多 →
【yyds】大模型开发新风向:上下文工程接管AI编程,RAG真的凉了吗?用TaoToken统一Key实测进阶指南

【yyds】大模型开发新风向:上下文工程接管AI编程,RAG真的凉了吗?用TaoToken统一Key实测进阶指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 13:42:54 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →