acmer-coach 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26,4 +26,6 @@ jobs:
26
26
  - uses: actions/setup-node@v4
27
27
  with:
28
28
  node-version: '24'
29
+ - run: npm install --ignore-scripts --no-package-lock
30
+ - run: npm test
29
31
  - run: npm publish --provenance --access public
package/README.md CHANGED
@@ -98,7 +98,7 @@ learned/verified 记录,或路线中在此前安排的必验训练,不能从
98
98
 
99
99
  本周主线可设置 `focusUntil`,到期先复盘修订。路线不提前占用数月日程,
100
100
  `coach_plan` 继续管理近期时间块。旧 v1 路线可读,会标记 `needsReview`;需明确
101
- 修订当前及后续阶段后迁移 v2,插件不会自动重写。优先级与教学方案仍由模型判断,
101
+ 修订当前及后续阶段后迁移 v3,插件不会自动重写。优先级与教学方案仍由模型判断,
102
102
  程序现在会要求目标和 VP 证据先进入策略层;能力卡片仍由仓库维护,未知卡片不会自动臆造。
103
103
  现在可以直接连接 VP:`coach_vp_connect start` 打开授权页,登录并允许只读访问后,
104
104
  把一次性 code 交给 `coach_vp_connect finish`。然后用 `coach_vp_sync` 增量同步比赛、
@@ -108,12 +108,42 @@ learned/verified 记录,或路线中在此前安排的必验训练,不能从
108
108
  把 AC、WA/TLE/RE 和比赛分钟画在同一条时间轴上。
109
109
 
110
110
  每个 VP 账号都放在 `~/.dsh/knowledge/vp-accounts/<user_id>/`,token 单独保存,
111
- 同步游标、原始安全投影和回放缓存都按账号分开。切换账号会切换教练工作区;服务端
111
+ 同步游标、原始安全投影、回放缓存和 `VP_EVENTS.yaml` 都按账号分开。个人训练数据
112
+ `PROGRESS.yaml`、`CURRICULUM.yaml`、`SCHEDULE.yaml`、`TARGET.yaml` 始终留在
113
+ `~/.dsh/knowledge/`,切换 VP 账号不会换教练。2.4.0 对旧账号目录只补齐缺失的个人文件;主目录已存在时保留它,冲突账号版本另存为 `.from-vp-account-<user_id>`。完成标记防止以后反复迁移覆盖,原账号文件保留;2.3.1 已产生的 `.pre-vp-account-<user_id>` 备份也保留。
114
+ 服务端
112
115
  返回的账号 id 与当前账号不一致时,客户端拒绝写入。同步和回放都不返回提交代码或 judge 输出。
113
116
  `disconnect` 只删除本地 token,保留缓存,方便重新连接同一个账号。
114
117
 
115
118
  详见 [长期课程机制](docs/长期课程机制.md)。
116
119
 
120
+ ### 2.4:证据、验收与教学依据
121
+
122
+ `coach_focus` 分开近30天的独立成功、待确认观察、已确认短板,按不同场次计数。
123
+ 成功不会增加“问题次数”;WA 不直接证明不会。`coach_postmortem findings` 用
124
+ `hypothesis/confirmed/resolved` 区分判断,必须引用 `coach_curriculum assess` 返回的本场
125
+ 原始事实;原始内容变化后旧确认引用失效。旧文字复盘保留为观察,不删除。
126
+
127
+ 新训练阶段必须提供结构化 `exitChecks`,例如
128
+ `[{node: "区间 DP", minEvents: 2, minDistinctDays: 2, independent: true, maxMinutes: 45}]`。
129
+ 只有满足条件、本阶段发生的不同成功事件才计数,缺独立性或用时记录不会被猜成通过。
130
+ `read` 返回每项 `exitCheckResults` 和缺口;旧 v1/v2 课程只读保留,先 `revise` 补齐条件
131
+ 后升级 v3。通过检测证明的是该次条件下的表现,不能解释成永久掌握。
132
+
133
+ `coach_target profiles` 提供 `regional-diagnostic`、`wf-extension`、`xian-pending` 三个
134
+ 有来源、采样范围和限制的配置,选定后可通过 `profileId` 保存。它们都仍是 provisional,
135
+ 不是西安考纲、专题频率或奖牌保证。`coach_scope` 优先使用14张精确节点卡,返回识别条件、
136
+ 证明问题、失效反例、迁移练习与原始资料,避免把一个 DP 通用卡当成所有 DP 节点的讲法。
137
+ 详见 [比赛与教学依据](docs/比赛与教学依据.md)。
138
+
139
+ 近期安排需解释“长期能力 → 本次比赛 → 当前阶段 → 今天一个动作”的取舍。
140
+ VP 增量同步会累计各分页记录,`hasMore` 告诉教练是否继续拉下一页;不会把累计缓存冒充新增记录,也不会覆盖教练补充的独立性和能力标签。平台无时区的时间按服务端 UTC 约定解释,训练日期按本机日期记录;不更改 VP 服务端。
141
+
142
+ `coach_curriculum assess` 支持 `evidenceEventIds` 查询旧场次,不受全局最近200条的影响。
143
+ 事件级 `measurements` 可记录 `competency/metric/value/passed/independent/occurredAt`;例如
144
+ 已核对回放后的零漏读测量。工具要求有限数值与显式验收、独立性,不能从一个 AC 自动推断。
145
+ 同场同指标不会凑成“两场通过”;修改旧记录也不会变成新阶段的新表现。
146
+
117
147
  **「学过」和「已验证」是两级,绝不合并。** 自评 ≠ 掌握 ——
118
148
  合成一个「会/不会」就等于退回「从数据推断掌握度」,而数据能说「花了很久」,
119
149
  说不出「卡在哪」。所以 `verified` 手标不了,它只能由检测产生。
@@ -147,12 +177,12 @@ dsh plugin --profile web add github:Miantiao1231/acmer-coach # 或从 GitHub
147
177
  > ESM 模块在进程里只求值一次,之后永远命中缓存 —— 旧代码继续跑,
148
178
  > **不报错、不报警**。唯一例外是只改浏览器端(`lib/client.js`),刷新页面即可。
149
179
 
150
- ### 首次使用:前两周它就是在瞎猜
180
+ ### 首次使用:先诊断,不把猜测当短板
151
181
 
152
182
  **说清楚这一点**:装完它对你一无所知。没有检测记录、没有判因台账,
153
- 它给的判断只能靠猜。这不是 bug,是数据不够。
183
+ 它应明确哪些未知,先安排能取得证据的小诊断;数据不足不能编造掌握度或弱项。
154
184
 
155
- 大概做几次检测之后才开始准。别在前两周就下结论。
185
+ 检测和实际训练记录逐步减少不确定性,不承诺“用满两周就一定准”。
156
186
 
157
187
  **定位不是"推断",是二分搜索。** 349 个节点,第一次怎么知道你在哪:
158
188
 
@@ -2,7 +2,7 @@ version: 1
2
2
  competencies:
3
3
  - id: contest-reading
4
4
  title: 比赛读题与筛选
5
- contestUse: 在前 30 分钟扫完题面,识别可做题和高风险题,避免漏读与过早开写。
5
+ contestUse: 在团队约定的首轮时间盒内扫描题面,识别可做题和高风险题,记录漏读与过早开写。
6
6
  nodes: []
7
7
  appliesTo: [所有区域赛场次]
8
8
  extensions: [首轮扫描, 题目分层, 读题时间盒]
@@ -10,26 +10,37 @@ competencies:
10
10
  commonFailures: [漏读题面, 被样例带偏, 没有放弃条件]
11
11
  transferProblems: [一场完整 VP]
12
12
  exitEvidence: [两场 VP 都记录首轮扫描顺序, 没有漏读题]
13
+ sources:
14
+ - title: ICPC NCNA 公布的区域赛规则(通用背景;扫描时间盒是教学设计)
15
+ url: https://nc.na.icpc.global/rules/
13
16
  - id: contest-decision
14
17
  title: 比赛决策与终局
15
18
  contestUse: 根据成功概率、剩余时间和罚时决定继续、换题或集中火力。
16
19
  nodes: []
17
- appliesTo: [区域赛 VP, 最后 60 分钟]
20
+ appliesTo: [区域赛 VP, 团队定义的终局阶段]
18
21
  extensions: [换题阈值, 终局集中, 代码验算分工]
19
22
  notFor: [多道难题同时无边界死磕]
20
23
  commonFailures: [沉没成本, 最后阶段分散火力, 不复盘换题原因]
21
24
  transferProblems: [5 小时团队 VP]
22
25
  exitEvidence: [两场 VP 有明确换题记录和终局策略]
26
+ sources:
27
+ - title: ICPC NCNA 公布的区域赛规则(排名背景;换题与终局方法是教学设计)
28
+ url: https://nc.na.icpc.global/rules/
23
29
  - id: implementation-stability
24
30
  title: 实现稳定性
25
31
  contestUse: 在限时下把已知套路写成一次通过、边界完整的代码。
26
- nodes: [数据结构, 二分, 前缀和, 差分, 动态规划基础]
32
+ nodes: [二分, 前缀和 & 差分, 动态规划基础]
27
33
  appliesTo: [中档签到题, 需要快速转化的常见模型]
28
34
  extensions: [边界清单, 小样例自测, 重写压缩]
29
35
  notFor: [只背模板不理解状态来源]
30
36
  commonFailures: [下标错误, 初始化遗漏, 重复提交同一类低级错误]
31
37
  transferProblems: [两道未见过的同类题]
32
38
  exitEvidence: [两道迁移题限时独立通过, 至少一题隔天复测]
39
+ sources:
40
+ - title: OI Wiki 二分:实现细节与边界
41
+ url: https://oi-wiki.org/basic/binary/
42
+ - title: OI Wiki 前缀和与差分:区间边界
43
+ url: https://oi-wiki.org/basic/prefix-sum/
33
44
  - id: dp-modeling
34
45
  title: DP 建模与迁移
35
46
  contestUse: 从题面抽出状态、转移、顺序和复杂度,而不是只认题型名称。
@@ -40,16 +51,24 @@ competencies:
40
51
  commonFailures: [状态定义含糊, 转移漏情况, 复杂度算错]
41
52
  transferProblems: [一道结构相同但题面不同的 DP, 一道隔天迁移题]
42
53
  exitEvidence: [能解释状态为何足够, 两道新题独立完成]
54
+ sources:
55
+ - title: OI Wiki 动态规划基础:状态与转移
56
+ url: https://oi-wiki.org/dp/basic/
43
57
  - id: graph-modeling
44
58
  title: 图论建模
45
59
  contestUse: 识别图结构并选对最短路、连通性、拓扑序、树或网络流模型。
46
- nodes: [图论基础, 最短路, 拓扑排序, DFS(搜索), 并查集]
60
+ nodes: [图论相关概念, 最短路, 拓扑排序, DFS(图论), 并查集, 强连通分量, 最近公共祖先]
47
61
  appliesTo: [关系传播, 依赖顺序, 连通块, 路径代价]
48
62
  extensions: [DAG DP, 树上问题, 生成树, 流与匹配]
49
63
  notFor: [把所有关系题都硬套最短路]
50
64
  commonFailures: [建边方向错, 忘记不连通, 复杂度超限]
51
65
  transferProblems: [两种表面不同的关系建模题]
52
66
  exitEvidence: [限时识别模型并独立写出两题]
67
+ sources:
68
+ - title: OI Wiki 最短路:算法适用条件
69
+ url: https://oi-wiki.org/graph/shortest-path/
70
+ - title: OI Wiki 强连通分量:互达与缩点应用
71
+ url: https://oi-wiki.org/graph/scc/
53
72
  - id: data-structures
54
73
  title: 数据结构选型与实现
55
74
  contestUse: 根据操作、约束和查询方式选择合适结构并稳定实现。
@@ -60,6 +79,11 @@ competencies:
60
79
  commonFailures: [区间边界错, 懒标记下传错, 结构选重]
61
80
  transferProblems: [同结构不同操作题]
62
81
  exitEvidence: [模板能从零写出, 新题能说明为何选它]
82
+ sources:
83
+ - title: OI Wiki 树状数组:操作与可差分信息
84
+ url: https://oi-wiki.org/ds/fenwick/
85
+ - title: OI Wiki 线段树基础:维护信息与延迟标记
86
+ url: https://oi-wiki.org/ds/seg/
63
87
  - id: math-combinatorics
64
88
  title: 数学与组合建模
65
89
  contestUse: 把计数、模运算、概率和构造题压成可计算的结构。
@@ -70,6 +94,11 @@ competencies:
70
94
  commonFailures: [重复计数, 模逆不存在, 边界概率遗漏]
71
95
  transferProblems: [两道不同叙事的计数题]
72
96
  exitEvidence: [能写出计数对象和去重方式, 一题隔天复测]
97
+ sources:
98
+ - title: OI Wiki 排列组合:计数对象与组合公式
99
+ url: https://oi-wiki.org/math/combinatorics/combination/
100
+ - title: OI Wiki 模逆元:存在条件与求法
101
+ url: https://oi-wiki.org/math/number-theory/inverse/
73
102
  - id: code-review
74
103
  title: 代码检查与调试
75
104
  contestUse: 在提交前快速发现边界、溢出、复杂度和实现偏差。
@@ -80,6 +109,9 @@ competencies:
80
109
  commonFailures: [没有最小反例, 只看样例, 不验证复杂度]
81
110
  transferProblems: [给出一份错误代码并定位最小反例]
82
111
  exitEvidence: [三次提交前检查都能指出具体风险]
112
+ sources:
113
+ - title: OI Wiki 常见错误(边界、溢出和调试检查)
114
+ url: https://oi-wiki.org/contest/common-mistakes/
83
115
  - id: team-communication
84
116
  title: 团队沟通与分工
85
117
  contestUse: 让三个人并行推进、及时同步、减少重复劳动和信息丢失。
@@ -90,3 +122,6 @@ competencies:
90
122
  commonFailures: [没人汇报, 两人重复做题, 交接时丢约束]
91
123
  transferProblems: [三人 5 小时 VP]
92
124
  exitEvidence: [两场 VP 有分工记录和交接记录]
125
+ sources:
126
+ - title: ICPC NCNA 公布的区域赛规则(团队赛制;交接与验收是教学设计)
127
+ url: https://nc.na.icpc.global/rules/
@@ -0,0 +1,61 @@
1
+ # 这是可追溯的选题诊断,不是出题频率榜;provisional 禁止解释成官方考纲。
2
+ version: 1
3
+ profiles:
4
+ - id: regional-diagnostic
5
+ title: 区域赛通用能力诊断(有限样本)
6
+ scope: 用公开区域赛的题面与官方解题建立诊断任务,再结合本人 VP 证据取舍。
7
+ status: provisional
8
+ sources:
9
+ - title: NWERC 2024 官方题面(采样 A、D、E、F、K、L)
10
+ url: https://2024.nwerc.eu/main/problem-set.pdf
11
+ - title: NWERC 2024 官方解题(A/D/E/F/K/L 对应页)
12
+ url: https://2024.nwerc.eu/main/solutions.pdf
13
+ - title: ICPC NCNA 公布的区域赛规则(通用背景,不提供专题频率)
14
+ url: https://nc.na.icpc.global/rules/
15
+ competencyIds: [contest-reading, contest-decision, implementation-stability, dp-modeling, graph-modeling, data-structures, math-combinatorics, code-review, team-communication]
16
+ selectionGuidance:
17
+ - 先用整场 VP 诊断读题、实现、调试与分工,再用经确认的失败原因选择专题;成功题用作能力基线。
18
+ - 采样 A 检查从精确排序规则到实现的转化;D 检查计数状态;E 检查大次数变换与模幂,题名不决定算法。
19
+ - 采样 L 检查可行性单调性与贪心证明;F 检查单调栈和并查集组合;K 检查路径与概率模型组合。
20
+ - 赛前优先修复已证实、可在剩余时间完成验收的障碍;未证实的缺口先安排短诊断,不直接扩知识点。
21
+ - 同一题允许多种正确解法;把能解释条件并独立迁移作为验收,不能将某个算法标签当唯一答案。
22
+ limitations:
23
+ - 当前算法样本只有 NWERC 2024 的六题,不能推出中国区域赛频率、任何场次金牌题数或西安出题预测。
24
+ - 读题时间盒、换题条件、验收动作是插件教学设计,需要按个人与团队记录调整,规则来源不证明这些训练阈值。
25
+ - 未采样其余题或跨年份统计;此配置不是西安考纲,排名与奖牌目标仍需对应比赛榜单。
26
+ - id: wf-extension
27
+ title: WF 扩展能力诊断(题面样本)
28
+ scope: 在基础能力稳定后,以 World Finals 原题检查跨模型推理、约束解释和交互实现。
29
+ status: provisional
30
+ sources:
31
+ - title: ICPC 2024 World Finals 官方题面(采样 B、I、L)
32
+ url: https://icpc.global/worldfinals/problems/2024-ICPC-World-Finals/icpc2024.pdf
33
+ - title: ICPC 2024 交互题评测说明(输出刷新等要求)
34
+ url: https://docs.icpc.global/wp-content/uploads/2024/08/2024-JudgingNotes.pdf
35
+ competencyIds: [contest-reading, contest-decision, dp-modeling, graph-modeling, data-structures, math-combinatorics, code-review, team-communication]
36
+ selectionGuidance:
37
+ - 采样 B 用于检查概率对象、重复元素与事件依赖的精确表达;不能仅凭概率题标签选一个模板。
38
+ - 采样 I 用于检查树上覆盖目标与最坏响应时间的建模,要求先解释判定或优化方案再实现。
39
+ - 采样 L 用于检查未知位置与朝向下的信息状态、安全动作和终止条件;交互程序必须按评测说明刷新输出。
40
+ - 只有当前基础能力经新题和延迟复测确认后,才将此样本中的扩展任务转为主线;短期比赛可保留为旁线讨论。
41
+ limitations:
42
+ - 当前只有 2024 WF 三道题面样本,未核验这些题的完整官方题解;能力映射是教学诊断推断,不是唯一解法。
43
+ - 不能从样本推出 WF 录取标准、区域赛奖牌线或必备专题全表;不把 CF rating 当作阶段通过证据。
44
+ - 不用未验证的交互策略宣称可通过;需要对应交互器与完整程序验证。
45
+ - id: xian-pending
46
+ title: 西安区域赛(待采样)
47
+ scope: 为已选西安目标保留真实样本入口;当前只提供通用比赛过程诊断。
48
+ status: provisional
49
+ sources:
50
+ - title: QOJ 西安历年比赛目录(仅核验样本入口,未作专题统计)
51
+ url: https://qoj.ac/category/87
52
+ - title: ICPC NCNA 公布的区域赛规则(通用背景,非西安本届规则)
53
+ url: https://nc.na.icpc.global/rules/
54
+ competencyIds: [contest-reading, contest-decision, implementation-stability, code-review, team-communication]
55
+ selectionGuidance:
56
+ - 使用本人和当前团队 VP 的经确认障碍安排短期动作,专题需求暂参考区域赛通用诊断并明示来源。
57
+ - 先核验目标届次、原始题面、主办方题解和榜单,再记录逐题模型、可替代解法及样本年份。
58
+ - 样本补齐后才修订专题取舍;比赛名和账号 rating 都不能单独生成西安专题权重。
59
+ limitations:
60
+ - 历年目录不能证明某知识点高频;尚未完成西安原题与官方题解逐题采样,不能预测本届题目。
61
+ - 此配置不是西安考纲,也未核验目标届次奖牌榜单,不能给出金牌保证或做题数保证。
@@ -0,0 +1,201 @@
1
+ # 技术边界来自逐页来源;练习与验收是本插件的教学设计,不是比赛考纲。
2
+ version: 1
3
+ nodes:
4
+ - id: 二分
5
+ title: 二分:先证明可行性边界
6
+ contestUse: 把最优值问题转成可判定的阈值问题,先算一次 check 的成本。
7
+ recognition: [答案有序且 check 的真假只切换一次, 能构造保证包含答案的上下界]
8
+ proofQuestions: [为什么 check 成立时更宽松的阈值也成立, 循环不变量与终止后的答案分别是什么]
9
+ appliesTo: [有序查找, 最大值最小化或最小值最大化且判定单调]
10
+ extensions: [实数二分的误差界, 二分加贪心或图算法判定]
11
+ notFor: [真假模式为真假真时直接二分, 没有单峰证明就套三分]
12
+ commonFailures: [全可行或全不可行时越界, 上下界更新不推进, check 的复杂度被漏算]
13
+ transferProblems: [一道未标注算法的容量分配题, 把判定改成非单调并给出二分失效样例]
14
+ exitEvidence: [独立写出判定单调性证明, 新题通过并检查边界无解与答案在端点的情况]
15
+ sources:
16
+ - title: OI Wiki 二分:二分答案与实现细节
17
+ url: https://oi-wiki.org/basic/binary/
18
+ - id: 贪心
19
+ title: 贪心:选择规则和交换证明
20
+ contestUse: 在编码前说明局部选择为何保留至少一个最优解。
21
+ recognition: [能替换最优方案中的一步而不变差, 选择后剩余问题保持相同结构]
22
+ proofQuestions: [交换以后是否仍可行, 哪个条件保证目标值不变差]
23
+ appliesTo: [能证明的排序选择, 区间调度或可撤销的选择]
24
+ extensions: [堆维护后悔选择, 贪心作为二分的 check]
25
+ notFor: [只有最优子结构却未证明贪心选择性质, 凭样例推导排序规则]
26
+ commonFailures: [只比较眼前收益, 交换破坏后续可行性, 比较器不满足严格弱序]
27
+ transferProblems: [把无权区间调度改为带权并解释原贪心为何失效, 一道不同叙事的交换论证题]
28
+ exitEvidence: [写出可行性与不变差两段证明, 用小规模穷举核验候选规则并独立完成迁移题]
29
+ sources:
30
+ - title: OI Wiki 贪心:证明与动态规划的区别
31
+ url: https://oi-wiki.org/basic/greedy/
32
+ - id: 前缀和 & 差分
33
+ title: 前缀和与差分:离线维护的边界
34
+ contestUse: 先区分查询发生在全部更新之后,还是更新查询交替发生。
35
+ recognition: [区间信息可由两个前缀消去, 多次区间加后只需一次恢复数组]
36
+ proofQuestions: [为什么区间和是两个前缀之差, 区间修改为什么只改差分的两个端点]
37
+ appliesTo: [静态区间和, 离线区间加, 二维矩形统计]
38
+ extensions: [差分加树状数组支持在线查询, 树上差分加最近公共祖先]
39
+ notFor: [用两个前缀最小值直接相减求区间最小值, 每次更新后重算全数组却声称在线高效]
40
+ commonFailures: [闭区间右端漏加一, 空区间和零下标处理错, 累加溢出]
41
+ transferProblems: [矩形加和单点查询的离线题, 把同题改为更新查询交替并重新选结构]
42
+ exitEvidence: [解释端点更新和恢复过程, 用单点全区间相邻区间样例验证并做一题新题]
43
+ sources:
44
+ - title: OI Wiki 前缀和与差分:一维与二维、在线扩展
45
+ url: https://oi-wiki.org/basic/prefix-sum/
46
+ - id: 动态规划基础
47
+ title: 动态规划:状态足够与计算顺序
48
+ contestUse: 从可区分的未来决策设计状态,写清合法性、目标值和依赖。
49
+ recognition: [许多决策路径到达同一个子问题, 状态保留影响未来的全部必要信息]
50
+ proofQuestions: [相同状态的两段历史为何允许共用后续解, 转移是否覆盖且只覆盖合法决策]
51
+ appliesTo: [有限状态上的递推, 有可计算依赖顺序或可证明终止的记忆化搜索]
52
+ extensions: [树形和区间 DP, 状压 DP, 计数与最优化使用不同合并运算]
53
+ notFor: [将不同剩余资源的历史合为一态, 有环依赖却直接按下标递推]
54
+ commonFailures: [状态含义在中途变化, 不可达状态初始化为零, 只算状态数没算转移数]
55
+ transferProblems: [未标注专题的选择序列题, 给出只记当前位置却漏掉剩余资源的反例]
56
+ exitEvidence: [解释状态充分性与依赖顺序, 两道新题独立完成且至少一题隔天复测]
57
+ sources:
58
+ - title: OI Wiki 动态规划基础:状态、转移与性质
59
+ url: https://oi-wiki.org/dp/basic/
60
+ - id: 背包 DP
61
+ title: 背包:使用次数决定转移层
62
+ contestUse: 从物品使用次数和容量语义确定转移与遍历方向。
63
+ recognition: [资源容量较小且可作为状态, 可选项按零一或多次使用分类]
64
+ proofQuestions: [一维压缩后的转移读取的是上一层还是本层, 恰好装满与容量以内最优如何初始化]
65
+ appliesTo: [零一与完全背包, 可转成资源容量的计数选择]
66
+ extensions: [多重背包的二进制拆分, 多维资源或价值维度转换]
67
+ notFor: [容量巨大时照搬 O(nW), 有额外物品依赖却当成独立选择]
68
+ commonFailures: [零一背包正序导致同一件重复使用, 计数题混淆组合与排列, 恰好装满未标不可达]
69
+ transferProblems: [同一题分别限制每项一次和不限次数, 一道容量维度换成价值维度的题]
70
+ exitEvidence: [用单件物品容量两倍构造错误循环反例, 独立完成新题并说明初始化与复杂度]
71
+ sources:
72
+ - title: OI Wiki 背包 DP:零一背包与完全背包
73
+ url: https://oi-wiki.org/dp/knapsack/basic/
74
+ - id: 状压 DP
75
+ title: 状压 DP:集合不是完整历史
76
+ contestUse: 当对象数小,用集合编码已使用对象,再补上影响未来的状态。
77
+ recognition: [对象数量允许指数状态, 集合与少量附加信息足以确定后续选择]
78
+ proofQuestions: [为什么相同集合仍可能需要区分终点, 枚举子集的总转移量是 2^n 还是 3^n]
79
+ appliesTo: [小规模集合选择, 集合加终点的路径 DP]
80
+ extensions: [子集卷积式枚举, 轮廓状态与插头 DP 的状态设计]
81
+ notFor: [只看 n 小不核算内存, 旅行路径只记访问集合而漏掉当前终点]
82
+ commonFailures: [补集超出 n 位, 重复计数, 指数复杂度漏乘状态维度]
83
+ transferProblems: [一道未标注专题的任务分配题, 同一访问集合不同终点的后续代价反例]
84
+ exitEvidence: [写出状态与总转移复杂度, 用小 n 全排列对照并完成一题未见过的迁移题]
85
+ sources:
86
+ - title: OI Wiki 状压 DP:集合编码与例题状态
87
+ url: https://oi-wiki.org/dp/state/
88
+ - id: 最短路
89
+ title: 最短路:权值条件和状态图
90
+ contestUse: 先确定点代表什么状态、边代价是什么,再依据权值选算法。
91
+ recognition: [目标是路径上可相加代价的最小值, 状态图能够完整表达约束]
92
+ proofQuestions: [Dijkstra 的确定最小距离步骤为何依赖非负边, 负环是否从源点可达且能影响目标]
93
+ appliesTo: [非负权 Dijkstra, 单位权 BFS, 允许负权时按规模选择 Bellman-Ford 或 DAG 递推]
94
+ extensions: [分层图表达有限次数操作, 双向距离组合, 最短路上的计数需处理零权环]
95
+ notFor: [负边图直接使用确定后不再更新的 Dijkstra, 将一般图最长简单路直接变号后套最短路]
96
+ commonFailures: [错误建边方向, INF 相加溢出, 把第一次入队当作最终距离]
97
+ transferProblems: [s到a权2、s到b权5、b到a权-4的有向图,展示提前确定a的错误, 一道带一次优惠操作的状态图题]
98
+ exitEvidence: [解释算法适用条件及负权反例, 独立建立新题状态图并检查不连通与溢出]
99
+ sources:
100
+ - title: OI Wiki 最短路:Bellman-Ford、Dijkstra 正确性与比较
101
+ url: https://oi-wiki.org/graph/shortest-path/
102
+ - id: 强连通分量
103
+ title: 强连通分量:互达与缩点
104
+ contestUse: 把有向图中的互达关系压成 DAG,同时确认组件内信息能否压缩。
105
+ recognition: [需要识别有向环组成的互达块, 跨组件关系需要拓扑顺序]
106
+ proofQuestions: [为什么缩点后不能有有向环, 组件内所有点互达为何不等于所有点权都能合法收集]
107
+ appliesTo: [有向图互达划分, 保持语义的缩点 DP, 2-SAT 的矛盾检测]
108
+ extensions: [缩点加拓扑 DP, 2-SAT, 凝聚图上的可达性]
109
+ notFor: [把无向连通块当成 SCC 的完整替代, 简单路径问题中不证明便将组件点权求和]
110
+ commonFailures: [用已出栈节点更新 low, 未遍历全部连通部分, 缩点后的重边重复计数]
111
+ transferProblems: [中心和三个叶子的双向星形图构成一个 SCC,但简单路径最多经过三个点,解释缩点求和失效, 一道依赖循环消除后的 DAG 题]
112
+ exitEvidence: [手算一例分量与凝聚图并解释信息合并条件, 独立完成新题并核对 low 与栈状态]
113
+ sources:
114
+ - title: OI Wiki 强连通分量:Tarjan 的栈状态和应用
115
+ url: https://oi-wiki.org/graph/scc/
116
+ - id: 并查集
117
+ title: 并查集:只合并的等价关系
118
+ contestUse: 用集合代表等价或无向连通关系,先检查是否需要删除与分裂。
119
+ recognition: [连接只增加且查询是否同集合, 已处理位置可以永久跳过]
120
+ proofQuestions: [父指针为何只是集合表示而非原图边, 删除一条桥后为什么普通并查集无法分裂]
121
+ appliesTo: [增量无向连通, Kruskal, 满足单调性的后继跳转]
122
+ extensions: [带权并查集, 回滚并查集配合离线动态连通]
123
+ notFor: [直接维护有向可达性, 对路径压缩结构随意撤销单次合并]
124
+ commonFailures: [合并非根节点, 将父指针当原图路径, 忘记初始化孤立点]
125
+ transferProblems: [在线只加边后改为允许删边并说明新需求, 一道永久填满后跳过位置的模拟题]
126
+ exitEvidence: [解释等价关系与维护的不变量, 用重复合并孤点自环自测并独立完成迁移题]
127
+ sources:
128
+ - title: OI Wiki 并查集:合并、路径压缩及扩展操作
129
+ url: https://oi-wiki.org/ds/dsu/
130
+ - id: 树状数组
131
+ title: 树状数组:前缀聚合和可消去信息
132
+ contestUse: 对单点加和区间和先选短小结构,扩展操作必须重新推导。
133
+ recognition: [频繁单点变化与前缀聚合, 区间答案可以从两个前缀消去]
134
+ proofQuestions: [lowbit 管辖的区间如何覆盖前缀且互不重复, 为什么两个前缀最小值无法恢复区间最小值]
135
+ appliesTo: [单点加区间和, 离散化后逆序对, 差分后的区间加单点查]
136
+ extensions: [两棵树状数组维护区间加区间和, 非负频数下寻找第 k 小]
137
+ notFor: [把前缀 min 相减查询任意区间, 频数有负值仍直接按前缀单调性找第 k 小]
138
+ commonFailures: [零下标更新死循环, 离散化顺序或重复值错误, 把赋值操作当作增量]
139
+ transferProblems: [一道动态排名题, 从点加区间和推导区间加区间和]
140
+ exitEvidence: [从区间覆盖解释更新和查询, 负增量重复值与边界自测并完成未标注专题新题]
141
+ sources:
142
+ - title: OI Wiki 树状数组:区间查询、区间加与第 k 小
143
+ url: https://oi-wiki.org/ds/fenwick/
144
+ - id: 线段树
145
+ title: 线段树:信息合并和标记作用
146
+ contestUse: 先定义节点信息、合并方式和更新如何作用,最后写树的代码。
147
+ recognition: [区间可分成左右两半并合并查询结果, 更新可由足够的摘要正确作用于整段]
148
+ proofQuestions: [合并运算为何满足结合律且顺序是否重要, 赋值与加法标记先后作用的结果是否相同]
149
+ appliesTo: [动态区间和或最值, 可证明标记作用的区间加与赋值]
150
+ extensions: [树链剖分, 可持久化, 特定条件下的区间最值操作]
151
+ notFor: [只有区间和却直接推出区间 chmin 后的新和, 混合标记不定义复合顺序]
152
+ commonFailures: [下传后父节点未重算, 标记覆盖顺序错, 乘区间长度或数值范围漏算]
153
+ transferProblems: [区间加与区间赋值交替的查询题, 数组(0和4)与(2和2)同和,逐项与2取min后和为2与4,证明仅有区间和摘要不足]
154
+ exitEvidence: [写出节点与标记不变量, 与小数组朴素模拟对照并限时完成一题新操作迁移题]
155
+ sources:
156
+ - title: OI Wiki 线段树基础:区间操作与延迟标记
157
+ url: https://oi-wiki.org/ds/seg/
158
+ - id: 最近公共祖先
159
+ title: 最近公共祖先:树上的共同祖先
160
+ contestUse: 将静态树上的距离和路径统计化成深度与共同祖先问题。
161
+ recognition: [对象构成有根树或分森林处理, 多次询问两点路径的公共部分]
162
+ proofQuestions: [先对齐深度后为何能同时向上跳, 根距离公式为什么减去两倍 LCA 距离]
163
+ appliesTo: [静态树 LCA, 带权树路径长度, 树上差分辅助]
164
+ extensions: [Euler 序加 RMQ, 倍增带路径聚合, 换根查询]
165
+ notFor: [一般 DAG 中直接假定共同祖先唯一, 动态改边时沿用旧倍增表]
166
+ commonFailures: [根与虚拟父节点边界错, 重链或倍增深度混用, 对不同树的点返回伪答案]
167
+ transferProblems: [带权树上多次距离查询, 同一树更换询问根后求 LCA]
168
+ exitEvidence: [解释跳跃不变量和距离式, 链星形同点祖先点样例验证并独立做迁移题]
169
+ sources:
170
+ - title: OI Wiki 最近公共祖先:倍增与树上距离
171
+ url: https://oi-wiki.org/graph/lca/
172
+ - id: 前缀函数与 KMP 算法
173
+ title: KMP:边界链与失配回退
174
+ contestUse: 用已匹配前缀的信息避免重新比较,理解失败链接才扩展题型。
175
+ recognition: [单模式精确匹配, 前后缀相等关系可沿 border 链回退]
176
+ proofQuestions: [失配为什么回到前缀函数指向的位置而不漏解, 指针增加与回退为什么合计线性]
177
+ appliesTo: [单模式匹配, border 与周期关系, 前缀出现次数统计]
178
+ extensions: [Z 函数, 多模式时的 AC 自动机, 前缀自动机上的 DP]
179
+ notFor: [多模式题仅运行一次单模式 KMP, 模糊匹配直接沿用精确相等失配链]
180
+ commonFailures: [匹配结束不回退导致漏重叠, 前缀函数下标混乱, 拼接分隔符在字符集内]
181
+ transferProblems: [重叠匹配和所有 border 的题, 题面不写字符串匹配但要求周期检测的题]
182
+ exitEvidence: [手算失配链和线性复杂度, 重复字符无匹配全匹配自测并独立完成迁移题]
183
+ sources:
184
+ - title: OI Wiki 前缀函数与 KMP:失配、应用与复杂度
185
+ url: https://oi-wiki.org/string/kmp/
186
+ - id: 快速幂
187
+ title: 快速幂:把重复作用拆成二进制
188
+ contestUse: 指数很大时寻找可结合的合成操作,并核算每次合成成本。
189
+ recognition: [同一变换重复非负整数次数, 合成满足结合律且有单位元]
190
+ proofQuestions: [指数的二进制拆分如何保证每次选取正确, 矩阵或置换的合成顺序为什么不能随意交换]
191
+ appliesTo: [整数模幂, 矩阵幂, 置换或函数重复合成]
192
+ extensions: [倍增跳转, 线性递推矩阵, 大指数下的周期研究]
193
+ notFor: [未证明周期就取模缩减指数, 未检查逆元存在就把负指数当作普通幂]
194
+ commonFailures: [指数零漏单位元, 模乘中间值溢出, 指数类型不够大]
195
+ transferProblems: [一道重复字符索引变换题, 将标量乘法改为矩阵合成并重新核算复杂度]
196
+ exitEvidence: [解释单位元与合成不变量, 核验指数零一大指数并独立完成非标量迁移题]
197
+ sources:
198
+ - title: OI Wiki 快速幂:二进制取幂与推广
199
+ url: https://oi-wiki.org/math/binary-exponentiation/
200
+ - title: OI Wiki 模逆元:模意义负指数的存在条件
201
+ url: https://oi-wiki.org/math/number-theory/inverse/
@@ -9,6 +9,19 @@
9
9
 
10
10
  ### 比赛目标先于知识图
11
11
 
12
+ * 按“长期能力目标 → 本次比赛目标 → 当前阶段成果 → 今天一个动作”解释取舍。
13
+ 比赛目标不能悄悄覆盖长期目标。赛前在剩余实际容量内选择可验收的改善,赛后再按新
14
+ 证据修订;日期只提供约束,不证明某专题该学。无法装进预算时说明暂缓什么与代价。
15
+ * `coach_target profiles` 提供有来源和样本限制的配置,再按需设置 `profileId`。
16
+ provisional 表示有限样本或尚待取样,不能称官方考纲、预测本届高频专题或保证奖牌。
17
+ 不因某知识点“低频”就永久排除,不把同一道题的某一种解法当唯一算法标签。
18
+ * 原始 VP 判题、耗时和提交是观察;WA 不等于不会,AC 不证明独立完成。先用
19
+ `coach_curriculum assess` 取事实引用,再在 `coach_postmortem findings` 记录 hypothesis。
20
+ 查代码/回放核实后才用 confirmed,引用本场真实事实并解释原因;resolved 需要独立成功
21
+ 事实。旧文字复盘只是待核实观察。工具核对引用存在,不保证因果解释正确。
22
+ * `coach_focus` 只汇总近30天不同场次:成功起点不算问题,重复提交/复盘不增加场次数,
23
+ 修改旧复盘不把它变成最近发生。分数是取舍参考,不是掌握度、出题概率或奖牌概率。
24
+
12
25
  * 有比赛目标时,先调 `coach_target read`,再调 `coach_focus`。没有目标时不能用
13
26
  rating、游标或地图后继猜长期方向;先建立比赛、日期、结果目标、团队模式、时间预算
14
27
  和能力优先级。
@@ -19,6 +32,9 @@
19
32
  `coach_postmortem`。需要回放时先用 `coach_vp_contests` 按比赛名称选择,再调
20
33
  `coach_vp_replay`;不要让学生提供 Contest ID。VP 的读题、耗时、提交、换题和团队问题优先于 rating;没有 VP 证据时要
21
34
  明确说“尚无记录”,不能装作知道短板。手工导入仍可用 `coach_vp_import`,但不能和当前账号记录混用。
35
+ * 同步返回 `hasMore=true` 时继续拉页,`pageCounts` 是本页条数,数组是累计缓存;
36
+ 不把累计条数说成新增。核对回放后可用事件级 `measurements` 记录有限数值指标,
37
+ 显式填 `passed/independent`;不要从 AC 推断零漏读或沟通良好。显式导入更新整场,保留已有题目和注解。
22
38
  * 讲知识点之前调 `coach_scope`。必须说明适用范围、延伸、反例、常见错误、迁移题和退出
23
39
  条件;工具返回“没有范围卡片”时不许凭记忆补一段看似完整的范围。
24
40
  * 训练重点是比赛能力,不是沿着地图无限往下走。阶段达到目标后可以停在当前节点,转做
@@ -28,11 +44,19 @@
28
44
 
29
45
  * 长期训练先用 `coach_curriculum read` 查看路线,再用 `assess` 查实际编排依据。
30
46
  `assess` 从 checks、代码判因、passes 和课表实际完成中给出 `id/eventId`;记录多时
31
- 按 `evidenceNodes` 缩小范围。**rating、节点状态、取消的卷子不能代替短板证据。**
47
+ 按 `evidenceNodes` 或 `evidenceEventIds` 缩小范围。**rating、节点状态、取消的卷子不能代替短板证据。**
32
48
  * 建立或修订路线前核实目标、起点与可用时间。每个阶段除能力成果、节点和验收条件外,
33
49
  必须填写 `basis`、`goalContribution`、`priorityReason`、`estimatedHours`、
34
50
  `evidenceRefs`、`finding`、`kind`、`uncertainty`、`diagnosticMethod`。
35
51
  说清观察到了什么、它怎样服务目标、为何排在这里、预计投入多少,不套统一算法清单。
52
+ * training 阶段还必须填 `exitChecks`,覆盖每个节点或能力:明确 `minEvents`,按需
53
+ 指定 `minDistinctDays`、`independent`、`maxMinutes`,或有真实测量的 `metric/maxValue`。
54
+ 不用一句“两场VP表现好”代替可检查条件;看 read 返回的 `exitCheckResults` 逐条解释缺口。
55
+ 缺字段不当通过,同一事件不重复计数。旧课程先 revise 补齐,不覆盖旧训练账本。
56
+ * verified 只证明记录日期与检测条件下的表现。隔天迁移、混合题识别和重新检测用于核对
57
+ 保持与迁移,不能把历史一次过卷解释成永久掌握;先给未标专题的题,再看能否自选模型。
58
+ * 讲节点优先使用 `coach_scope` 精确节点卡,按“识别条件 → 为什么成立 → 失效边界 →
59
+ 陌生题迁移”展开。结合 recognition/proofQuestions 和原始资料,不只给算法名与模板。
36
60
  * `kind=training` 的每个节点都要对应真实证据:补短板用 `finding=gap`,引用 gap;读题、决策、团队沟通这类没有单一地图节点的阶段改用 `competencies`,引用 VP/复盘产生的能力证据;
37
61
  在已证实能力上进阶用 `finding=extension`,引用 baseline。记录指向什么由你解读,
38
62
  但**不能写一段理由替代不存在的记录**,也不能把别的节点的失败贴来凑依据。
@@ -58,8 +82,8 @@
58
82
  动作或检测卷未结束时工具会拒绝。机械门槛通过也不等于能力自动达标;
59
83
  **刷够题数、讲完内容、到了周末都不能替代能力验收。** 优先级理由仍需教学判断,
60
84
  程序没有证明这条路线教育上最优。
61
- * 旧 v1 路线可查看,但 `needsReview` 时不能继续执行;先 assess,再 revise 补齐当前
62
- 及后续阶段的依据,明确迁移 v2。已完成阶段保留,不能自动编造依据或改写旧历史。
85
+ * 旧 v1/v2 路线可查看,但 `needsReview` 时不能继续执行;先 assess,再 revise 补齐当前
86
+ 及后续阶段的依据和 exitChecks,明确迁移 v3。已完成阶段保留,不能自动编造依据或改写旧历史。
63
87
  * `coach_plan` 仍只排近期时间块,`coach_curriculum` 保存课程顺序与阶段目标,
64
88
  `PROGRESS.yaml` 保存实际学习/检测记录,不复制另一套掌握状态。
65
89
 
@@ -0,0 +1,74 @@
1
+ import test from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import { readFileSync } from 'node:fs'
4
+ import YAML from 'yaml'
5
+
6
+ const knowledge = new URL('../assets/knowledge/', import.meta.url)
7
+ const read = name => YAML.parse(readFileSync(new URL(name, knowledge), 'utf8'))
8
+ const mapIds = new Set(read('MAP.yaml').nodes.map(node => node.id))
9
+ const competencies = read('COMPETENCIES.yaml').competencies
10
+
11
+ function sources(value, label) {
12
+ assert.ok(Array.isArray(value) && value.length > 0, `${label}: sources required`)
13
+ for (const source of value) {
14
+ assert.ok(typeof source.title === 'string' && source.title.trim(), `${label}: source title required`)
15
+ const url = new URL(source.url)
16
+ assert.equal(url.protocol, 'https:', `${label}: public HTTPS source required`)
17
+ assert.ok(!url.username && !url.password && !url.search, `${label}: no account credentials or query data`)
18
+ assert.ok(url.pathname !== '/', `${label}: link to evidence, not a homepage`)
19
+ }
20
+ }
21
+
22
+ function textList(value, label) {
23
+ assert.ok(Array.isArray(value) && value.length > 0, `${label}: nonempty list required`)
24
+ assert.ok(value.every(item => typeof item === 'string' && item.trim()), `${label}: text required`)
25
+ }
26
+
27
+ test('node teaching cards use exact map nodes and contain sourced transfer boundaries', () => {
28
+ const catalog = read('NODE_SCOPES.yaml')
29
+ assert.equal(catalog.version, 1)
30
+ assert.ok(catalog.nodes.length >= 12)
31
+ assert.equal(new Set(catalog.nodes.map(card => card.id)).size, catalog.nodes.length)
32
+ for (const card of catalog.nodes) {
33
+ assert.ok(mapIds.has(card.id), `${card.id}: unknown MAP node`)
34
+ assert.ok(card.title && card.contestUse)
35
+ for (const field of ['recognition', 'proofQuestions', 'appliesTo', 'extensions', 'notFor', 'commonFailures', 'transferProblems', 'exitEvidence']) {
36
+ textList(card[field], `${card.id}.${field}`)
37
+ }
38
+ sources(card.sources, card.id)
39
+ }
40
+ for (const id of ['最短路', '强连通分量', '线段树', '动态规划基础']) {
41
+ assert.ok(catalog.nodes.some(card => card.id === id), `${id}: important boundary card required`)
42
+ }
43
+ })
44
+
45
+ test('contest profiles identify sampling limits and use only existing competencies', () => {
46
+ const catalog = read('CONTEST_PROFILES.yaml')
47
+ const competencyIds = new Set(competencies.map(card => card.id))
48
+ assert.equal(catalog.version, 1)
49
+ assert.ok(catalog.profiles.length >= 3)
50
+ assert.equal(new Set(catalog.profiles.map(profile => profile.id)).size, catalog.profiles.length)
51
+ for (const profile of catalog.profiles) {
52
+ assert.ok(profile.title && profile.scope)
53
+ assert.ok(['provisional', 'reviewed'].includes(profile.status))
54
+ textList(profile.selectionGuidance, `${profile.id}.selectionGuidance`)
55
+ textList(profile.limitations, `${profile.id}.limitations`)
56
+ assert.ok(profile.competencyIds.length > 0)
57
+ for (const id of profile.competencyIds) assert.ok(competencyIds.has(id), `${profile.id}: unknown ${id}`)
58
+ sources(profile.sources, profile.id)
59
+ assert.match(profile.limitations.join(' '), /样本|采样|未核验/)
60
+ assert.doesNotMatch(JSON.stringify(profile), /金牌.*(?:必须|至少)\s*\d+\s*题|必考|命中率/)
61
+ }
62
+ const xian = catalog.profiles.find(profile => profile.id === 'xian-pending')
63
+ assert.ok(xian)
64
+ assert.equal(xian.status, 'provisional')
65
+ assert.match(xian.limitations.join(' '), /不是.*考纲|不能.*预测/)
66
+ })
67
+
68
+ test('general competency mappings reference real nodes and disclose their sources', () => {
69
+ assert.equal(new Set(competencies.map(card => card.id)).size, competencies.length)
70
+ for (const card of competencies) {
71
+ for (const id of card.nodes) assert.ok(mapIds.has(id), `${card.id}: unknown MAP node ${id}`)
72
+ sources(card.sources, card.id)
73
+ }
74
+ })