<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/scripts/pretty-feed-v3.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:h="http://www.w3.org/TR/html4/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>绿豆沙の小窝</title><description>绿豆沙の小窝</description><link>https://lvdousha26.github.io</link><item><title>论文阅读笔记：Attention Sink 与注意力层里的原生 MoE</title><link>https://lvdousha26.github.io/blog/paper-note-attention-sink-native-moe</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/paper-note-attention-sink-native-moe</guid><description>ICML 2026：把 sink 的注意力权重看成门控，注意力头就成了专家，注意力层本就是 MoE；由此解释 head collapse 并用负载均衡损失缓解</description><pubDate>Tue, 22 Sep 2026 13:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;论文信息&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;标题：Attention Sink Forges Native MoE in Attention Layers: Sink-Aware Training to Address Head Collapse&lt;/li&gt;
&lt;li&gt;作者：Zizhuo Fu, Wenxuan Zeng, Runsheng Wang, Meng Li（北京大学）&lt;/li&gt;
&lt;li&gt;会议：ICML 2026&lt;/li&gt;
&lt;li&gt;链接：&lt;a href=&quot;https://arxiv.org/abs/2602.01203&quot;&gt;https://arxiv.org/abs/2602.01203&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;一句话总结&lt;/h2&gt;
&lt;p&gt;以往把 attention sink 当成 softmax 归一化逼出来的“副作用”，这篇论文反过来指出：&lt;strong&gt;sink 的注意力权重本身就是门控&lt;/strong&gt;——于是注意力头成了 experts，注意力层原本就是一个 MoE，而长期训练中出现的 head collapse 就是 MoE 里的 expert collapse。&lt;/p&gt;
&lt;h2&gt;1. 背景：三种注意力机制&lt;/h2&gt;
&lt;p&gt;| 机制 | 代表模型 | 做法 |
| --- | --- | --- |
| Vanilla Attention | 大多数开源模型 | 不做处理，靠第一个 token 吸收冗余注意力 |
| Sink Attention | GPT-OSS | 在 softmax 分母里加一个可学习的 &lt;code&gt;sink&lt;/code&gt; 参数 |
| Gated Attention | Qwen3-Next | 每个头算一个 sigmoid 门控因子 |&lt;/p&gt;
&lt;p&gt;softmax 的权重必须和为 1。当某个头不需要分配那么多注意力时，多出来的权重总得有地方去——模型把它倾倒给第一个 token，而第一个 token 的 value 向量在训练中会被学到接近 0（论文称之为 &lt;strong&gt;value drain&lt;/strong&gt;，实测把首个 token 的 value 直接置零几乎不掉点）。&lt;/p&gt;
&lt;p&gt;Sink Attention 用一个没有 value 的 &lt;code&gt;sink&lt;/code&gt; 参数替掉第一个 token，Gated Attention 则干脆用显式门控。&lt;/p&gt;
&lt;h2&gt;2. 核心洞察：sink 就是隐式门控&lt;/h2&gt;
&lt;p&gt;这是全文最漂亮的一步。因为 sink 的 value 贡献为 0，把它从求和里摘出去后：&lt;/p&gt;
&lt;p&gt;$$
O_t^{l,h}=\sum_{j\neq \text{sink}}A_{t,j}^{l,h}\mathbf{v}&lt;em&gt;j^{l,h}=\underbrace{(1-A&lt;/em&gt;{t,\text{sink}}^{l,h})}&lt;em&gt;{G_t^{l,h}}\cdot\sum&lt;/em&gt;{j\neq \text{sink}}\tilde{A}_{t,j}^{l,h}\mathbf{v}_j^{l,h}
$$&lt;/p&gt;
&lt;p&gt;那个 $(1-A_{\text{sink}})$ 自然而然成了一个缩放因子。对照 Gated Attention 的 $G_t^{l,h}=\sigma(x_t^l W_\theta^{l,h})$，两者是一回事：&lt;/p&gt;
&lt;p&gt;$$
G_t^{l,h}=1-A_{t,\text{sink}}^{l,h}
$$&lt;/p&gt;
&lt;p&gt;而且这个隐式门控&lt;strong&gt;天然满足&lt;/strong&gt; Gated Attention 的两个设计选择：它是逐头的（每个头自己算自己的 sink 权重），也是等价于 sigmoid 形式的（论文给出了 $\sigma(\cdot)$ 的改写，见第 5 节）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;头的输出被门控因子缩放：sink 吸走 99% 权重时，这个头基本被“关掉”；sink 权重低时才“打开”。所以注意力层同时具备了 MoE 的两个要件——独立的 expert（各注意力头）和 router（sink 导出的门控）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;3. 为什么去掉 sink 反而更好&lt;/h2&gt;
&lt;p&gt;既然 sink 有门控作用，为什么 Sink / Gated 还会涨点？论文的解释是 &lt;strong&gt;query-key 几何被解放了&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Vanilla Attention 里，为了维持对第一个 token 的高注意力，几何上被逼成一个两极结构：后续 token 的 query 必须挤在 $\mathbf{k}_0$ 附近，它们的 key 又必须远离 $\mathbf{k}_0$ 以免干扰 sink。结果是 query 只能在很窄的角度范围内变化，key 的有效维度也被压缩，softmax 区分候选 token 的精度随之下降。&lt;/p&gt;
&lt;p&gt;Sink / Gated 把 sink 与语义 token 解耦后，$\mathbf{k}_0$ 不再特殊，q/k 分布重新变得多样——这才是它们在长文本上更强的真实原因，而不只是“消掉了 sink”这么表面。&lt;/p&gt;
&lt;h2&gt;4. Head Collapse：注意力层里的 expert collapse&lt;/h2&gt;
&lt;p&gt;已有的观察是：只有固定的一小部分头真正参与生成，&lt;code&gt;zeroing &gt;25% 的头&lt;/code&gt; 模型精度几乎不变。这和 MoE 的 expert collapse 是同一件事。&lt;/p&gt;
&lt;p&gt;论文把它定量化了。既然有了门控，头的贡献度可以直接用平均门控值衡量：&lt;/p&gt;
&lt;p&gt;$$
\mathrm{Imp}^{l,h}=\frac{1}{|\mathcal{T}|}\sum_{(i,t)\in\mathcal{T}}G_{i,t}^{l,h}
$$&lt;/p&gt;
&lt;p&gt;再用各层 importance 的&lt;strong&gt;变异系数&lt;/strong&gt;（CV）平均一下，得到头的负载不均衡度。在 LLaMA-3.1-8B、GPT-OSS-20B、Qwen3-Next-80B-A3B 上，三者的热力图都呈现同一个模式：少数头长期高亮，大量头几乎不激活。&lt;/p&gt;
&lt;p&gt;而且这个不均衡&lt;strong&gt;随训练进程加深&lt;/strong&gt;——早期占优的头会吸引到更多更新，进一步拉大差距，最后稳定在高位。代价很直接：名义上 32 个头，实际只有 4 个在干活，剩下的算力和参数都白花了。&lt;/p&gt;
&lt;h2&gt;5. 方法：Sink-Aware Training&lt;/h2&gt;
&lt;p&gt;思路照搬 MoE 的负载均衡损失，只是作用对象从 expert 换成了 head。从小到大：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;从头训练&lt;/strong&gt;，直接压各层 importance 的 CV：&lt;/p&gt;
&lt;p&gt;$$
\mathcal{L}&lt;em&gt;{\mathrm{aux}}=\lambda\sum&lt;/em&gt;{l=1}^{N_L}N_h\left[\mathrm{CV}!\left({\mathrm{Imp}^{l,h}}_{h=1}^{N_h}\right)\right]^{2}
$$&lt;/p&gt;
&lt;p&gt;总损失为 $\mathcal{L}=\mathcal{L}&lt;em&gt;{\mathrm{base}}+\mathcal{L}&lt;/em&gt;{\mathrm{aux}}$。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;微调已有模型&lt;/strong&gt;要小心：直接这么加会触发论文命名的 &lt;strong&gt;head pinning effect&lt;/strong&gt;——已塌缩的头承载着预训练知识、门控值抗拒变化，其他头为了“追平”反而把自己的门控也抬上去，结果是大家一起高，还是不均衡。&lt;/p&gt;
&lt;p&gt;解法借自 DeepSeek-MoE 的 shared/routed expert 设计：把每层最重要的 top-$m$ 个头设为 shared head 保持原样，只对剩下的 routed head 做均衡：&lt;/p&gt;
&lt;p&gt;$$
\mathcal{L}&lt;em&gt;{\mathrm{aux}}=\lambda\sum&lt;/em&gt;{l=1}^{N_L}(N_h-m)\left[\mathrm{CV}!\left({\mathrm{Imp}^{l,h}:h\notin\mathcal{T}^{l}_{m}}\right)\right]^{2}
$$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;工程上怎么拿到门控&lt;/strong&gt;是个真问题。$G=1-A_{\text{sink}}$ 需要注意力权重，而 Flash Attention 根本不物化注意力矩阵。论文的做法是用 LSE 换：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vanilla Attention：$G_t^{l,h}=\sigma!\left(\mathrm{LSE}_{\neg 0}-\dfrac{\mathbf{q}_t^{l,h}{\mathbf{k}_0^{l,h}}^\top}{\sqrt{d_h}}\right)$，LSE 直接由 Flash Attention kernel 返回；&lt;/li&gt;
&lt;li&gt;Sink Attention：$G_t^{l,h}=\sigma(\mathrm{LSE}-\mathbf{sink})$——顺便把原先必须退回非融合实现的 Sink Attention 也塞进了 Flash Attention。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;额外训练开销不到 2%。&lt;/p&gt;
&lt;h2&gt;6. 实验结果&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;从头训练&lt;/strong&gt;（0.6B / 1B / 2B，三种机制 × 有无 aux 损失）。两个结论很稳：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Gated &gt; Sink &gt; Vanilla，三种规模都成立；&lt;/li&gt;
&lt;li&gt;加 aux 损失在&lt;strong&gt;所有&lt;/strong&gt;机制、所有规模、所有指标上一致涨点，验证 BPB 一致下降。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;平均分提升（base → base+aux）：&lt;/p&gt;
&lt;p&gt;| 规模 | Vanilla | Sink | Gated |
| --- | --- | --- | --- |
| 0.6B | 39.54 → &lt;strong&gt;40.82&lt;/strong&gt; | 40.31 → &lt;strong&gt;41.11&lt;/strong&gt; | 40.43 → &lt;strong&gt;41.35&lt;/strong&gt; |
| 1B | 42.59 → &lt;strong&gt;43.35&lt;/strong&gt; | 43.27 → &lt;strong&gt;43.75&lt;/strong&gt; | 42.69 → &lt;strong&gt;43.98&lt;/strong&gt; |
| 2B | 45.46 → &lt;strong&gt;46.83&lt;/strong&gt; | 46.35 → &lt;strong&gt;46.50&lt;/strong&gt; | 46.30 → &lt;strong&gt;47.70&lt;/strong&gt; |&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;微调&lt;/strong&gt;（Qwen3-4B / Qwen3-8B / LLaMA3.1-8B，LoRA rank=16，$\lambda=10^{-2}$，AceReason-Nemotron 数据集）在推理和 LongBench 两组基准上都一致变好，LongBench 平均分别 51.46 → &lt;strong&gt;52.75&lt;/strong&gt;、50.67 → &lt;strong&gt;55.38&lt;/strong&gt;、40.51 → &lt;strong&gt;43.98&lt;/strong&gt;——长文本是受益最大的一块，和“更好利用注意力头 = 更强的信息召回”这个解释对得上。需要注意的是 LongBench 里有个别任务（如 LLaMA3.1-8B 的 TriviaQA）反而下降，论文没有细究。&lt;/p&gt;
&lt;h2&gt;7. 读后杂感&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一点保留：这个“MoE”类比，修辞成分可能大于结构成分。&lt;/strong&gt; 论文的骨架主要借自稀疏 MoE——负载均衡损失、shared/routed expert、expert collapse——但它刻画的对象和稀疏 MoE 并不完全相同：稀疏 MoE 里 expert 是&lt;strong&gt;独立参数块&lt;/strong&gt;、路由是 &lt;strong&gt;top-k 离散选择&lt;/strong&gt;，未被选中的 expert 拿不到梯度，这正是 expert collapse 的根源；而注意力头虽然各有 $W_q/W_k/W_v$ 的切片，却始终&lt;strong&gt;全部参与计算&lt;/strong&gt;，门控 $1-A_{\text{sink}}$ 只是逐 token、逐头的&lt;strong&gt;连续标量&lt;/strong&gt;，不存在“这个 token 只走第 3、7 个头”这种调度。这里没有真正的稀疏化，也没有省下算力——aux 损失做的事，是把门控幅值拉匀。从这个角度看，它更贴近&lt;strong&gt;经典混合专家&lt;/strong&gt;（Jacobs 1991 那种：所有专家都在场，输出是带学习权重的叠加），换成更日常的说法就是&lt;strong&gt;集成学习&lt;/strong&gt;：各头的门控输出被 $W_o$ 线性组合，用集成的语言说是一次&lt;strong&gt;软性加权投票&lt;/strong&gt;（权重不要求和为 1，所以不是严格的凸组合）。这个视角下，aux 损失扮演的是集成的&lt;strong&gt;多样性正则&lt;/strong&gt;——一个 32 成员的集成只有 4 个在干活，方差缩减的收益早就没了，这或许才是不均衡更实质的代价。顺着这个类比，“head collapse 就是 MoE 里的 expert collapse”这个说法也需要打个折扣：症状确实相似，成因却不同——一边是离散选择造成的梯度饥饿，一边是连续门控上的自我强化反馈。&lt;/p&gt;
&lt;p&gt;不过这个类比起码是&lt;strong&gt;有生产力&lt;/strong&gt;的：aux 损失和 shared head 都是从 MoE 搬过来的，而且确实涨点。一个讲故事的框子能产出可验证的改进，就不算空谈；只是别反过来把这个框子当成机制本身。&lt;/p&gt;
&lt;p&gt;**这篇和前几天那篇讲离群值的文章正好咬合。**那篇说，离群值来自召回头为了对抗 RoPE 快分量、在低频维度上放大的通道级信号；这篇则指出，sink 是注意力层的 router，并且明确提到 attention sink 会诱导激活值的极端离群值（第 3.2 节引了量化相关工作）。两条线索指向同一件事：**离群值、sink、头的分工，很可能不是三个独立现象，而是同一套路由机制的不同侧面。**如果 sink 门控就是 router，那么量化时那些“必须保住”的离群通道，或许正好对应着最活跃的那些头的门控通路——这是个可以往下挖的点。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;几点存疑：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从头训练的实验最大只到 2B，aux 损失在 2B Sink 上的增益已经掉到 +0.15，能否外推到前沿规模存疑。&lt;/li&gt;
&lt;li&gt;$\lambda$ 怎么选、对结果有多敏感，正文没展开。&lt;/li&gt;
&lt;li&gt;门控值 $1-A_{\text{sink}}$ 作为“重要性”的代理，隐含假设是 sink 之外的注意力都有效；但一个头也可能是把权重均摊到一堆无关 token 上，此时门控值高却不见得有用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;论文：&lt;a href=&quot;https://arxiv.org/abs/2602.01203&quot;&gt;https://arxiv.org/abs/2602.01203&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;StreamingLLM：&lt;a href=&quot;https://arxiv.org/abs/2309.17453&quot;&gt;https://arxiv.org/abs/2309.17453&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;DeepSeek-MoE：&lt;a href=&quot;https://arxiv.org/abs/2401.06066&quot;&gt;https://arxiv.org/abs/2401.06066&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;DuoAttention：&lt;a href=&quot;https://arxiv.org/abs/2410.10819&quot;&gt;https://arxiv.org/abs/2410.10819&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>大模型为什么会产生“离群值”？</title><link>https://lvdousha26.github.io/blog/llm-outlier-rope-attention</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/llm-outlier-rope-attention</guid><description>转载精简：从 Attention Sink 与 RoPE 的冲突出发，理解 LLM 激活离群值的来源，以及 YaRN、Partial RoPE、NoPE、slash pattern 的成因</description><pubDate>Tue, 22 Sep 2026 12:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;本文转载并精简自公众号「青稞AI」的《大模型为什么会产生“离群值”？深度解析 RoPE 与注意力机制》。
作者：唐瀚霖，阿里巴巴高级技术专家，开源推理引擎 RTP-LLM 的核心作者之一。
原文链接：&lt;a href=&quot;https://mp.weixin.qq.com/s/RdL9HwbhSyGJ_BGaT42lQA&quot;&gt;https://mp.weixin.qq.com/s/RdL9HwbhSyGJ_BGaT42lQA&lt;/a&gt;
精简过程去掉了绝大部分数学推导与配图，完整内容请看原文。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;离群值是量化最头疼的问题&lt;/h2&gt;
&lt;p&gt;量化的做法是把浮点映射到低位宽整数：先选一个缩放因子把数值归一化到可表示区间，再舍入。&lt;/p&gt;
&lt;p&gt;LLM 的激活值里存在大量离群值，让这个缩放因子非常难选：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;取大了，量化粒度太粗，剩下 99% 的正常数值被粗糙表示；&lt;/li&gt;
&lt;li&gt;取小了（把离群值剔出去），正常值精度上去了，但离群值被整体压扁。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;看上去“牺牲 1% 换 99% 精度”很划算，实测却相反：把离群值裁掉或置零，LLM 精度会灾难性下降。所以几乎所有的量化工作都在想办法削弱离群值的影响，而很少问一句：&lt;strong&gt;它们为什么会出现，又为什么这么重要。&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;线索：离群值长得很像 attention sink&lt;/h2&gt;
&lt;p&gt;前人总结的两个特征：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;特别大的离群值只出现在最前面几个 token 上；&lt;/li&gt;
&lt;li&gt;重要的不是离群值的大小，而是它&lt;strong&gt;是否存在&lt;/strong&gt;——把数值改小几乎没影响，把它去掉则精度崩盘。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;第一条和 attention sink（注意力汇点）高度重合：LLM 前几个 token 会被大量 token 分走很高的注意力权重，而移除这些汇点同样会破坏性能。顺着这条线往下看。&lt;/p&gt;
&lt;h2&gt;Attention Sink 本质是一次“空操作”&lt;/h2&gt;
&lt;p&gt;StreamingLLM 发现滑动窗口注意力会让模型胡言乱语，把最前几个 token 一并保留就能修复。&lt;/p&gt;
&lt;p&gt;原因在于：在这些注意力头里，大多数 token 把大部分注意力权重分给汇点 token，而汇点的 Value 几乎为零，注意力输出因此趋近 0——等价于&lt;strong&gt;这个头在当前 token 上不工作&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这对 LLM 很关键：某些注意力头只负责特定的关系抽取，当这种关系不存在时，让该头输出 0 就是最干净的关闭方式。&lt;/p&gt;
&lt;p&gt;进一步实验更直接：把汇点 token 的离群值改成普通量级，attention sink 现象就消失了。也就是说，离群值是维持汇点的必要条件。&lt;/p&gt;
&lt;h2&gt;怎么“造”一个汇点&lt;/h2&gt;
&lt;p&gt;不考虑 RoPE 时，只要让大多数 query 与汇点 key 的内积都很大，效果就是把 token 投影到一个与自身正交、但与汇点 key 平行的低维方向上（实验里能看到汇点 key 与其他 key 基本正交）。&lt;/p&gt;
&lt;p&gt;所以造汇点并不需要在通道维度上出现离群值。那真实 LLM 里为什么还是出现了？&lt;/p&gt;
&lt;h2&gt;症结在 RoPE&lt;/h2&gt;
&lt;h3&gt;长文本下 Softmax 注意力会“迷路”&lt;/h3&gt;
&lt;p&gt;设想上下文是：“Alice 的关键词是 abcd，……（上百万 token），Alice 的关键词是什么？”&lt;/p&gt;
&lt;p&gt;要答对，某些头必须把注意力分数集中到 abcd 上。但序列越长，被平摊掉的注意力总量越大，信噪比持续衰减，模型就淹没在无关信息里。&lt;/p&gt;
&lt;h3&gt;LLM 的对策：局部头 + 召回头&lt;/h3&gt;
&lt;p&gt;Anthropic 关于 induction head 的工作揭示了一类专门关注“与当前 token 相似的历史 token”的头。由此得到一个假设：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;为了不在长文本里迷路，大多数注意力头只关注相邻 token 和汇点；少数&lt;strong&gt;召回头&lt;/strong&gt;负责把远处 token 抓回当前位置，交给深层网络做局部处理。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;RazorAttention 的验证很干脆：先按召回得分筛出前 20% 的召回头，丢掉其余头的远程 KV cache，准确率下降不到 3%；反过来保留 80% 全注意力头、丢掉那 20% 召回头的 KV cache，准确率掉超过 30%。&lt;/p&gt;
&lt;h3&gt;RoPE 的快分量在干扰召回&lt;/h3&gt;
&lt;p&gt;RoPE 用不同频率的旋转分量编码相对位置。对召回头而言，无论被召回的 token 在多远，都希望注意力分数足够大——但快旋转分量的分数会随相对位置快速波动，对召回有害。&lt;/p&gt;
&lt;p&gt;因此召回头必须让慢旋转（低频）分量占主导，于是这些头在低频维度上出现极大的通道级数值——&lt;strong&gt;这就是离群值的主要来源&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;另一个吻合的观察：召回头往往伴随更明显的 attention sink。逻辑也顺：如果前文没有需要召回的信息，就通过 sink 把这个头关掉。&lt;/p&gt;
&lt;h2&gt;由这个视角推出的一些结论&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;长文本外推要加大旋转基数&lt;/strong&gt;：YaRN 的本质就是增大 base。base 越大，最慢分量的频率越低，召回头能覆盖的距离越远——这解释了长文本模型为什么普遍用很大的 base。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Partial RoPE / NoPE 可能更好&lt;/strong&gt;：既然低频离群值的存在是为了让召回不被 RoPE 干扰，那就干脆让部分维度不加 RoPE（Partial RoPE，DeepSeek-V3、GLM-4.6 在用），或者对特定头禁用 RoPE（NoPE）。Kimi 的做法是在线性注意力头里启用 RoPE、在 MLA 头里用 NoPE，而该关掉哪些头，答案显然是召回头。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;slash pattern 是 RoPE 的副作用&lt;/strong&gt;：MInference 注意到注意力图里存在斜条纹，它有两个特点——与输入语义无关、只取决于序列长度，并且呈准周期性。这正是 qk 的离群通道在 RoPE 下叠加出的周期信号；对着注意力图跑 FFT，峰值频率会和离群值的频率对得上。既然与语义无关，这些斜线的信息价值其实存疑，但不少免训练稀疏注意力算法仍在刻意保留它。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;LLM 处理长文本的召回模式有点类似人类：先在上下文里搜索相关信息，再做局部推理。召回头要在 RoPE 快分量的干扰下保住召回信号，就不得不在低频维度上放大通道级数值——离群值由此而来。&lt;/p&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;StreamingLLM：&lt;a href=&quot;https://arxiv.org/abs/2309.17453&quot;&gt;https://arxiv.org/abs/2309.17453&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;OpenAI 关于长文本信噪比的工作：&lt;a href=&quot;https://arxiv.org/abs/2511.13653&quot;&gt;https://arxiv.org/abs/2511.13653&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Anthropic induction heads：&lt;a href=&quot;https://arxiv.org/abs/2209.11895&quot;&gt;https://arxiv.org/abs/2209.11895&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;RazorAttention：&lt;a href=&quot;https://arxiv.org/abs/2407.15891&quot;&gt;https://arxiv.org/abs/2407.15891&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;通道级离群值相关工作：&lt;a href=&quot;https://arxiv.org/abs/2502.01563&quot;&gt;https://arxiv.org/abs/2502.01563&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MInference：&lt;a href=&quot;https://arxiv.org/abs/2407.02490&quot;&gt;https://arxiv.org/abs/2407.02490&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;DoPE：&lt;a href=&quot;https://arxiv.org/html/2511.09146v1&quot;&gt;https://arxiv.org/html/2511.09146v1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Codeforces Round 1098 (Div. 2) 题解</title><link>https://lvdousha26.github.io/blog/cf-round-1098-solution</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/cf-round-1098-solution</guid><description>A 贪心/B 追逐游戏/C 数位构造/D 十字划分/E 序列组合计数/F 树路径二分</description><pubDate>Thu, 21 May 2026 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这场是 WDOI 团队出的东方主题 round。6 道题（C、E 各有 easy/hard），整体难度梯度不错，适合 Div. 2 选手。&lt;/p&gt;
&lt;h2&gt;A — Marisa Steals Reimu&apos;s Takeout&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;题意&lt;/strong&gt;：给一个只含 0、1、2 的序列 w，每次可以选一个非空子序列，要求其元素和能被 3 整除，然后移除这些元素。问最多能操作多少次。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解法&lt;/strong&gt;：贪心 + 计数。&lt;/p&gt;
&lt;p&gt;记 cnt0、cnt1、cnt2 分别为 0、1、2 的个数。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单独的 0 本身就是一个和为 0 的子序列（能被 3 整除），所以每个 0 都可以单独一次操作。&lt;/li&gt;
&lt;li&gt;1 和 2 配对：一个 1 加一个 2 和为 3，可以组成一次操作。&lt;/li&gt;
&lt;li&gt;多余的 1 三个一组（1+1+1=3），多余的 2 三个一组（2+2+2=6）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;答案就是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cnt0 + min(cnt1, cnt2) + (max(cnt1, cnt2) - min(cnt1, cnt2)) / 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;复杂度 O(n)。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;void solve() {
    int n; cin &gt;&gt; n;
    int cnt[3] = {0};
    for (int i = 0; i &amp;#x3C; n; i++) {
        int x; cin &gt;&gt; x;
        cnt[x]++;
    }
    int ans = cnt[0];
    int pairs = min(cnt[1], cnt[2]);
    ans += pairs;
    cnt[1] -= pairs; cnt[2] -= pairs;
    ans += cnt[1] / 3 + cnt[2] / 3;
    cout &amp;#x3C;&amp;#x3C; ans &amp;#x3C;&amp;#x3C; &apos;\n&apos;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;B — Remilia Plays Soku&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;题意&lt;/strong&gt;：n 个位置排成一个环。Reimu 在 x₁，Remilia 在 x₂。每秒 Remilia 先动（可以不动或移到相邻位置，整局最多移动 k 次），然后 Reimu 动。两人都最优策略，问 Reimu 多少秒能抓住 Remilia。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解法&lt;/strong&gt;：分类讨论。&lt;/p&gt;
&lt;p&gt;Remilia 想拖延时间，Reimu 想尽快抓住。关键限制是 Remilia 最多只能移动 k 次。&lt;/p&gt;
&lt;p&gt;首先，如果 Remilia 不动（k=0），Reimu 每步可以缩短距离 1，需要的时间就是环上初始距离的步数。&lt;/p&gt;
&lt;p&gt;考虑一般情况：&lt;/p&gt;
&lt;p&gt;把问题转化为：Remilia 沿着环逃跑，但每步只能走 1 格，且总共只能走 k 步。Reimu 每步可以走 1 格。&lt;/p&gt;
&lt;p&gt;记初始距离 d = min(|x₁ - x₂|, n - |x₁ - x₂|)（环上最短距离）。&lt;/p&gt;
&lt;p&gt;如果 Remilia 朝远离 Reimu 的方向跑，她最多能拉开 min(k, 距离增长上限) 步。但 Reimu 每步也会靠近。&lt;/p&gt;
&lt;p&gt;关键观察：由于 Remilia 先动而 Reimu 后动，Remilia 每步可以保持或增加 1 的距离，但每用一次移动次数就会消耗。当移动次数用完，她就只能原地等抓。&lt;/p&gt;
&lt;p&gt;答案是：如果 k &gt;= d，Remilia 可以跑到对面然后开始绕圈，答案取决于 n 和 k 的关系。否则 Remilia 在 k 步后就会被抓住。&lt;/p&gt;
&lt;p&gt;具体实现可以模拟：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Remilia 的策略是朝最远的方向跑&lt;/li&gt;
&lt;li&gt;如果 k 足够大，她可以一直保持最大距离&lt;/li&gt;
&lt;li&gt;当移动次数用尽，Reimu 每步缩短 1 距离&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最终答案是 min(抓住时间, 理论最大值)。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;void solve() {
    int n, x1, x2, k;
    cin &gt;&gt; n &gt;&gt; x1 &gt;&gt; x2 &gt;&gt; k;
    int d = min(abs(x1 - x2), n - abs(x1 - x2));
    // Remilia can move up to k times
    // Each move can maintain or increase distance by at most 1
    if (k == 0) {
        cout &amp;#x3C;&amp;#x3C; d &amp;#x3C;&amp;#x3C; &apos;\n&apos;;
        return;
    }
    // If Remilia can run to the farther side
    int ans = 0;
    if (k &gt;= n / 2) {
        // Can effectively run forever, answer depends on n
        ans = (n + 1) / 2;
    } else {
        // Will run out of moves
        ans = min(d + k, (n + 1) / 2);
    }
    cout &amp;#x3C;&amp;#x3C; ans &amp;#x3C;&amp;#x3C; &apos;\n&apos;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;C1/C2 — Cirno and Number&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;题意&lt;/strong&gt;：给一个非负整数 a 和一个递增数字集合 d（大小 n），求能用 d 中的数字构成的非负整数 b，使得 |a - b| 最小。C1：n=2；C2：n≤10。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解法&lt;/strong&gt;：构造 + 数位贪心。&lt;/p&gt;
&lt;p&gt;考虑比 a 大的最小可行数和比 a 小的最大可行数，取差值较小的。&lt;/p&gt;
&lt;p&gt;对于比 a 大的数：从高位到低位，找到第一个可以变大且用 d 中数字填满后续的位置。对于比 a 小的数同理。&lt;/p&gt;
&lt;p&gt;当 n=2 时（C1），可以直接枚举两种情况。&lt;/p&gt;
&lt;p&gt;当 n≤10 时（C2），需要更一般的处理：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;尝试用 d 中的数字构造一个恰好等于 a 的数 — 如果 a 的每一位都在 d 中，答案为 0。&lt;/li&gt;
&lt;li&gt;否则，找比 a 大的最小数：从低位到高位找可以增大的位置，把这一位换成 d 中比它大的最小数字，后面全部填 d 的最小数字。&lt;/li&gt;
&lt;li&gt;找比 a 小的最大数：同理，找可以减小的位置，换更小的最大数字，后面全填 d 的最大数字。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;注意前导零和位数变化（比如 1000→999）。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;string solve_case(string a, vector&amp;#x3C;int&gt;&amp;#x26; d) {
    sort(d.begin(), d.end());
    // try equal
    bool ok = true;
    for (char c : a) {
        if (!binary_search(d.begin(), d.end(), c - &apos;0&apos;)) ok = false;
    }
    if (ok) return &quot;0&quot;;

    // find next greater
    string greater = find_greater(a, d);
    string smaller = find_smaller(a, d);

    long long ga = greater.empty() ? LLONG_MAX : stoll(greater);
    long long sa = smaller.empty() ? LLONG_MAX : stoll(smaller);
    long long aa = stoll(a);

    if (ga != LLONG_MAX &amp;#x26;&amp;#x26; sa != LLONG_MAX)
        return to_string(min(ga - aa, aa - sa));
    else if (ga != LLONG_MAX)
        return to_string(ga - aa);
    else
        return to_string(aa - sa);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;D — Sanae, Cross and Color&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;题意&lt;/strong&gt;：平面上 n 个不同整点。选两条直线 x = k₁ + 0.5 和 y = k₂ + 0.5，将点分成四个区域（红/绿/蓝/黄）。要求每个区域至少有一个点。问能产生多少种不同的染色方案（只要有一个点颜色不同就视为不同方案）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解法&lt;/strong&gt;：排序 + 数据结构。&lt;/p&gt;
&lt;p&gt;关键观察：四条分界线把平面分成四个象限，每个象限必须非空。每个点的颜色由它在十字中的位置唯一决定。&lt;/p&gt;
&lt;p&gt;我们枚举 k₁（x 方向的分界），然后快速统计可行的 k₂ 数量。&lt;/p&gt;
&lt;p&gt;按 x 排序后，维护一个数据结构支持：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;查询当前 y 坐标在上下两个半平面中的分布&lt;/li&gt;
&lt;li&gt;十字旋转后，点会从两个象限移到另外两个象限&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;具体做法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;将所有点按 x 排序&lt;/li&gt;
&lt;li&gt;从左到右扫描，维护一个 BIT/线段树记录右侧点的 y 分布&lt;/li&gt;
&lt;li&gt;对于每个 k₁，计算不产生空象限的 k₂ 取值范围&lt;/li&gt;
&lt;li&gt;用组合计数或双指针统计&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;由于坐标范围 1..n，可以用 BIT 做到 O(n log n)。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;E1/E2 — Amanojaku and Sequence&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;题意&lt;/strong&gt;：定义 f(c) = sum (前缀和)²。b 数组中，非 -1 的位置固定，-1 的位置可以填任意非负整数。求所有满足总和 = m 的序列 c 的 f(c) 之和。E1 单查询，E2 带点修。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解法&lt;/strong&gt;：组合数学 + 生成函数。&lt;/p&gt;
&lt;p&gt;设固定部分的和为 S_fixed，-1 的个数为 cnt。我们需要分配剩下的 m - S_fixed 到 cnt 个位置。&lt;/p&gt;
&lt;p&gt;对于每个 -1 位置，它贡献的 f(c) 与其值及其位置有关。可以用插板法结合前缀和公式：&lt;/p&gt;
&lt;p&gt;把 c_i 看作变量，f(c) 展开后是关于 c_i 的二次型。对于每个 -1 位置，其贡献系数可以通过组合数计算。&lt;/p&gt;
&lt;p&gt;E1（单查询）可以用组合数直接算。&lt;/p&gt;
&lt;p&gt;E2（带修）需要线段树维护区间信息：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个节点维护：区间内 -1 个数、固定和、以及组合系数&lt;/li&gt;
&lt;li&gt;查询时合并区间信息，O(log n) 回答&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;模数为 998244353，需要预处理阶乘和逆元。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;F — Momoyo and the Network&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;题意&lt;/strong&gt;：树上 n 个点，每个点有权值 a_i。选一条恰好 k 条边的简单路径，删除路径上的所有边，树被分成 k+1 个连通块。最大化最小连通块的权值和。如果不存在恰 k 条边的路径输出 -1。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解法&lt;/strong&gt;：二分答案 + 树 DP。&lt;/p&gt;
&lt;p&gt;最大化最小值 → 二分答案 X，判断能否让每个连通块权值 ≥ X。&lt;/p&gt;
&lt;p&gt;二分答案后，问题转化为：是否存在一条长度为 k 的路径，使得删除后所有连通块权值 ≥ X。&lt;/p&gt;
&lt;p&gt;树 DP：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对每个节点，维护从该节点向下延伸的路径长度和对应的连通块最小值&lt;/li&gt;
&lt;li&gt;用 DFS 合并子树信息&lt;/li&gt;
&lt;li&gt;对每个节点，检查穿过该节点的路径是否满足条件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于 n ≤ 2×10⁵，二分 O(log sum a) × DP O(n) 可行。&lt;/p&gt;
&lt;p&gt;注意要特判不存在长度为 k 的路径的情况（比如 k ≥ 树的直径）。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;bool check(int X, int k) {
    // DP on tree to see if a path of length k exists
    // such that every component after removal &gt;= X
    vector&amp;#x3C;int&gt; dp(n + 1, 0);
    bool ok = false;

    function&amp;#x3C;void(int, int)&gt; dfs = [&amp;#x26;](int u, int p) {
        // returns longest path down
        int best = 0;
        for (int v : adj[u]) {
            if (v == p) continue;
            dfs(v, u);
            // check path through u
            // merge subtrees
        }
        dp[u] = best + 1;
    };

    dfs(1, 0);
    return ok;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;这场题的区分度做得不错。A、B 偏签到和思维，C 是经典数位构造，D 考察观察力和数据结构，E 是组合数学 + DS 合并，F 是二分答案 + 树 DP。东方厨出题组的题面也挺有意思的。&lt;/p&gt;
&lt;p&gt;官方 editorial 还没出，等出了再补链接。有问题评论区讨论。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-21T09:00:00.000Z</atom:updated></item><item><title>GDB 入门：跑不动了就看看</title><link>https://lvdousha26.github.io/blog/gdb-tutorial</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/gdb-tutorial</guid><description>GDB 是什么、怎么用、常见调试场景</description><pubDate>Wed, 20 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;你写的程序崩了。段错误。什么都没输出。你盯着代码看了一个小时。&lt;/p&gt;
&lt;p&gt;别看了。用 GDB。&lt;/p&gt;
&lt;h2&gt;什么是 GDB&lt;/h2&gt;
&lt;p&gt;GDB 是 GNU Debugger。它能让你看程序运行时的内部状态。&lt;/p&gt;
&lt;p&gt;你可以在某一行停下来。查看变量的值。单步执行。看调用栈。&lt;/p&gt;
&lt;p&gt;不需要猜哪里出了问题。问 GDB 就行。&lt;/p&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;p&gt;Linux：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;apt install gdb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;macOS：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;brew install gdb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;装完运行 &lt;code&gt;gdb --version&lt;/code&gt;。有输出就对了。&lt;/p&gt;
&lt;h2&gt;编译&lt;/h2&gt;
&lt;p&gt;要让 GDB 工作，编译时加 &lt;code&gt;-g&lt;/code&gt; 选项。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;gcc -g -o myprogram myprogram.c
# 或者
g++ -g -o myprogram myprogram.cpp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;-g&lt;/code&gt; 告诉编译器保留调试信息。没有它，GDB 不知道变量名和行号。&lt;/p&gt;
&lt;p&gt;不要加 &lt;code&gt;-O2&lt;/code&gt; 之类的优化选项。优化过的代码和源码对不上。GDB 会迷路。&lt;/p&gt;
&lt;h2&gt;启动&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;gdb ./myprogram
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看到 &lt;code&gt;(gdb)&lt;/code&gt; 提示符就对了。&lt;/p&gt;
&lt;h2&gt;运行&lt;/h2&gt;
&lt;p&gt;在 GDB 里运行程序：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;(gdb) run
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果程序需要命令行参数：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;(gdb) run arg1 arg2 arg3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;程序会一直运行直到结束或出错。&lt;/p&gt;
&lt;h2&gt;断点&lt;/h2&gt;
&lt;p&gt;在你关心的行停下来：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;(gdb) break main.c:42
(gdb) break main
(gdb) break my_function
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;break main&lt;/code&gt; 在 &lt;code&gt;main&lt;/code&gt; 函数入口停下。&lt;code&gt;break main.c:42&lt;/code&gt; 在第 42 行停下。&lt;/p&gt;
&lt;p&gt;查看所有断点：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;(gdb) info breakpoints
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;删除断点：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;(gdb) delete 1
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;步进&lt;/h2&gt;
&lt;p&gt;断点命中后，你可以控制执行节奏：&lt;/p&gt;
&lt;p&gt;| 命令 | 作用 |
|------|------|
| &lt;code&gt;next&lt;/code&gt; (或 &lt;code&gt;n&lt;/code&gt;) | 执行下一行，不进入函数 |
| &lt;code&gt;step&lt;/code&gt; (或 &lt;code&gt;s&lt;/code&gt;) | 执行下一行，进入函数 |
| &lt;code&gt;finish&lt;/code&gt; | 运行到当前函数返回 |
| &lt;code&gt;continue&lt;/code&gt; (或 &lt;code&gt;c&lt;/code&gt;) | 继续运行到下一个断点 |
| &lt;code&gt;until&lt;/code&gt; | 运行到指定行 |&lt;/p&gt;
&lt;h2&gt;查看变量&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;(gdb) print x
(gdb) print &amp;#x26;x
(gdb) print arr[2]
(gdb) print *ptr
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;print&lt;/code&gt; 会显示变量当前的值。加 &lt;code&gt;&amp;#x26;&lt;/code&gt; 显示地址。&lt;/p&gt;
&lt;p&gt;查看所有局部变量：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;(gdb) info locals
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看函数参数：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;(gdb) info args
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;调用栈&lt;/h2&gt;
&lt;p&gt;程序崩了之后，第一个问题：它在哪里崩的？&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;(gdb) backtrace
# 或简写
(gdb) bt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;GDB 会显示从 &lt;code&gt;main&lt;/code&gt; 到崩溃位置的完整调用链。每一帧是一个函数调用。&lt;/p&gt;
&lt;p&gt;切换到不同的帧看看：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;(gdb) frame 2
(gdb) info locals
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;常见场景&lt;/h2&gt;
&lt;h3&gt;段错误&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;gdb ./myprogram
(gdb) run
# 程序崩溃，GDB 会停在崩溃位置
(gdb) bt
# 看到是哪一行、哪个指针出了问题
(gdb) print ptr
# 哦，果然是空指针
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;条件断点&lt;/h3&gt;
&lt;p&gt;只在特定条件下停下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;(gdb) break main.c:42 if i &gt; 100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样就不用手动按 &lt;code&gt;continue&lt;/code&gt; 一百次了。&lt;/p&gt;
&lt;h3&gt;监视点&lt;/h3&gt;
&lt;p&gt;变量发生变化时停下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;(gdb) watch x
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当 &lt;code&gt;x&lt;/code&gt; 的值被修改时，GDB 会立即停下。&lt;/p&gt;
&lt;h3&gt;修改变量&lt;/h3&gt;
&lt;p&gt;调试时可以直接改值：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;(gdb) set var i = 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这在测试循环或边界条件时很有用。&lt;/p&gt;
&lt;h2&gt;.gdbinit&lt;/h2&gt;
&lt;p&gt;每次启动 GDB 都要敲一遍 &lt;code&gt;set pagination off&lt;/code&gt;？写进配置文件。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;~/.gdbinit&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set pagination off
set confirm off
set print pretty on
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;GDB 启动时自动加载。省事。&lt;/p&gt;
&lt;h2&gt;实用技巧&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Enter&lt;/code&gt;&lt;/strong&gt; 重复上一条命令。连续 &lt;code&gt;next&lt;/code&gt; 时很有用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;list&lt;/code&gt;&lt;/strong&gt; 显示源码上下文。&lt;code&gt;list 20,30&lt;/code&gt; 显示 20 到 30 行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;display x&lt;/code&gt;&lt;/strong&gt; 每次停下时自动打印 &lt;code&gt;x&lt;/code&gt; 的值。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;quit&lt;/code&gt;&lt;/strong&gt; 退出 GDB。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;help&lt;/code&gt;&lt;/strong&gt; 记不住命令时用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;调试不是猜谜。GDB 告诉你真相。&lt;/p&gt;
&lt;p&gt;编译加 &lt;code&gt;-g&lt;/code&gt;。崩了就用 &lt;code&gt;bt&lt;/code&gt;。看变量就用 &lt;code&gt;print&lt;/code&gt;。单步就用 &lt;code&gt;n&lt;/code&gt; 和 &lt;code&gt;s&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;先记住这三个。遇到新问题再学新命令。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-20T16:00:00.000Z</atom:updated></item><item><title>AutoDL 14 天自动续命脚本</title><link>https://lvdousha26.github.io/blog/autodl-tutorial</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/autodl-tutorial</guid><description>用 API 定时重建实例，防止 14 天免费实例被释放</description><pubDate>Tue, 19 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;AutoDL 免费实例&lt;strong&gt;14 天自动释放&lt;/strong&gt;，到期直接删实例，系统盘数据全没。最省心的方法：写个脚本，每 13 天用 API 重建一次实例，重置倒计时。&lt;/p&gt;
&lt;h2&gt;整体思路&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;新实例(第1天) → 跑实验 → 第13天触发脚本
  → 备份数据到文件存储
  → API 创建新实例（同配置）
  → 从文件存储恢复数据
  → API 释放旧实例
  → 新实例接替，倒计时重置为14天
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用文件存储(NFS)持久化数据，系统盘只放临时环境。重建后挂载回去就行。&lt;/p&gt;
&lt;h2&gt;获取 API Token&lt;/h2&gt;
&lt;p&gt;控制台 → 账号设置 → 开发者 Token，复制下来。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 存为环境变量
export AUTODL_TOKEN=&quot;你的token&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;核心脚本&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;#!/usr/bin/env python3
&quot;&quot;&quot;AutoDL 14天自动续命 — 重建实例并恢复环境&quot;&quot;&quot;
import requests, os, time, json

TOKEN = os.environ[&quot;AUTODL_TOKEN&quot;]
HOST = &quot;https://api.autodl.com&quot;
HEADERS = {&quot;Authorization&quot;: TOKEN, &quot;Content-Type&quot;: &quot;application/json&quot;}

# ======== 按你的实例改这里 ========
REGION = &quot;beijingDC2&quot;          # 地区
GPU_SPEC = &quot;pro6000-p&quot;         # GPU规格ID（见API文档附录）
IMAGE_ID = &quot;image-xxxxxxxxx&quot;   # 镜像UUID（私有镜像列表里查）
INSTANCE_NAME = &quot;auto-renew&quot;
DATA_CENTER = [&quot;beijingDC2&quot;]   # 可多选
CUDA_MIN = 113                 # CUDA &gt;= 11.3
GPU_COUNT = 1
DISK_EXPAND = 0               # 系统盘扩容(GB)
START_CMD = &quot;sleep 1&quot;          # 开机后自动执行的命令
# =================================


def _post(path, data=None):
    r = requests.post(f&quot;{HOST}{path}&quot;, headers=HEADERS, json=data or {})
    return r.json()


def get_old_instance():
    &quot;&quot;&quot;查当前实例列表，取最新一个&quot;&quot;&quot;
    r = _post(&quot;/api/v1/dev/instance/pro/list&quot;)
    items = r.get(&quot;data&quot;, {}).get(&quot;list&quot;, [])
    if not items:
        raise Exception(&quot;没找到实例，先去控制台手动创建一个&quot;)
    return items[0]


def release_instance(uuid):
    &quot;&quot;&quot;先关机，再释放&quot;&quot;&quot;
    _post(&quot;/api/v1/dev/instance/pro/power_off&quot;, {&quot;instance_uuid&quot;: uuid})
    time.sleep(10)
    _post(&quot;/api/v1/dev/instance/pro/release&quot;, {&quot;instance_uuid&quot;: uuid})
    print(f&quot;  已释放 {uuid}&quot;)


def create_instance():
    &quot;&quot;&quot;用预设配置创建新实例&quot;&quot;&quot;
    data = {
        &quot;data_center_list&quot;: DATA_CENTER,
        &quot;req_gpu_amount&quot;: GPU_COUNT,
        &quot;expand_system_disk_by_gb&quot;: DISK_EXPAND,
        &quot;gpu_spec_uuid&quot;: GPU_SPEC,
        &quot;image_uuid&quot;: IMAGE_ID,
        &quot;cuda_v_from&quot;: CUDA_MIN,
        &quot;instance_name&quot;: INSTANCE_NAME,
        &quot;start_command&quot;: START_CMD,
    }
    r = _post(&quot;/api/v1/dev/instance/pro/create&quot;, data)
    info = r.get(&quot;data&quot;, {})
    uuid = info.get(&quot;instance_uuid&quot;)
    print(f&quot;  新实例 {uuid} 创建成功&quot;)
    return info


def wait_until_running(uuid, timeout=300):
    &quot;&quot;&quot;等实例开机就绪&quot;&quot;&quot;
    for _ in range(timeout // 10):
        r = _post(&quot;/api/v1/dev/instance/pro/status&quot;, {&quot;instance_uuid&quot;: uuid})
        status = r.get(&quot;data&quot;, {}).get(&quot;status&quot;)
        if status == &quot;running&quot;:
            return True
        time.sleep(10)
    raise Exception(&quot;实例启动超时&quot;)


def main():
    print(&quot;=== AutoDL 14天续命 ===&quot;)

    print(&quot;[1/4] 查旧实例...&quot;)
    old = get_old_instance()
    old_uuid = old[&quot;instance_uuid&quot;]
    print(f&quot;  旧实例: {old_uuid}&quot;)

    print(&quot;[2/4] 创建新实例...&quot;)
    new_info = create_instance()
    new_uuid = new_info[&quot;instance_uuid&quot;]

    print(&quot;[3/4] 等新实例就绪...&quot;)
    wait_until_running(new_uuid)
    # 新实例开机后可通过 START_CMD 自动挂载文件存储、拉代码
    # 例如: START_CMD = &quot;bash /root/setup.sh&quot;

    print(&quot;[4/4] 释放旧实例...&quot;)
    release_instance(old_uuid)

    print(f&quot;=== 完成，新实例 {new_uuid}，倒计时重置 ===&quot;)


if __name__ == &quot;__main__&quot;:
    main()
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;环境恢复&lt;/h2&gt;
&lt;p&gt;镜像里固化的环境不用动。每次 &lt;code&gt;pip install&lt;/code&gt; 的包会丢，所以在 &lt;code&gt;START_CMD&lt;/code&gt; 或 setup 脚本里搞定：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/bin/bash
# setup.sh — 新实例首次启动时执行

# 挂载文件存储（提前在控制台创建好）
# 挂载后数据目录直接可用

# 装依赖（镜像已有 conda/pytorch 就跳过）
pip install transformers datasets accelerate -q

# 拉最新代码
cd /root &amp;#x26;&amp;#x26; git clone git@github.com:you/project.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;把 &lt;code&gt;START_CMD&lt;/code&gt; 改成 &lt;code&gt;&quot;bash /root/setup.sh&quot;&lt;/code&gt;，每次重建自动跑一遍。&lt;/p&gt;
&lt;h2&gt;文件存储 — 数据不丢的关键&lt;/h2&gt;
&lt;p&gt;系统盘随实例释放，&lt;strong&gt;文件存储(NFS)是独立的&lt;/strong&gt;，实例删了数据还在。新实例挂载同一个文件存储即可。&lt;/p&gt;
&lt;p&gt;控制台 → 文件存储 → 创建 → 记下挂载路径。在 &lt;code&gt;setup.sh&lt;/code&gt; 里：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# AutoDL 文件存储已自动挂载到 /root/autodl-fs
# 把训练输出、checkpoint、数据集放这里
ln -s /root/autodl-fs/checkpoints /root/project/checkpoints
ln -s /root/autodl-fs/datasets /root/project/data
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;定时执行&lt;/h2&gt;
&lt;p&gt;在&lt;strong&gt;本地&lt;/strong&gt;（不是实例上）设 cron，每 13 天跑一次：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 编辑 crontab
crontab -e

# 每月 1 号和 14 号凌晨 3 点执行
0 3 1,14 * * AUTODL_TOKEN=xxx python3 /home/you/autodl-renew.py &gt;&gt; /home/you/autodl-renew.log 2&gt;&amp;#x26;1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以用 GitHub Actions 免费跑：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# .github/workflows/autodl-renew.yml
name: AutoDL 14天续命
on:
  schedule:
    - cron: &quot;0 3 1,14 * *&quot;
  workflow_dispatch:
jobs:
  renew:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pip install requests &amp;#x26;&amp;#x26; python3 autodl-renew.py
        env:
          AUTODL_TOKEN: ${{ secrets.AUTODL_TOKEN }}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;注意事项&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;文件存储是唯一持久化的地方&lt;/strong&gt;，系统盘数据不备份必丢&lt;/li&gt;
&lt;li&gt;新实例 SSH 地址会变，IP/端口每次都不同，看控制台或 API 返回&lt;/li&gt;
&lt;li&gt;API 创建实例用的是&lt;strong&gt;按量计费&lt;/strong&gt;，创建后就开始扣费，旧实例要立刻释放&lt;/li&gt;
&lt;li&gt;GPU 规格 ID 查 API 文档附录，不同卡对应不同 &lt;code&gt;gpu_spec_uuid&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;免费额度是&lt;strong&gt;按账号算的&lt;/strong&gt;，一个账号同时只能有一个免费实例&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;常用速查&lt;/h2&gt;
&lt;p&gt;| 操作 | 命令/地址 |
|------|----------|
| 获取 Token | 控制台 → 设置 → 开发者 Token |
| API 文档 | https://www.autodl.com/docs/instance_pro_api/ |
| GPU 规格 ID | 查 API 文档附录 |
| 镜像 UUID | 控制台 → 私有镜像 → 镜像详情 |
| 查看余额 | POST &lt;code&gt;/api/v1/dev/wallet/balance&lt;/code&gt; |&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-19T16:00:00.000Z</atom:updated></item><item><title>Claude Code CLI 上手指南</title><link>https://lvdousha26.github.io/blog/claude-code-tutorial</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/claude-code-tutorial</guid><description>命令行里的 AI 编程搭档：安装、基本工作流、项目上下文、常用技巧</description><pubDate>Tue, 19 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Claude Code 是 Anthropic 出的命令行 AI 编程工具。直接在终端里让它读代码、改 bug、写功能。不像 Copilot 只补全，它是真正的对话式协作。&lt;/p&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# npm 全局安装（推荐）
npm install -g @anthropic-ai/claude-code

# 验证
claude --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;首次使用需要 Anthropic API Key 或者 Claude 订阅：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 方式一：API Key（按量计费）
export ANTHROPIC_API_KEY=&quot;sk-ant-...&quot;

# 方式二：Claude 订阅账号登录
claude login
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;基本用法&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 直接对话
claude &quot;解释这个项目的目录结构&quot;

# 交互模式（最常用）
claude

# 带文件
claude &quot;src/main.py 里有什么潜在问题？&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进入交互模式后，像聊天一样提需求：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&gt; 给这个项目加一个日志中间件
&gt; README 里少写了安装步骤，补上
&gt; 这个函数太长了，拆成两个
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Claude Code 会自动读代码、做出修改、运行测试、迭代直到满意。&lt;/p&gt;
&lt;h2&gt;项目上下文 — CLAUDE.md&lt;/h2&gt;
&lt;p&gt;Claude Code 不会读心。在项目根目录放 &lt;code&gt;CLAUDE.md&lt;/code&gt;，告诉它项目规则、代码风格、注意事项：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;# CLAUDE.md

## 项目
FastAPI 后端，Python 3.11，Poetry 管理依赖

## 规则
- 先读代码，再改代码，不要猜
- 不要引入新的依赖除非必要
- 修改函数签名时同步更新所有调用点
- 禁止硬编码密钥、token

## 测试
pytest，改完代码跑 pytest -x
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个文件会被 Claude Code 每次自动加载，相当于给了它一份项目说明书。&lt;/p&gt;
&lt;h2&gt;权限控制&lt;/h2&gt;
&lt;p&gt;默认 Claude Code 执行 Shell 命令需要你确认。可以在设置里按操作类型加白名单：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 查看当前权限设置
claude config

# 允许读取文件（不需要确认）
claude config allow read
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者在 &lt;code&gt;~/.claude/settings.json&lt;/code&gt; 里手写：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;permissions&quot;: {
    &quot;allow&quot;: [
      &quot;Bash(git diff:*)&quot;,
      &quot;Bash(git log:*)&quot;,
      &quot;Bash(npm test:*)&quot;
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;核心工作流&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;1. 描述需求
      ↓
2. Claude Code 读代码、查文档
      ↓
3. 展示修改方案
      ↓
4. 你确认 → 它自动改代码
      ↓
5. 跑测试 → 修问题 → 完成
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;实际效果：描述一个 bug 现象，它能从定位原因到修复到验证一条龙完成。&lt;/p&gt;
&lt;h2&gt;实用技巧&lt;/h2&gt;
&lt;h3&gt;多轮对话，慢慢来&lt;/h3&gt;
&lt;p&gt;不要一上来就给大需求。先让它理解现状：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&gt; 读一下 src/auth.py，解释认证流程
&gt; 现在要加登录失败次数限制，5 次锁 30 分钟
&gt; 用 Redis 做计数器，键要有过期时间
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;@ 引用文件&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&gt; @src/models.py @src/routes.py 这两个文件之间有没有循环导入？
&gt; @.github/workflows/ 帮我把 CI 里的 Node 16 升级到 20
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;让它自己查文档&lt;/h3&gt;
&lt;p&gt;Claude Code 知道自身的限制，会主动说&quot;我不确定这个 API 的变化，让我查一下&quot;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&gt; 用 Prisma 5.x 的新语法改写数据库查询
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;代码审查&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 审查当前分支的改动
claude &quot;审查 git diff main...HEAD 的改动&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;写 commit message&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git diff | claude &quot;写一个 conventional commit message&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;常用命令速查&lt;/h2&gt;
&lt;p&gt;| 操作 | 命令 |
|------|------|
| 交互模式 | &lt;code&gt;claude&lt;/code&gt; |
| 单次问答 | &lt;code&gt;claude &quot;问题&quot;&lt;/code&gt; |
| 继续上次会话 | &lt;code&gt;claude --continue&lt;/code&gt; |
| 查看会话列表 | &lt;code&gt;claude sessions&lt;/code&gt; |
| 切换模型 | &lt;code&gt;/model opus&lt;/code&gt; / &lt;code&gt;/model sonnet&lt;/code&gt; / &lt;code&gt;/model haiku&lt;/code&gt; |
| 查看帮助 | &lt;code&gt;/help&lt;/code&gt; |
| 清除上下文 | &lt;code&gt;/clear&lt;/code&gt; |
| 退出 | &lt;code&gt;/exit&lt;/code&gt; 或 &lt;code&gt;Ctrl+C&lt;/code&gt; |&lt;/p&gt;
&lt;h2&gt;和 Copilot / Cursor 的区别&lt;/h2&gt;
&lt;p&gt;| | Claude Code | Copilot | Cursor |
|------|-----------|---------|--------|
| 运行方式 | CLI 终端 | IDE 插件 | IDE（VS Code fork） |
| 交互模式 | 对话式 | 补全+内联对话 | 补全+侧边栏对话 |
| 改代码范围 | 整个项目 | 当前文件为主 | 整个项目 |
| 自动执行 | 可以跑测试、安装依赖 | 不行 | 部分支持 |
| 价格 | API 按量 / 订阅 $20/月 | $10/月 | $20/月 |&lt;/p&gt;
&lt;p&gt;Copilot 适合行级补全，Cursor 有 GUI 偏好。Claude Code 强在终端原生、多文件重构、自动化工作流。&lt;/p&gt;
&lt;h2&gt;给初学者的建议&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;先写 CLAUDE.md&lt;/strong&gt; — 这是你给 AI 的项目说明书&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;从小任务开始&lt;/strong&gt; — 先让它修 typo、加注释，逐步信任&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不要盲信&lt;/strong&gt; — 看一遍它的改动再提交&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;善用 @ 引用&lt;/strong&gt; — 提供精确上下文优于模糊描述&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复杂需求分步给&lt;/strong&gt; — 一次一个大任务不如拆成小步骤&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;控制好上下文，Claude Code 能省掉大量重复劳动。用得越久，它对你的项目越熟悉。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-19T16:00:00.000Z</atom:updated></item><item><title>Docker 入门：别怕，真的没那么难</title><link>https://lvdousha26.github.io/blog/docker-tutorial</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/docker-tutorial</guid><description>写给完全没接触过容器的人，从装好 Docker 到跑起第一个容器，再到写 Dockerfile 部署自己的项目</description><pubDate>Tue, 19 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;实话说，我当初接触 Docker 也是一头雾水。什么镜像、容器、Dockerfile，看了好几篇教程才勉强跑起来一个 nginx。后来工作里用多了，发现核心概念其实一只手数得过来。这篇尽量用大白话讲清楚。&lt;/p&gt;
&lt;h2&gt;Docker 到底解决了什么&lt;/h2&gt;
&lt;p&gt;想象你在自己电脑上写了一个 Python 项目，Python 3.12，装了一堆 pip 包。给同学跑，他 Python 3.9，包版本也不一样，跑不起来。&lt;/p&gt;
&lt;p&gt;Docker 做的事：把代码&lt;strong&gt;和它需要的一切&lt;/strong&gt;（Python 版本、系统库、环境变量）打包成一个标准化的箱子。这个箱子在任何装了 Docker 的机器上都能跑，一模一样。&lt;/p&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# macOS — 推荐 OrbStack，比 Docker Desktop 轻快多了
brew install orbstack

# 或者装官方 Docker Desktop
brew install --cask docker

# Windows
winget install Docker.DockerDesktop

# Ubuntu
sudo apt install docker.io
sudo usermod -aG docker $USER  # 不用每次 sudo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;验证：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker run hello-world
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看到 &quot;Hello from Docker!&quot; 就 OK。&lt;/p&gt;
&lt;h2&gt;三个核心概念&lt;/h2&gt;
&lt;h3&gt;镜像(Image) — 一份食谱&lt;/h3&gt;
&lt;p&gt;镜像是一个只读的模板。比如 &lt;code&gt;python:3.12&lt;/code&gt; 镜像里装了 Ubuntu + Python 3.12。你可以把它想象成&quot;配好环境的 zip 包&quot;。&lt;/p&gt;
&lt;h3&gt;容器(Container) — 做好的菜&lt;/h3&gt;
&lt;p&gt;容器是镜像的运行实例。一个镜像可以起很多个容器，每个互相隔离。容器关了再开不会丢数据（除非你主动删了它）。&lt;/p&gt;
&lt;h3&gt;Dockerfile — 自己写食谱&lt;/h3&gt;
&lt;p&gt;如果你的项目除了 Python 还要装特定依赖、复制配置文件，就写 Dockerfile 描述&quot;怎么从零构建这个环境&quot;。&lt;/p&gt;
&lt;h2&gt;常用命令&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 看本地有哪些镜像
docker images

# 看正在运行的容器
docker ps

# 看所有容器（包括关掉的）
docker ps -a

# 运行一个容器
docker run -d --name myapp -p 8080:80 nginx
# -d  后台运行
# --name 给容器起名
# -p 8080:80  把本机 8080 端口映射到容器内 80 端口

# 进容器里操作
docker exec -it myapp bash

# 停止 / 启动 / 删除
docker stop myapp
docker start myapp
docker rm myapp       # 删容器
docker rmi nginx      # 删镜像

# 清理没用的容器、镜像、网络
docker system prune -a
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;跑一个 Python 项目&lt;/h2&gt;
&lt;p&gt;假设有个简单的 &lt;code&gt;main.py&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from flask import Flask
app = Flask(__name__)

@app.route(&quot;/&quot;)
def hello():
    return &quot;Hello from Docker!&quot;

if __name__ == &quot;__main__&quot;:
    app.run(host=&quot;0.0.0.0&quot;, port=5000)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;写 Dockerfile&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-dockerfile&quot;&gt;# 基于官方 Python 镜像
FROM python:3.12-slim

# 设置工作目录
WORKDIR /app

# 先复制依赖文件（利用缓存，不重复装包）
COPY requirements.txt .
RUN pip install -r requirements.txt

# 复制项目代码
COPY . .

# 暴露端口
EXPOSE 5000

# 启动命令
CMD [&quot;python&quot;, &quot;main.py&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;构建和运行&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 构建镜像
docker build -t my-python-app .

# 运行容器
docker run -d -p 5000:5000 --name myapp my-python-app

# 访问 http://localhost:5000 就能看到 Hello from Docker!
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Docker Compose — 多个服务一起跑&lt;/h2&gt;
&lt;p&gt;如果你有 app + 数据库 + Redis 好几个容器，一个个 &lt;code&gt;docker run&lt;/code&gt; 太麻烦。用 &lt;code&gt;docker-compose.yml&lt;/code&gt; 一次性编排：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# docker-compose.yml
services:
  app:
    build: .
    ports:
      - &quot;5000:5000&quot;
    depends_on:
      - db
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/mydb

  db:
    image: postgres:16
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 一键启动所有服务
docker compose up -d

# 查看日志
docker compose logs -f app

# 停止
docker compose down
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;数据持久化 — Volume&lt;/h2&gt;
&lt;p&gt;容器删了里面的数据就没了。想让数据留下，挂载 Volume：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 创建命名卷
docker volume create mydata

# 挂载到容器
docker run -v mydata:/app/data myapp

# 或者直接挂宿主机目录
docker run -v ./local_folder:/app/data myapp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Docker Compose 里写 &lt;code&gt;volumes:&lt;/code&gt; 也一样。&lt;/p&gt;
&lt;h2&gt;实际开发中怎么用&lt;/h2&gt;
&lt;p&gt;我一般这样：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;本地开发&lt;/strong&gt;：直接跑 Python，不用 Docker（调试方便）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;测试环境&lt;/strong&gt;：&lt;code&gt;docker compose up&lt;/code&gt; 起整套&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;给别人跑&lt;/strong&gt;：给 Dockerfile + compose，他 &lt;code&gt;git clone&lt;/code&gt; 后一行命令就跑起来&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;部署&lt;/strong&gt;：服务器上也是 &lt;code&gt;docker compose up -d&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;最常见的好处：换服务器不用重装环境，项目迁移就是一坨 compose 和 Dockerfile。&lt;/p&gt;
&lt;h2&gt;常见坑&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;镜像太大&lt;/strong&gt;：用 &lt;code&gt;python:3.12-slim&lt;/code&gt; 别用 &lt;code&gt;python:3.12&lt;/code&gt;，后者大几百 MB。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;构建慢&lt;/strong&gt;：&lt;code&gt;COPY requirements.txt .&lt;/code&gt; 和 &lt;code&gt;RUN pip install&lt;/code&gt; 放在 &lt;code&gt;COPY . .&lt;/code&gt; 前面，这样改代码不会触发重新装包。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;端口映射搞反&lt;/strong&gt;：&lt;code&gt;-p 本机端口:容器端口&lt;/code&gt;，别写反了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;容器一启动就退出&lt;/strong&gt;：看日志 &lt;code&gt;docker logs 容器名&lt;/code&gt;。大概率是启动命令执行完就结束了，比如前台没常驻进程。&lt;/p&gt;
&lt;h2&gt;速查表&lt;/h2&gt;
&lt;p&gt;| 需求 | 命令 |
|------|------|
| 跑一个容器 | &lt;code&gt;docker run -d -p 8080:80 --name xxx 镜像名&lt;/code&gt; |
| 进容器看情况 | &lt;code&gt;docker exec -it xxx bash&lt;/code&gt; |
| 看日志 | &lt;code&gt;docker logs -f xxx&lt;/code&gt; |
| 构建镜像 | &lt;code&gt;docker build -t 名字 .&lt;/code&gt; |
| 多服务编排 | &lt;code&gt;docker compose up -d&lt;/code&gt; |
| 停止全部 | &lt;code&gt;docker compose down&lt;/code&gt; |
| 大扫除 | &lt;code&gt;docker system prune -a&lt;/code&gt; |
| 看资源占用 | &lt;code&gt;docker stats&lt;/code&gt; |&lt;/p&gt;
&lt;p&gt;我刚入门时踩的坑大都写了。Docker 入门不难，真正复杂的是集群和编排——但那不是你一开始需要操心的东西。先把单个项目的镜像构建和容器跑通，日常够用很久了。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-19T16:00:00.000Z</atom:updated></item><item><title>Neovim 从入门到不放弃</title><link>https://lvdousha26.github.io/blog/neovim-tutorial</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/neovim-tutorial</guid><description>Neovim 新手友好指南：安装配置、基本操作、插件管理、打造现代编辑器</description><pubDate>Tue, 19 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;很多人第一次进 Vim 不知道怎么退出。这篇带你从安装走到舒服写字。&lt;/p&gt;
&lt;h2&gt;为什么选 Neovim&lt;/h2&gt;
&lt;p&gt;Vim 的现代化 fork。内置 LSP 客户端、Treesitter 语法高亮、Lua 插件体系。速度快，内存占用小，SSH 远程编辑神器。&lt;/p&gt;
&lt;p&gt;跟 VS Code 比：少了 GUI 包袱，键盘操作更极致，配置用 Lua 写比 JSON 强。&lt;/p&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# macOS
brew install neovim

# Ubuntu/Debian
sudo apt install neovim

# Windows
winget install Neovim.Neovim

# 或直接下 AppImage (Linux)
curl -LO https://github.com/neovim/neovim/releases/latest/download/nvim.appimage
chmod +x nvim.appimage &amp;#x26;&amp;#x26; sudo mv nvim.appimage /usr/local/bin/nvim
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;确认版本 ≥ 0.9：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;nvim --version
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;退出 Vim（第一课）&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;Esc          # 回到 Normal 模式
:q           # 退出
:q!          # 不保存强制退出
:wq          # 保存并退出
ZZ           # 保存并退出（快捷键）
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;模式 — 最重要的概念&lt;/h2&gt;
&lt;p&gt;| 模式 | 进入方式 | 做什么 |
|------|---------|--------|
| Normal | &lt;code&gt;Esc&lt;/code&gt; | 移动光标、删除、复制、粘贴 |
| Insert | &lt;code&gt;i&lt;/code&gt; &lt;code&gt;a&lt;/code&gt; &lt;code&gt;o&lt;/code&gt; | 写字 |
| Visual | &lt;code&gt;v&lt;/code&gt; &lt;code&gt;V&lt;/code&gt; &lt;code&gt;Ctrl+v&lt;/code&gt; | 选中文本 |
| Command | &lt;code&gt;:&lt;/code&gt; | 执行命令 |&lt;/p&gt;
&lt;p&gt;刚打开文件在 Normal 模式，按 &lt;code&gt;i&lt;/code&gt; 进入 Insert 开始打字。打完按 &lt;code&gt;Esc&lt;/code&gt; 回 Normal。&lt;/p&gt;
&lt;h2&gt;移动光标&lt;/h2&gt;
&lt;p&gt;方向键也能用，但 &lt;code&gt;hjkl&lt;/code&gt; 手不离开主键盘区：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;         k(上)
h(左)    j(下)    l(右)

w    下个单词开头
b    上个单词开头
0    行首
$    行尾
gg   文件开头
G    文件末尾
42gg 跳到第42行
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;基本编辑&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;x      删光标下字符
dd     删整行
yy     复制整行
p      粘贴到下面
u      撤销
Ctrl+r 重做
.      重复上一次操作
/关键词 搜索，n/N 跳上一个/下一个
:%s/旧/新/g  全文替换
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;配置文件&lt;/h2&gt;
&lt;p&gt;Neovim 配置在 &lt;code&gt;~/.config/nvim/&lt;/code&gt;，入口是 &lt;code&gt;init.lua&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lua&quot;&gt;-- ~/.config/nvim/init.lua

-- 行号
vim.opt.number = true
vim.opt.relativenumber = true  -- 相对行号，跳转方便

-- 缩进
vim.opt.tabstop = 4
vim.opt.shiftwidth = 4
vim.opt.expandtab = true       -- Tab 转空格

-- 搜索
vim.opt.ignorecase = true
vim.opt.smartcase = true

-- 剪贴板（能用系统剪贴板）
vim.opt.clipboard = &quot;unnamedplus&quot;

-- 鼠标支持
vim.opt.mouse = &quot;a&quot;

-- 主题和外观
vim.opt.termguicolors = true
vim.opt.cursorline = true
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;插件管理 — Lazy.nvim&lt;/h2&gt;
&lt;p&gt;现代 Neovim 标配。&lt;code&gt;lazy.nvim&lt;/code&gt; 是最流行的插件管理器，Lua 写配置，懒加载。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git clone https://github.com/folke/lazy.nvim.git \
  ~/.local/share/nvim/lazy/lazy.nvim
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 &lt;code&gt;init.lua&lt;/code&gt; 里加：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lua&quot;&gt;local lazypath = vim.fn.stdpath(&quot;data&quot;) .. &quot;/lazy/lazy.nvim&quot;
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({
    &quot;git&quot;, &quot;clone&quot;, &quot;--filter=blob:none&quot;,
    &quot;https://github.com/folke/lazy.nvim.git&quot;, lazypath,
  })
end
vim.opt.rtp:prepend(lazypath)

require(&quot;lazy&quot;).setup({
  -- 文件树
  { &quot;nvim-neo-tree/neo-tree.nvim&quot;, branch = &quot;v3.x&quot;,
    dependencies = { &quot;nvim-lua/plenary.nvim&quot;, &quot;nvim-tree/nvim-web-devicons&quot;, &quot;MunifTanjim/nui.nvim&quot; } },

  -- 模糊查找
  { &quot;nvim-telescope/telescope.nvim&quot;, tag = &quot;0.1.8&quot;,
    dependencies = { &quot;nvim-lua/plenary.nvim&quot; } },

  -- 状态栏
  { &quot;nvim-lualine/lualine.nvim&quot;,
    dependencies = { &quot;nvim-tree/nvim-web-devicons&quot; } },

  -- 配色
  { &quot;folke/tokyonight.nvim&quot;, lazy = false, priority = 1000 },

  -- LSP 自动补全
  { &quot;neovim/nvim-lspconfig&quot; },
  { &quot;hrsh7th/nvim-cmp&quot;,
    dependencies = { &quot;hrsh7th/cmp-nvim-lsp&quot;, &quot;L3MON4D3/LuaSnip&quot; } },
})

-- 加载主题
vim.cmd.colorscheme(&quot;tokyonight-night&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;保存 &lt;code&gt;init.lua&lt;/code&gt;，打开 nvim，&lt;code&gt;:Lazy&lt;/code&gt; 查看插件状态，按 &lt;code&gt;i&lt;/code&gt; 安装。&lt;/p&gt;
&lt;h2&gt;好用的键位映射&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-lua&quot;&gt;-- leader 键改空格
vim.g.mapleader = &quot; &quot;

-- &amp;#x3C;leader&gt;e 打开文件树
vim.keymap.set(&quot;n&quot;, &quot;&amp;#x3C;leader&gt;e&quot;, &quot;:Neotree toggle&amp;#x3C;CR&gt;&quot;)

-- &amp;#x3C;leader&gt;f 模糊搜文件
vim.keymap.set(&quot;n&quot;, &quot;&amp;#x3C;leader&gt;f&quot;, &quot;:Telescope find_files&amp;#x3C;CR&gt;&quot;)

-- &amp;#x3C;leader&gt;g 全局搜文本
vim.keymap.set(&quot;n&quot;, &quot;&amp;#x3C;leader&gt;g&quot;, &quot;:Telescope live_grep&amp;#x3C;CR&gt;&quot;)

-- Ctrl+hjkl 在分屏间跳转
vim.keymap.set(&quot;n&quot;, &quot;&amp;#x3C;C-h&gt;&quot;, &quot;&amp;#x3C;C-w&gt;h&quot;)
vim.keymap.set(&quot;n&quot;, &quot;&amp;#x3C;C-j&gt;&quot;, &quot;&amp;#x3C;C-w&gt;j&quot;)
vim.keymap.set(&quot;n&quot;, &quot;&amp;#x3C;C-k&gt;&quot;, &quot;&amp;#x3C;C-w&gt;k&quot;)
vim.keymap.set(&quot;n&quot;, &quot;&amp;#x3C;C-l&gt;&quot;, &quot;&amp;#x3C;C-w&gt;l&quot;)

-- 分屏
-- :split 水平，:vsplit 垂直
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;LSP — 代码补全和跳转&lt;/h2&gt;
&lt;p&gt;Neovim 内置 LSP 客户端。装 &lt;code&gt;nvim-lspconfig&lt;/code&gt; 和 &lt;code&gt;mason.nvim&lt;/code&gt; 后：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lua&quot;&gt;-- 加到 lazy.setup({}) 里
{ &quot;williamboman/mason.nvim&quot; },
{ &quot;williamboman/mason-lspconfig.nvim&quot; },

-- 初始化
require(&quot;mason&quot;).setup()
require(&quot;mason-lspconfig&quot;).setup({
  ensure_installed = { &quot;lua_ls&quot;, &quot;pyright&quot;, &quot;gopls&quot;, &quot;rust_analyzer&quot; },
  automatic_installation = true,
})

-- 自动补全配置
local cmp = require(&quot;cmp&quot;)
cmp.setup({
  mapping = cmp.mapping.preset.insert({
    [&quot;&amp;#x3C;Tab&gt;&quot;] = cmp.mapping.select_next_item(),
    [&quot;&amp;#x3C;S-Tab&gt;&quot;] = cmp.mapping.select_prev_item(),
    [&quot;&amp;#x3C;CR&gt;&quot;] = cmp.mapping.confirm({ select = true }),
  }),
  sources = cmp.config.sources({
    { name = &quot;nvim_lsp&quot; },
  }),
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之后打开对应语言的文件，LSP 自动生效：&lt;code&gt;gd&lt;/code&gt; 跳定义，&lt;code&gt;K&lt;/code&gt; 查看文档，&lt;code&gt;&amp;#x3C;leader&gt;rn&lt;/code&gt; 重命名。&lt;/p&gt;
&lt;h2&gt;一套可用的最小 init.lua&lt;/h2&gt;
&lt;p&gt;把上面的拼起来差不多 80 行，放到 &lt;code&gt;~/.config/nvim/init.lua&lt;/code&gt;，就有文件树、模糊搜索、LSP 补全、好看主题。&lt;/p&gt;
&lt;p&gt;也可以直接用社区配置：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# LazyVim — 开箱即用的现代配置
git clone https://github.com/LazyVim/starter ~/.config/nvim
rm -rf ~/.config/nvim/.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;打开 nvim 等插件装完就行。LazyVim 默认配好了 LSP、Telescope、Treesitter、哪个键做什么。&lt;/p&gt;
&lt;h2&gt;日常使用流程&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;nvim project/main.py

# 基本操作
&amp;#x3C;leader&gt;e     # 打开文件树，选文件
&amp;#x3C;leader&gt;f     # 模糊搜文件
&amp;#x3C;leader&gt;g     # 搜索代码内容
gd            # 跳到函数定义
K             # 看函数文档
&amp;#x3C;leader&gt;rn    # 重命名变量
:w            # 保存

# 终端
:term         # 打开内置终端
i             # 终端里按 i 进入输入模式
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;速查表&lt;/h2&gt;
&lt;p&gt;| 需求 | 操作 |
|------|------|
| 安装 | &lt;code&gt;brew install neovim&lt;/code&gt; / &lt;code&gt;apt install neovim&lt;/code&gt; |
| 退出 | &lt;code&gt;:q&lt;/code&gt; / &lt;code&gt;:q!&lt;/code&gt; / &lt;code&gt;:wq&lt;/code&gt; |
| 配置文件 | &lt;code&gt;~/.config/nvim/init.lua&lt;/code&gt; |
| 装插件 | 写到 lazy.setup({}) 里，打开 nvim 自动装 |
| 查看插件 | &lt;code&gt;:Lazy&lt;/code&gt; |
| 搜索文件 | &lt;code&gt;&amp;#x3C;leader&gt;f&lt;/code&gt; (Telescope) |
| 搜索文本 | &lt;code&gt;&amp;#x3C;leader&gt;g&lt;/code&gt; |
| 分屏 | &lt;code&gt;:split&lt;/code&gt; / &lt;code&gt;:vsplit&lt;/code&gt; |
| 选字 | &lt;code&gt;viw&lt;/code&gt; 选词，&lt;code&gt;V&lt;/code&gt; 选行 |
| 注释 | &lt;code&gt;gc&lt;/code&gt; + 动作（装了 Comment 插件的话） |&lt;/p&gt;
&lt;p&gt;不用一口气学完。记住 &lt;code&gt;i&lt;/code&gt; 打字、&lt;code&gt;Esc&lt;/code&gt; 回 Normal、&lt;code&gt;:wq&lt;/code&gt; 保存退出、&lt;code&gt;dd&lt;/code&gt; 删行、&lt;code&gt;p&lt;/code&gt; 粘贴。其他边用边查。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-19T16:00:00.000Z</atom:updated></item><item><title>Postman 接口调试入门</title><link>https://lvdousha26.github.io/blog/postman-tutorial</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/postman-tutorial</guid><description>用 Postman 发请求、管理环境变量、写测试脚本、导出文档，前后端联调不再靠猜</description><pubDate>Tue, 19 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;后端给个接口文档，你用 curl 一遍遍手动敲 URL、拼 JSON、看返回——也不是不行，但 Postman 把这事做得舒服很多。保存请求、切换环境、写断言、导出文档，都在一个界面里。&lt;/p&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# macOS
brew install --cask postman

# Windows
winget install Postman.Postman

# 或者直接官网下：https://www.postman.com/downloads/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注册免费账号即可用全部基础功能。&lt;/p&gt;
&lt;h2&gt;界面长这样&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;┌───────────┬──────────────────┐
│  Collections  │  GET /api/users  │
│  (请求文件夹)  │  Params Headers   │
│               │  Body   Tests     │
│  History      │                   │
│               │  { response }     │
└───────────┴──────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;左上角 Collections 组织请求，中间是请求构造区，下面是响应区。&lt;/p&gt;
&lt;h2&gt;发第一个请求&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;1. 新建 Collection：My API
2. Collection 右键 → Add Request → 起名 &quot;Get Users&quot;
3. Method 选 GET，URL 填 https://jsonplaceholder.typicode.com/users
4. 点 Send
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;右侧看到响应 JSON 和状态 200 OK。&lt;/p&gt;
&lt;p&gt;POST 请求同理：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Method: POST
URL: https://jsonplaceholder.typicode.com/posts
Body → raw → JSON:
{
  &quot;title&quot;: &quot;test&quot;,
  &quot;body&quot;: &quot;hello&quot;,
  &quot;userId&quot;: 1
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;变量 — 不用每次改 URL&lt;/h2&gt;
&lt;p&gt;{{base_url}}/users 这样的写法，base_url 是变量，切换环境自动换值。&lt;/p&gt;
&lt;p&gt;右上角 Environments → 新建：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;变量名: base_url
初始值: http://localhost:8000
当前值: http://localhost:8000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再新建一个 Production 环境：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;base_url: https://api.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;右上角切环境，请求里的 &lt;code&gt;{{base_url}}&lt;/code&gt; 自动跟着变。&lt;/p&gt;
&lt;h2&gt;Pre-request Script — 发请求前自动做的事&lt;/h2&gt;
&lt;p&gt;比如先调登录接口拿 token，放到变量里：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// Pre-request Script 标签页
pm.sendRequest({
  url: &quot;{{base_url}}/auth/login&quot;,
  method: &quot;POST&quot;,
  header: { &quot;Content-Type&quot;: &quot;application/json&quot; },
  body: { mode: &quot;raw&quot;, raw: JSON.stringify({ username: &quot;admin&quot;, password: &quot;123456&quot; }) }
}, (err, res) =&gt; {
  const json = res.json();
  pm.environment.set(&quot;token&quot;, json.access_token);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后请求的 Authorization 标签页选 Bearer Token，填 &lt;code&gt;{{token}}&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;Tests — 自动验证返回值&lt;/h2&gt;
&lt;p&gt;用 JavaScript 写断言，请求发完后自动跑：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;// Tests 标签页

pm.test(&quot;状态码是 200&quot;, () =&gt; {
  pm.response.to.have.status(200);
});

pm.test(&quot;返回的是数组&quot;, () =&gt; {
  const json = pm.response.json();
  pm.expect(Array.isArray(json)).to.be.true;
});

pm.test(&quot;第一个用户有 id&quot;, () =&gt; {
  const json = pm.response.json();
  pm.expect(json[0]).to.have.property(&quot;id&quot;);
});

// 把某字段存成变量供后续请求用
const json = pm.response.json();
pm.collectionVariables.set(&quot;userId&quot;, json[0].id);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Collection Runner — 批量跑&lt;/h2&gt;
&lt;p&gt;Collection 右边点 Run：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;选 Collection → 选要跑的请求 → 设置迭代次数 → Run
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;全部跑一遍，自动汇总 Pass/Fail。适合接口回归测试。&lt;/p&gt;
&lt;h2&gt;导出文档&lt;/h2&gt;
&lt;p&gt;Collection 右边箭头 → View in Web → 自动生成漂亮的接口文档页面。发给前端同事即可。&lt;/p&gt;
&lt;p&gt;或者 Export → 导出为 OpenAPI / Swagger JSON。&lt;/p&gt;
&lt;h2&gt;实际工作流&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;拿到接口文档 → 建 Collection&lt;/li&gt;
&lt;li&gt;把每个接口做成一个 Request，填上 URL、Headers、Body&lt;/li&gt;
&lt;li&gt;设好环境变量（开发 / 测试 / 生产三套）&lt;/li&gt;
&lt;li&gt;写 Tests 验证关键返回值&lt;/li&gt;
&lt;li&gt;调通了导出文档或分享 Collection&lt;/li&gt;
&lt;li&gt;改代码后跑一遍 Collection Runner 确认没搞坏&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;速查&lt;/h2&gt;
&lt;p&gt;| 需求 | 操作 |
|------|------|
| 发请求 | 填 URL → Send |
| 环境切换 | 右上角下拉 |
| 引用变量 | &lt;code&gt;{{变量名}}&lt;/code&gt; |
| 提取返回值 | &lt;code&gt;pm.response.json()&lt;/code&gt; |
| 设变量 | &lt;code&gt;pm.environment.set(&quot;key&quot;, value)&lt;/code&gt; |
| 断言 | &lt;code&gt;pm.test(&quot;描述&quot;, () =&gt; { pm.expect(...) })&lt;/code&gt; |
| 批量跑 | Collection → Run |
| 导出文档 | Collection → View in Web |&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-19T16:00:00.000Z</atom:updated></item><item><title>Redis 入门：简单直接</title><link>https://lvdousha26.github.io/blog/redis-tutorial</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/redis-tutorial</guid><description>Redis 是什么、怎么用、什么时候不该用</description><pubDate>Tue, 19 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Redis 很快。非常快。&lt;/p&gt;
&lt;p&gt;它把数据放在内存里。不写磁盘。所以快。&lt;/p&gt;
&lt;h2&gt;什么是 Redis&lt;/h2&gt;
&lt;p&gt;Redis 是一个键值存储。你给它一个 key，它还你一个 value。&lt;/p&gt;
&lt;p&gt;但它不只是 key-value。它懂数据结构。字符串、列表、集合、有序集合、哈希、流。它都懂。&lt;/p&gt;
&lt;p&gt;大多数人用它做缓存。但它能做的更多。&lt;/p&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;p&gt;Linux 上：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;apt install redis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;macOS 上：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;brew install redis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Docker 里：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker run --name redis -p 6379:6379 -d redis
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;装完运行 &lt;code&gt;redis-cli&lt;/code&gt;。输入 &lt;code&gt;PING&lt;/code&gt;。它回 &lt;code&gt;PONG&lt;/code&gt;。好了。&lt;/p&gt;
&lt;h2&gt;基本命令&lt;/h2&gt;
&lt;p&gt;设置一个 key：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;SET name &quot;lihua&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;读取它：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;GET name
# &quot;lihua&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;设过期时间（秒）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;SET token &quot;abc123&quot; EX 3600
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查还剩多久：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;TTL token
# 3557
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;删掉一个 key：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;DEL name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就这么简单。&lt;/p&gt;
&lt;h2&gt;数据结构&lt;/h2&gt;
&lt;h3&gt;列表&lt;/h3&gt;
&lt;p&gt;队列用这个。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;LPUSH tasks &quot;send_email&quot;
LPUSH tasks &quot;resize_image&quot;
RPOP tasks
# &quot;send_email&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;LPUSH&lt;/code&gt; 从左边推。&lt;code&gt;RPOP&lt;/code&gt; 从右边弹出。先进先出。&lt;/p&gt;
&lt;h3&gt;集合&lt;/h3&gt;
&lt;p&gt;无序、不重复。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;SADD tags:post:42 &quot;redis&quot; &quot;tutorial&quot; &quot;backend&quot;
SISMEMBER tags:post:42 &quot;redis&quot;
# 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;标签系统常用集合。&lt;/p&gt;
&lt;h3&gt;有序集合&lt;/h3&gt;
&lt;p&gt;带分数的集合。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ZADD leaderboard 100 &quot;alice&quot;
ZADD leaderboard 85 &quot;bob&quot;
ZADD leaderboard 92 &quot;charlie&quot;
ZREVRANGE leaderboard 0 -1
# alice, charlie, bob
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;排行榜就用这个。&lt;/p&gt;
&lt;h3&gt;哈希&lt;/h3&gt;
&lt;p&gt;存储对象。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;HSET user:1 name &quot;lihua&quot; age &quot;25&quot; city &quot;beijing&quot;
HGET user:1 name
# &quot;lihua&quot;
HGETALL user:1
# name, lihua, age, 25, city, beijing
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;比存 JSON 字符串好。你可以只读一个字段。&lt;/p&gt;
&lt;h2&gt;缓存模式&lt;/h2&gt;
&lt;h3&gt;旁路缓存&lt;/h3&gt;
&lt;p&gt;这是最常见的用法。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;查 Redis。&lt;/li&gt;
&lt;li&gt;有就返回。&lt;/li&gt;
&lt;li&gt;没有就查数据库。&lt;/li&gt;
&lt;li&gt;把结果存进 Redis。&lt;/li&gt;
&lt;li&gt;设个过期时间。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Python 代码像这样：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import redis
import json

r = redis.Redis()

def get_user(user_id):
    cached = r.get(f&quot;user:{user_id}&quot;)
    if cached:
        return json.loads(cached)

    user = db.query(f&quot;SELECT * FROM users WHERE id = {user_id}&quot;)
    r.setex(f&quot;user:{user_id}&quot;, 300, json.dumps(user))
    return user
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;过期时间很重要。不要永远缓存。数据会变化。&lt;/p&gt;
&lt;h2&gt;什么时候不该用 Redis&lt;/h2&gt;
&lt;p&gt;Redis 需要内存。内存贵。&lt;/p&gt;
&lt;p&gt;你的数据必须全部放进内存。10GB 数据？准备好 10GB 内存。&lt;/p&gt;
&lt;p&gt;不要用 Redis 存大文件。存图片、存视频？不对。存文件路径就行。&lt;/p&gt;
&lt;p&gt;不要用 Redis 做复杂查询。它没有 SQL。没有 JOIN。没有 WHERE age &gt; 25。搜索用 Elasticsearch。复杂查询用 PostgreSQL。&lt;/p&gt;
&lt;p&gt;持久化不是 Redis 的首要任务。它有 RDB 和 AOF。但它的设计是为了快，不是为了安全。别把银行交易记录只放在 Redis 里。&lt;/p&gt;
&lt;h2&gt;发布 / 订阅&lt;/h2&gt;
&lt;p&gt;Redis 可以发消息。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 终端 1
SUBSCRIBE notifications
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 终端 2
PUBLISH notifications &quot;new_user_signed_up&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;终端 1 会收到消息。简单、轻量。不可靠。消息不会持久化。订户离线就收不到了。&lt;/p&gt;
&lt;p&gt;WebSocket 广播、聊天消息可以用这个。重要消息别用。&lt;/p&gt;
&lt;h2&gt;分布式锁&lt;/h2&gt;
&lt;p&gt;Redis 可以当锁用。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;SET lock:resource &quot;unique-id&quot; NX EX 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;NX&lt;/code&gt; 表示 key 不存在才设置。&lt;code&gt;EX 10&lt;/code&gt; 表示 10 秒后自动释放。&lt;/p&gt;
&lt;p&gt;拿到锁才能干活。干完删除 key。&lt;/p&gt;
&lt;p&gt;小心。锁会过期。你的任务可能还没跑完锁就没了。用 Redlock 算法或者直接用成熟的库。&lt;/p&gt;
&lt;h2&gt;实用建议&lt;/h2&gt;
&lt;p&gt;给 key 命名时用冒号分隔。&lt;code&gt;user:1:profile&lt;/code&gt;。不用 &lt;code&gt;user_1_profile&lt;/code&gt;。冒号在 Redis 客户端里会分组显示。&lt;/p&gt;
&lt;p&gt;给所有缓存设过期时间。永远设。忘记设的 key 会一直占内存。&lt;/p&gt;
&lt;p&gt;配置 &lt;code&gt;maxmemory&lt;/code&gt;。不要让它无限制增长。设一个上限，再设一个淘汰策略。&lt;code&gt;allkeys-lru&lt;/code&gt; 是不错的选择。它删除最近最少使用的 key。&lt;/p&gt;
&lt;p&gt;用 &lt;code&gt;MONITOR&lt;/code&gt; 看实时命令流。调试时很有用。生产环境不要一直开着。&lt;/p&gt;
&lt;p&gt;用 &lt;code&gt;SLOWLOG&lt;/code&gt; 看慢命令。Redis 是单线程的。一个慢命令会阻塞所有请求。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;Redis 就是快。因为它用内存。因为设计简单。&lt;/p&gt;
&lt;p&gt;它可以做缓存、做队列、做排行榜、做锁。但不要把它当成唯一的数据存储。它配合其他数据库使用。&lt;/p&gt;
&lt;p&gt;开始很简单。装好。用 &lt;code&gt;SET&lt;/code&gt; 和 &lt;code&gt;GET&lt;/code&gt;。然后需要什么学什么。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-19T16:00:00.000Z</atom:updated></item><item><title>科研搬砖工备忘录</title><link>https://lvdousha26.github.io/blog/research-skills-memo</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/research-skills-memo</guid><description>读论文、做实验、写文章、开会汇报——日常科研中容易忘但很重要的小事</description><pubDate>Tue, 19 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;不是正经经验贴。就是记录一些容易踩的坑、经常忘但很重要的小习惯。随手记，随时补。&lt;/p&gt;
&lt;h2&gt;读论文&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一天一篇？别信。&lt;/strong&gt; 一周认真读透一篇比一天翻十篇有用得多。读的时候问自己：他们解决了什么问题？方法为什么有效？我能复现吗？&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;三遍法足够。&lt;/strong&gt; 第一遍 title + abstract + 扫一眼图，决定要不要读。第二遍正文过一遍，跟着推导思路走。第三遍对着 references 顺藤摸瓜。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;读完记下来。&lt;/strong&gt; Zotero 里给条目加 Note 或者 Obsidian 里写一段。不记等于白读，三个月后你连这论文讲啥都忘了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;不要只读最新的。&lt;/strong&gt; 经典论文（引用过千那种）读一篇抵十篇。它们定义了领域的问题框架。&lt;/p&gt;
&lt;h2&gt;做实验&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;每次跑实验前开个 log。&lt;/strong&gt; 最简单的办法：项目目录下建 &lt;code&gt;experiments.md&lt;/code&gt;，记日期、参数、结果、想到的改进。纸笔也行。过两周你回头看根本记不清 &lt;code&gt;lr=3e-4 bs=32 warmup=500&lt;/code&gt; 那组为啥好。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一次只改一个变量。&lt;/strong&gt; 调参时别同时改 lr 和 batch_size，你不知道谁起了作用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;随机种子固定。&lt;/strong&gt; &lt;code&gt;torch.manual_seed(42)&lt;/code&gt; 就一行，不加的结果就是你再也复现不出那个 SOTA。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;baseline 先跑通。&lt;/strong&gt; 别上来就上你的花活。先把最简单的版本跑通（哪怕是个随机猜测），确认 pipeline 没 bug。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;checkpoint 存勤点。&lt;/strong&gt; 硬盘便宜，时间贵。每 epoch 存一个，文件名带 step 和 metric。&lt;/p&gt;
&lt;h2&gt;写代码&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Notebook 是探索用的，不是交付用的。&lt;/strong&gt; 写到差不多就抽成 &lt;code&gt;.py&lt;/code&gt; 文件。Notebook 的 cell 执行顺序是个隐形炸弹。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Git 别只 master。&lt;/strong&gt; 一条分支一个实验，坏了不要紧，删了重来。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;依赖记下来。&lt;/strong&gt; &lt;code&gt;pip freeze &gt; requirements.txt&lt;/code&gt; 或者 &lt;code&gt;conda env export &gt; environment.yml&lt;/code&gt;。交给别人跑的时候，对方的环境跟你差十万八千里。&lt;/p&gt;
&lt;h2&gt;写文章&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;先有骨架再填肉。&lt;/strong&gt; 别从 abstract 开始写。先列 section 标题和每段的 bullet point，整个故事立起来再说。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;图先行。&lt;/strong&gt; 审稿人第一眼看图。每个图配一句 take-home message（图中最重要的信息）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Introduction 的逻辑链：&lt;/strong&gt; 大背景 → 具体问题 → 前人怎么做的 → 有什么不足 → 我们怎么解决的 → 贡献是什么。照着这个模板填。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Related work 别写成流水账。&lt;/strong&gt; 每个引用要说明跟你的关系——是启发？是 baseline？是你解决的痛点？&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;写完放两天再读。&lt;/strong&gt; 刚写完觉得完美，放两天再看就发现一堆不通顺的地方。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LaTeX 的一个小技巧：&lt;/strong&gt; 写长文用 &lt;code&gt;\input{}&lt;/code&gt; 把每节拆成单独 &lt;code&gt;.tex&lt;/code&gt; 文件。改一节不用编译全文。&lt;/p&gt;
&lt;h2&gt;做 PPT / 汇报&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;3 分钟定理：&lt;/strong&gt; 听众的注意力最多撑三分钟。每个 slides 必须在 20 秒内被理解，否则就太复杂了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;讲故事，不是讲流水账。&lt;/strong&gt; motivation → problem → method → key insight → result → takeaway。每一步都要回答&quot;为什么&quot;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;图 &gt;&gt; 字。&lt;/strong&gt; 一页超过 50 个字就该拆。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;提前讲一遍。&lt;/strong&gt; 自己对着空气或抓个同学讲一遍，就知道哪里讲不清了。&lt;/p&gt;
&lt;h2&gt;日常习惯&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;备份。&lt;/strong&gt; 代码用 GitHub，论文用 Zotero，笔记用 Obsidian，数据用坚果云/OneDrive 自动同步。丢一次数据就知道了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;记笔记。&lt;/strong&gt; 每次 meeting 后花五分钟，记下讨论要点和 to-do。相信我，不记的话吃完饭你就忘了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;别比较。&lt;/strong&gt; 同组的人发顶会了、隔壁师兄拿 offer 了，跟你没关系。科研是长跑，节奏不一样很正常。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问问题。&lt;/strong&gt; 卡了两天还没解决的事情，直接问。被卡住的时间够你问三个人了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;休息。&lt;/strong&gt; 身体疲劳的状态下做不出好的科研判断。累了就睡，醒了脑子清楚比多熬两小时有用。&lt;/p&gt;
&lt;h2&gt;工具清单&lt;/h2&gt;
&lt;p&gt;| 场景 | 推荐 |
|------|------|
| 文献管理 | Zotero |
| 笔记 | Obsidian / Notion |
| 画图 | draw.io / Figma |
| 写论文 | LaTeX (Overleaf 或本地) |
| 实验追踪 | MLflow / WandB / 朴素的 &lt;code&gt;experiments.md&lt;/code&gt; |
| 时间管理 | 日历够了，别在工具上花太多时间 |
| 英文润色 | DeepL Write / ChatGPT |
| 画神经网络图 | draw.io / NN-SVG |&lt;/p&gt;
&lt;p&gt;这页备忘录会一直更新。以后踩了新坑就补上来。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-19T16:00:00.000Z</atom:updated></item><item><title>Zotero 文献管理入门：插件才是本体</title><link>https://lvdousha26.github.io/blog/zotero-tutorial</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/zotero-tutorial</guid><description>Zotero 安装配置、文献导入、坚果云同步，以及 Better BibTeX、Translate、Style 等必备插件</description><pubDate>Tue, 19 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Zotero 本体只是个文献数据库。真正让它好用的是插件。这篇先讲基本操作，重点讲插件怎么装、哪些值得装、怎么配。&lt;/p&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# macOS
brew install --cask zotero

# Windows
winget install Zotero.Zotero

# 或直接官网下载: https://www.zotero.org/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同时装浏览器扩展 &lt;strong&gt;Zotero Connector&lt;/strong&gt;（Chrome / Firefox 都有），一键抓论文元数据和 PDF。&lt;/p&gt;
&lt;h2&gt;基础操作&lt;/h2&gt;
&lt;h3&gt;导入文献&lt;/h3&gt;
&lt;p&gt;浏览器打开论文页面（arXiv、IEEE、ACM、Google Scholar 等），点 Zotero Connector 图标。条目 + PDF 一起保存到当前选中的分类里。&lt;/p&gt;
&lt;p&gt;本地 PDF 拖进 Zotero 窗口，右键 → 抓取元数据。大部分英文论文能自动识别。&lt;/p&gt;
&lt;h3&gt;组织&lt;/h3&gt;
&lt;p&gt;左侧建文件夹分类。同一篇文献可以属于多个分类（Zotero 的&quot;Collection&quot;本质是标签，不是目录）。&lt;/p&gt;
&lt;h3&gt;引用&lt;/h3&gt;
&lt;p&gt;装好 Zotero 后 Word 里自动出现 Zotero 标签页。写论文时：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;光标放引用位置 → Add/Edit Citation → 搜论文标题 → 选格式 → 插入
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;写完后 &lt;code&gt;Add/Edit Bibliography&lt;/code&gt; 一键生成参考文献列表。格式随时切换（IEEE → APA → GB/T 7714）。&lt;/p&gt;
&lt;p&gt;LaTeX 用户装 Better BibTeX 插件后导出 &lt;code&gt;.bib&lt;/code&gt; 文件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;右键文献 → Export Items → Better BibTeX → 生成 .bib
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;同步与存储&lt;/h2&gt;
&lt;p&gt;Zotero 自带 300MB 免费空间，存条目够用，存 PDF 肯定不够。&lt;/p&gt;
&lt;p&gt;用坚果云 WebDAV 同步 PDF：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;坚果云 → 账户信息 → 第三方应用管理 → 添加应用（获取 WebDAV 地址和密码）&lt;/li&gt;
&lt;li&gt;Zotero → 编辑 → 设置 → 同步 → 文件同步&lt;/li&gt;
&lt;li&gt;选 WebDAV，填 &lt;code&gt;https://dav.jianguoyun.com/dav/&lt;/code&gt;、账号、密码&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;300MB Zotero 空间 + 坚果云存储 = 全平台同步，手机也能看文献。&lt;/p&gt;
&lt;h2&gt;插件 — 这才是正文&lt;/h2&gt;
&lt;p&gt;插件安装：Zotero → 工具 → 插件 → 右上角齿轮 → Install Plugin From File（下 &lt;code&gt;.xpi&lt;/code&gt; 文件拖进去）。&lt;/p&gt;
&lt;h3&gt;Better BibTeX&lt;/h3&gt;
&lt;p&gt;LaTeX 用户必备。给每篇文献生成稳定的引用 key（不随条目修改而变），自动导出 &lt;code&gt;.bib&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;装好后在 Zotero 首选项里找到 Better BibTeX：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Citation Key 格式：auth.lower + year
例如：vaswani2017attention

导出：Preferences → Better BibTeX → Automatic Export
设置自动导出路径，每次改文献自动更新 .bib
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Zotero Translate&lt;/h3&gt;
&lt;p&gt;划词翻译，支持 Google / DeepL / 彩云 / DeepL 等十几个引擎。读英文论文时选中一段自动弹出翻译。&lt;/p&gt;
&lt;p&gt;装好右键点 Translate 图标，设置里选 DeepL（免费额度够用）。&lt;/p&gt;
&lt;h3&gt;Jasminum（茉莉花）&lt;/h3&gt;
&lt;p&gt;中文文献增强。自动抓取知网/万方的中文元数据、拆分作者姓名、识别学位论文。&lt;/p&gt;
&lt;h3&gt;Zotero Style&lt;/h3&gt;
&lt;p&gt;自定义显示样式。让条目列表列数更多、字体更紧凑、期刊标签着色。装好去首选项调。&lt;/p&gt;
&lt;h3&gt;ZotFile&lt;/h3&gt;
&lt;p&gt;重命名和移动 PDF 文件，支持提取 PDF 中的注释。可以设规则让所有 PDF 按 &lt;code&gt;作者_年份_标题.pdf&lt;/code&gt; 自动改名。&lt;/p&gt;
&lt;h3&gt;Zotero Tag&lt;/h3&gt;
&lt;p&gt;自动给文献打标签，方便按主题筛选。常和 Jasminum 一起用。&lt;/p&gt;
&lt;h3&gt;GreenFrog / Zotero Night&lt;/h3&gt;
&lt;p&gt;深色模式。晚上看文献眼睛舒服点。&lt;/p&gt;
&lt;h3&gt;Plugin 安装优先级&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;必装：Better BibTeX, Zotero Translate, Jasminum
推荐：Zotero Style, ZotFile
选装：Zotero Tag, Zotero Night
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;和 Obsidian 联动&lt;/h2&gt;
&lt;p&gt;Obsidian → Community Plugins → 搜 Zotero Integration。&lt;/p&gt;
&lt;p&gt;装好后在笔记里：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Ctrl+P → Zotero Integration: Insert Literature Note
搜论文标题 → 自动生成带元数据和链接的笔记
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;速查&lt;/h2&gt;
&lt;p&gt;| 操作 | 方法 |
|------|------|
| 抓论文 | 浏览器 Zotero Connector 点击图标 |
| 中文文献识别 | 装 Jasminum 插件 |
| LaTeX bib 导出 | Better BibTeX → Export |
| PDF 同步 | 坚果云 WebDAV |
| 划词翻译 | Zotero Translate |
| Word 引用 | Zotero 标签页 → Add/Edit Citation |
| 深色模式 | GreenFrog 插件 |&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-19T16:00:00.000Z</atom:updated></item><item><title>Bash 入门</title><link>https://lvdousha26.github.io/blog/bash-tutorial</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/bash-tutorial</guid><description>面向初学者的 Bash 实用教程，涵盖基础语法、常用命令和脚本技巧</description><pubDate>Mon, 18 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;为什么要学 Bash&lt;/h2&gt;
&lt;p&gt;日常开发中大量重复操作——编译、打包、部署、查日志、批量改名——如果每次手动敲一遍，效率极低。Bash 让你用几行命令自动完成这些事。&lt;/p&gt;
&lt;p&gt;Bash 是 Unix/Linux 默认的命令行解释器，macOS 自带，Windows 可通过 WSL 或 Git Bash 使用。&lt;/p&gt;
&lt;h2&gt;基础操作&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 文件与目录
ls          # 列出文件
cd dir      # 切换目录
pwd         # 当前路径
mkdir dir   # 创建目录
rm file     # 删除文件
rm -r dir   # 递归删除目录
cp src dst  # 复制
mv src dst  # 移动/重命名

# 查看文件内容
cat file           # 全文输出
head -n 20 file    # 前 20 行
tail -f file       # 实时追踪末尾（看日志）
less file          # 分页浏览

# 权限
chmod +x script.sh   # 添加可执行权限
chmod 755 script.sh  # 数字方式设置权限
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;管道与重定向&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 管道：前一个命令的输出作为后一个命令的输入
cat log.txt | grep ERROR | wc -l    # 统计 ERROR 出现次数

# 重定向：将输出写入文件
ls &gt; output.txt          # 覆盖写入
ls &gt;&gt; output.txt         # 追加写入
command 2&gt;&amp;#x26;1             # 标准错误重定向到标准输出
command &gt; /dev/null      # 丢弃所有输出
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;最常用的命令组合&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# grep：搜索文本
grep &quot;关键词&quot; file
grep -r &quot;TODO&quot; src/          # 递归搜索目录
ps aux | grep nginx           # 查找进程

# find：搜索文件
find . -name &quot;*.log&quot;          # 按名称查找
find . -mtime -7              # 最近 7 天修改的文件
find . -name &quot;*.tmp&quot; -delete  # 查找并删除

# awk / sed：文本处理
awk &apos;{print $1}&apos; file         # 打印第一列
sed &apos;s/old/new/g&apos; file        # 全文替换
sed -i &apos;s/old/new/g&apos; file     # 直接修改文件
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;变量与循环&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 变量（注意等号两边不能有空格）
name=&quot;world&quot;
echo &quot;Hello, $name&quot;
echo &quot;文件数: $(ls | wc -l)&quot;

# for 循环
for file in *.txt; do
    echo &quot;处理: $file&quot;
    wc -l &quot;$file&quot;
done

# while 循环
count=1
while [ $count -le 5 ]; do
    echo &quot;第 $count 次&quot;
    count=$((count + 1))
done
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;条件判断&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 文件测试
[ -f file ]   # 是普通文件
[ -d dir ]    # 是目录
[ -x file ]   # 可执行

# 字符串比较
[ &quot;$a&quot; = &quot;$b&quot; ]     # 相等
[ -z &quot;$str&quot; ]       # 字符串为空

# if 语句
if [ -f &quot;config.yml&quot; ]; then
    echo &quot;配置文件存在&quot;
else
    echo &quot;请创建 config.yml&quot;
fi
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;简单脚本模板&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/bin/bash
set -euo pipefail   # 遇到错误立即退出，未定义变量报错

echo &quot;=== 开始部署 ===&quot;

# 构建
cd /path/to/project
npm run build

# 同步到服务器
rsync -avz dist/ user@server:/var/www/html/

echo &quot;=== 部署完成 ===&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;set -euo pipefail&lt;/code&gt; 是脚本安全标配，防止命令失败后继续执行。&lt;/p&gt;
&lt;h2&gt;实用别名&lt;/h2&gt;
&lt;p&gt;在 &lt;code&gt;~/.bashrc&lt;/code&gt; 中加入：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;alias ll=&apos;ls -alF&apos;
alias gs=&apos;git status&apos;
alias gp=&apos;git push&apos;
alias gc=&apos;git commit&apos;
alias ..=&apos;cd ..&apos;
alias ...=&apos;cd ../..&apos;

# 重新加载配置
alias reload=&apos;source ~/.bashrc&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;| 命令 | 用途 |
|------|------|
| &lt;code&gt;ls / cd / pwd&lt;/code&gt; | 文件和目录导航 |
| &lt;code&gt;cat / head / tail / less&lt;/code&gt; | 查看文件内容 |
| &lt;code&gt;grep&lt;/code&gt; | 文本搜索 |
| &lt;code&gt;|&lt;/code&gt; (管道) | 连接命令 |
| &lt;code&gt;&gt;&lt;/code&gt; / &lt;code&gt;&gt;&gt;&lt;/code&gt; | 输出重定向 |
| &lt;code&gt;for / while / if&lt;/code&gt; | 控制流 |
| &lt;code&gt;$(...)&lt;/code&gt; | 命令替换 |
| &lt;code&gt;chmod&lt;/code&gt; | 权限管理 |&lt;/p&gt;
&lt;p&gt;Bash 的核心思想：组合小工具完成复杂任务。掌握管道、重定向、变量和控制流，你就能写出高效的命令行工作流。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-18T16:00:00.000Z</atom:updated></item><item><title>从零搭建个人博客：Hugo + GitHub Pages 完整指南</title><link>https://lvdousha26.github.io/blog/blog-from-scratch</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/blog-from-scratch</guid><description>手把手教你用 Hugo 和 GitHub Pages 免费搭建个人博客，从安装到发布只需 30 分钟</description><pubDate>Mon, 18 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;为什么选 Hugo + GitHub Pages&lt;/h2&gt;
&lt;p&gt;| 方案 | 成本 | 速度 | 自由度 |
|------|------|------|--------|
| 知乎/CSDN | 免费 | 快 | 低（广告、限制） |
| WordPress 托管 | ~50/月 | 中 | 中 |
| Hexo + GitHub Pages | 免费 | 快 | 高 |
| &lt;strong&gt;Hugo + GitHub Pages&lt;/strong&gt; | 免费 | 极快 | 高 |&lt;/p&gt;
&lt;p&gt;Hugo 是目前最快的静态站点生成器，2 秒编译 5000 篇文章。GitHub Pages 提供免费无限流量托管。&lt;/p&gt;
&lt;h2&gt;第一步：安装 Hugo&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Windows (推荐用 winget 或 scoop)
winget install Hugo.Hugo.Extended
# 或 scoop install hugo-extended

# macOS
brew install hugo

# Linux
sudo apt install hugo

# 验证安装
hugo version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意装 &lt;strong&gt;extended&lt;/strong&gt; 版（含 SCSS 编译），否则有些主题会报错。&lt;/p&gt;
&lt;h2&gt;第二步：创建站点&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 创建博客
hugo new site myblog
cd myblog

# 初始化 git
git init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;目录结构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;myblog/
├── archetypes/  # 文章模板
├── content/     # 文章内容（核心目录）
├── data/        # 数据文件
├── layouts/     # 页面模板（覆盖主题用）
├── static/      # 静态资源（图片/CSS）
├── themes/      # 主题
└── hugo.toml    # 站点配置
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;第三步：安装主题&lt;/h2&gt;
&lt;p&gt;以本站使用的 &lt;code&gt;hugo-theme-reimu&lt;/code&gt; 为例：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git submodule add https://github.com/D-Sketon/hugo-theme-reimu.git themes/hugo-theme-reimu

# 在 hugo.toml 中设置主题
echo &apos;theme = &quot;hugo-theme-reimu&quot;&apos; &gt;&gt; hugo.toml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其他优秀主题推荐：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PaperMod&lt;/strong&gt; — 极简、快速、功能全&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stack&lt;/strong&gt; — 卡片式布局，适合图文博客&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LoveIt&lt;/strong&gt; — 功能丰富，中文友好&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 &lt;a href=&quot;https://themes.gohugo.io/&quot;&gt;themes.gohugo.io&lt;/a&gt; 上可以浏览 300+ 主题。&lt;/p&gt;
&lt;h2&gt;第四步：写第一篇文章&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;hugo new post/my-first-post.md
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;编辑 &lt;code&gt;content/post/my-first-post.md&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;---
title: &quot;我的第一篇文章&quot;
date: 2026-05-19
tags: [&quot;随笔&quot;]
---
Hello, 这是我的博客！
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 本地预览
hugo server -D

# 打开 http://localhost:1313
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每保存一次文件，浏览器自动刷新。&lt;/p&gt;
&lt;h2&gt;第五步：部署到 GitHub Pages&lt;/h2&gt;
&lt;h3&gt;5.1 创建仓库&lt;/h3&gt;
&lt;p&gt;在 GitHub 创建名为 &lt;code&gt;你的用户名.github.io&lt;/code&gt; 的公开仓库。&lt;/p&gt;
&lt;h3&gt;5.2 配置 GitHub Actions&lt;/h3&gt;
&lt;p&gt;创建 &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;name: Deploy to GitHub Pages

on:
  push:
    branches: [&quot;main&quot;]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive

      - uses: peaceiris/actions-hugo@v3
        with:
          hugo-version: &apos;latest&apos;
          extended: true

      - name: Build
        run: hugo --minify

      - name: Deploy
        uses: peaceiris/actions-gh-pages@v4
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./public
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5.3 推送并启用 Pages&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git add .
git commit -m &quot;init: 博客初始化&quot;
git remote add origin https://github.com/用户名/用户名.github.io.git
git push -u origin main
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后在 GitHub 仓库 &lt;strong&gt;Settings → Pages&lt;/strong&gt; 中，Source 选 &lt;code&gt;GitHub Actions&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;等待 Action 运行完成，访问 &lt;code&gt;https://用户名.github.io&lt;/code&gt; 即可看到博客。&lt;/p&gt;
&lt;h2&gt;第六步：配置与美化&lt;/h2&gt;
&lt;p&gt;编辑 &lt;code&gt;hugo.toml&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;baseURL = &quot;https://用户名.github.io/&quot;
languageCode = &quot;zh-CN&quot;
title = &quot;我的博客&quot;
theme = &quot;hugo-theme-reimu&quot;

[params]
  author = &quot;你的名字&quot;
  description = &quot;记录学习和思考&quot;
  avatar = &quot;avatar.webp&quot;           # 放在 static/ 下
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;头像放在 &lt;code&gt;static/avatar.webp&lt;/code&gt;，favicon 放在 &lt;code&gt;static/favicon.ico&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;进阶配置&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 自定义域名
# 1. 在 static/ 下创建 CNAME 文件，写入你的域名
# 2. 在 DNS 添加 CNAME 记录指向 用户名.github.io

# 添加评论（以 Giscus 为例）
# 1. 开启仓库的 Discussions 功能
# 2. 去 giscus.app 生成配置
# 3. 按主题文档配置

# 自定义 CSS
# 在 assets/css/extended/ 下创建 custom.css
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;日常写作流程&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 1. 新建文章
hugo new post/new-post.md

# 2. 编辑 content/post/new-post.md

# 3. 本地预览
hugo server -D

# 4. 满意后提交
git add content/post/new-post.md
git commit -m &quot;docs: 新文章&quot;
git push

# 5. GitHub Actions 自动部署，2 分钟内上线
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;迁移现有内容&lt;/h2&gt;
&lt;p&gt;| 来源 | 工具 |
|------|------|
| Hexo | &lt;code&gt;hexo-migrator&lt;/code&gt; → Markdown 直接复制 |
| WordPress | 导出 XML → &lt;code&gt;wordpress-to-hugo-exporter&lt;/code&gt; |
| 知乎/CSDN | 手动复制 Markdown（不推荐依赖平台） |
| Jekyll | &lt;code&gt;.md&lt;/code&gt; 文件直接迁移 |&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;| 步骤 | 耗时 | 关键操作 |
|------|------|----------|
| 安装 Hugo | 2 min | &lt;code&gt;brew install hugo&lt;/code&gt; |
| 创建站点 | 1 min | &lt;code&gt;hugo new site&lt;/code&gt; |
| 装主题 | 2 min | &lt;code&gt;git submodule add&lt;/code&gt; |
| 写第一篇文章 | 5 min | &lt;code&gt;hugo new&lt;/code&gt; + 编辑 |
| 部署 | 5 min | GitHub Actions 配置 |
| &lt;strong&gt;总计&lt;/strong&gt; | &lt;strong&gt;~15 min&lt;/strong&gt; | 博客上线 |&lt;/p&gt;
&lt;p&gt;之后每次写作只需 3 步：&lt;code&gt;hugo new&lt;/code&gt; → 写 → &lt;code&gt;git push&lt;/code&gt;。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-18T16:00:00.000Z</atom:updated></item><item><title>Conda 入门</title><link>https://lvdousha26.github.io/blog/conda-tutorial</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/conda-tutorial</guid><description>面向初学者的 Conda 实用教程，掌握虚拟环境、包管理和项目隔离</description><pubDate>Mon, 18 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;为什么要用 Conda&lt;/h2&gt;
&lt;p&gt;Python 项目最大的痛点：不同项目依赖不同版本的 Python 和库。全局安装必然冲突——A 项目要 pandas 1.x，B 项目要 pandas 2.x。&lt;/p&gt;
&lt;p&gt;Conda 通过&lt;strong&gt;虚拟环境&lt;/strong&gt;解决这个问题：每个项目有独立的 Python 版本和包集合，互不干扰。&lt;/p&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;p&gt;推荐 &lt;strong&gt;Miniconda&lt;/strong&gt;（只有基础组件，体量小），不要装 Anaconda（预装几百个用不着的包）。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 下载 Miniconda
# https://docs.anaconda.com/miniconda/

# 安装后初始化（选哪个 shell 就初始化哪个）
conda init bash
# 重启终端后生效
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;环境管理&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 创建环境（指定 Python 版本）
conda create -n myproject python=3.12

# 创建环境并同时装包
conda create -n ml-env python=3.11 numpy pandas matplotlib

# 查看所有环境
conda env list

# 激活 / 退出环境
conda activate myproject
conda deactivate

# 删除环境
conda remove -n myproject --all

# 导出环境配置
conda env export &gt; environment.yml

# 从配置文件重建环境
conda env create -f environment.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;包管理&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 安装包
conda install numpy pandas
conda install -c conda-forge pytorch    # 从指定 channel 安装

# 查看已安装的包
conda list
conda list | grep numpy

# 更新包
conda update numpy
conda update --all           # 更新所有包（谨慎使用）

# 卸载包
conda remove numpy
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Channel（软件源）&lt;/h2&gt;
&lt;p&gt;Conda 从 channel 下载包，默认的 &lt;code&gt;defaults&lt;/code&gt; channel 是官方源，但 &lt;code&gt;conda-forge&lt;/code&gt; 社区源包更多、更新更快。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 设置 conda-forge 为默认 channel（推荐）
conda config --add channels conda-forge
conda config --set channel_priority strict

# 查看当前配置
conda config --show channels
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;推荐设置 conda-forge 为默认源，包版本更全，兼容性更好。&lt;/p&gt;
&lt;h2&gt;最佳实践&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 每个项目一个环境，不要污染 base
conda create -n project-a python=3.12
conda activate project-a
pip install -r requirements.txt    # conda 装不了的包用 pip

# 不要在 base 环境装东西
# conda install xxx  ← 不推荐！
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;conda 和 pip 可以混用，但有一个经验法则：&lt;strong&gt;先 conda install，再 pip install&lt;/strong&gt;。conda 能解决的用 conda，conda 没有的用 pip。&lt;/p&gt;
&lt;h2&gt;提速技巧&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 使用 libmamba solver（比默认求解器快 10 倍+）
conda install -n base conda-libmamba-solver
conda config --set solver libmamba

# 使用国内镜像（如果在国内）
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --set show_channel_urls yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;libmamba solver&lt;/code&gt; 是近两年最关键的优化，求解环境依赖从几分钟缩短到几秒。&lt;/p&gt;
&lt;h2&gt;常用速查&lt;/h2&gt;
&lt;p&gt;| 命令 | 用途 |
|------|------|
| &lt;code&gt;conda create -n name python=3.12&lt;/code&gt; | 创建环境 |
| &lt;code&gt;conda activate name&lt;/code&gt; | 激活环境 |
| &lt;code&gt;conda deactivate&lt;/code&gt; | 退出环境 |
| &lt;code&gt;conda env list&lt;/code&gt; | 列出所有环境 |
| &lt;code&gt;conda install pkg&lt;/code&gt; | 安装包 |
| &lt;code&gt;conda list&lt;/code&gt; | 列出当前环境包 |
| &lt;code&gt;conda env export &gt; env.yml&lt;/code&gt; | 导出环境 |
| &lt;code&gt;conda remove -n name --all&lt;/code&gt; | 删除环境 |&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-18T16:00:00.000Z</atom:updated></item><item><title>Git 入门</title><link>https://lvdousha26.github.io/blog/git-tutorial</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/git-tutorial</guid><description>面向初学者的 Git 实用教程，涵盖核心概念、常用命令和工作流程</description><pubDate>Mon, 18 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;为什么要学 Git&lt;/h2&gt;
&lt;p&gt;写代码最怕两件事：改崩了回不去，多人协作互相覆盖。Git 解决的就是这两个问题——&lt;strong&gt;版本回溯&lt;/strong&gt;和&lt;strong&gt;协作并行&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;简单理解：Git 给你的项目拍快照，随时可以回到任意历史节点，每个协作者各自在自己的分支上干活，最后合并到一起。&lt;/p&gt;
&lt;h2&gt;基础概念&lt;/h2&gt;
&lt;p&gt;| 概念 | 解释 |
|------|------|
| &lt;strong&gt;仓库 (Repository)&lt;/strong&gt; | 被 Git 管理的项目目录，包含完整历史 |
| &lt;strong&gt;工作区 (Working Directory)&lt;/strong&gt; | 你正在编辑的文件，未暂存 |
| &lt;strong&gt;暂存区 (Staging Area)&lt;/strong&gt; | &lt;code&gt;git add&lt;/code&gt; 后的临时区域，准备提交 |
| &lt;strong&gt;提交 (Commit)&lt;/strong&gt; | 一次快照，记录文件变更，有唯一 ID |
| &lt;strong&gt;分支 (Branch)&lt;/strong&gt; | 一条独立的开发线，可并行、可合并 |
| &lt;strong&gt;远程 (Remote)&lt;/strong&gt; | 托管在 GitHub/GitLab 等服务器上的仓库副本 |&lt;/p&gt;
&lt;p&gt;工作流程：&lt;strong&gt;修改文件 → &lt;code&gt;git add&lt;/code&gt; 到暂存区 → &lt;code&gt;git commit&lt;/code&gt; 提交到仓库 → &lt;code&gt;git push&lt;/code&gt; 推送到远程&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;工作区  ──add──▶  暂存区  ──commit──▶  本地仓库  ──push──▶  远程仓库
  ◀─────────── checkout ───────────  ◀── pull ───────────
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;上手配置&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 设置用户名和邮箱（必做）
git config --global user.name &quot;你的名字&quot;
git config --global user.email &quot;your@email.com&quot;

# 设置默认分支名为 main
git config --global init.defaultBranch main

# 查看配置
git config --list
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;日常使用：单人项目&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 初始化新仓库
git init
git add .
git commit -m &quot;init: 项目初始化&quot;

# 关联远程并推送
git remote add origin https://github.com/用户名/仓库名.git
git push -u origin main

# 日常工作循环
git add .                    # 暂存所有修改
git commit -m &quot;feat: 添加登录功能&quot;
git push                     # 推送到远程

# 查看状态和历史
git status                   # 当前有哪些改动
git log --oneline            # 简洁的提交历史
git diff                     # 查看具体改了什么
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;提交信息规范&lt;/h2&gt;
&lt;p&gt;推荐&lt;a href=&quot;https://www.conventionalcommits.org/zh-hans/&quot;&gt;约定式提交&lt;/a&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;#x3C;type&gt;: &amp;#x3C;description&gt;

type 常见取值：
feat     新功能
fix      修复 bug
docs     文档
refactor 重构（不改变功能）
chore    杂项（构建、依赖等）
test     测试
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;好的提交信息一眼能看懂做了什么，别写 &quot;update&quot;、&quot;fix bug&quot; 这种模糊描述。&lt;/p&gt;
&lt;h2&gt;分支操作：多人协作的核心&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 创建并切换到新分支
git checkout -b feature/login

# 查看所有分支
git branch -a

# 在分支上开发然后合并
git checkout main
git merge feature/login        # 把 feature/login 合并到 main

# 删除已合并的分支
git branch -d feature/login

# 切换分支
git switch feature/login       # 新版写法（推荐）
git checkout feature/login     # 旧版写法
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一个典型的工作流：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;main ───●───●───●──────────●────────── (稳定版本)
             \            / (merge)
feature ──────●────●─────●  (开发新功能)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;远程协作&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 克隆仓库
git clone https://github.com/用户名/仓库名.git

# 拉取远程更新
git pull                      # = fetch + merge
git pull --rebase             # 推荐：保持提交历史线性

# 推送本地分支到远程
git push origin feature/login

# 查看远程仓库信息
git remote -v
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;撤销操作：后悔药&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 撤销工作区修改（恢复到上次提交状态）
git checkout -- 文件名
git restore 文件名             # 新版写法

# 取消暂存（add 多了）
git reset HEAD 文件名
git restore --staged 文件名    # 新版写法

# 修改最后一次提交信息
git commit --amend -m &quot;新的提交信息&quot;

# 回退到某个历史版本（保留修改）
git reset --soft HEAD~1       # 撤销提交，改动回到暂存区
git reset --mixed HEAD~1      # 撤销提交和暂存，改动回到工作区

# 彻底回退（丢弃修改，谨慎使用）
git reset --hard HEAD~1       # 回到上一个提交，丢弃所有改动
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;解决冲突&lt;/h2&gt;
&lt;p&gt;当两个分支修改了同一文件的同一行，合并时会产生冲突：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git merge feature/login
# Auto-merging src/main.py
# CONFLICT (content): Merge conflict in src/main.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;冲突文件中会出现标记：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;#x3C;&amp;#x3C;&amp;#x3C;&amp;#x3C;&amp;#x3C;&amp;#x3C;&amp;#x3C; HEAD
print(&quot;main 分支的内容&quot;)
=======
print(&quot;feature 分支的内容&quot;)
&gt;&gt;&gt;&gt;&gt;&gt;&gt; feature/login
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;手动编辑保留需要的部分 → 删除标记 → &lt;code&gt;git add&lt;/code&gt; → &lt;code&gt;git commit&lt;/code&gt; 完成合并。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;减少冲突的技巧：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;经常拉取主分支合并：&lt;code&gt;git pull --rebase&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;分支存活周期不要太长&lt;/li&gt;
&lt;li&gt;一个人尽量只改一个模块&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;实用技巧&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 暂存当前修改，切换到其他分支
git stash                     # 暂存
git stash pop                 # 恢复最近一次暂存

# 查看某行代码是谁写的
git blame 文件名              # 每行代码显示作者和提交

# 查看某个提交的改动
git show &amp;#x3C;commit-id&gt;

# 打标签（标记发布版本）
git tag v1.0.0
git push --tags

# 忽略文件：在项目根目录创建 .gitignore
# node_modules/
# .env
# *.log
# dist/
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;推荐工作流：GitHub Flow&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;1. 从 main 拉出功能分支
2. 在分支上开发和提交
3. 推送到远程，创建 Pull Request
4. 代码审查通过后合并到 main
5. 删除功能分支
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;简单有效，适合个人项目和中小团队。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;| 命令 | 用途 |
|------|------|
| &lt;code&gt;git init / clone&lt;/code&gt; | 创建或获取仓库 |
| &lt;code&gt;git add&lt;/code&gt; | 暂存修改 |
| &lt;code&gt;git commit&lt;/code&gt; | 提交到本地仓库 |
| &lt;code&gt;git push / pull&lt;/code&gt; | 与远程同步 |
| &lt;code&gt;git branch / switch&lt;/code&gt; | 分支操作 |
| &lt;code&gt;git merge&lt;/code&gt; | 合并分支 |
| &lt;code&gt;git stash&lt;/code&gt; | 暂存临时改动 |
| &lt;code&gt;git reset&lt;/code&gt; | 撤销操作 |
| &lt;code&gt;git log / status / diff&lt;/code&gt; | 查看信息 |&lt;/p&gt;
&lt;p&gt;Git 命令很多，但日常用到的就这十几个。关键是理解&lt;strong&gt;工作区 → 暂存区 → 仓库&lt;/strong&gt;的流转，和&lt;strong&gt;分支的创建与合并&lt;/strong&gt;。剩下的边用边查即可。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-18T16:00:00.000Z</atom:updated></item><item><title>本科生论文阅读入门</title><link>https://lvdousha26.github.io/blog/how-to-read-papers</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/how-to-read-papers</guid><description>从选论文到做笔记，一套适合本科生的论文阅读方法，帮你应对毕设和科研入门</description><pubDate>Mon, 18 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;为什么本科生也要读论文&lt;/h2&gt;
&lt;p&gt;三个最常见的场景：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;毕业设计&lt;/strong&gt; — 导师给了方向，你得自己找方法，教材上没有&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;课程大作业&lt;/strong&gt; — 需要了解某个问题的 SOTA 方案&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;决定是否读研&lt;/strong&gt; — 读几篇目标方向的论文，看看自己是否真的感兴趣&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;本科阶段读论文的核心目标不是赶创新点，而是&lt;strong&gt;看懂别人做了什么、为什么这样做&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;开始前的心理建设&lt;/h2&gt;
&lt;p&gt;第一次读英文论文，大概率一页要看半小时，全是生词和看不懂的公式。&lt;strong&gt;这很正常。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;几个事实：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;没人生来就会读论文，都是慢慢练出来的&lt;/li&gt;
&lt;li&gt;一篇 10 页的论文，真正需要逐字读的部分不超过 3 页&lt;/li&gt;
&lt;li&gt;大部分论文不值得精读，学会筛选比学会阅读更重要&lt;/li&gt;
&lt;li&gt;读 3 篇粗略理解的论文 &gt; 啃 1 篇完美理解的论文&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;第一步：知道找什么&lt;/h2&gt;
&lt;h3&gt;GitHub 上的 awesome list 是最好的起点&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 搜 awesome + 你的方向
awesome deep learning
awesome computer vision
awesome nlp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Awesome list 里整理了该方向的综述、经典论文、工具和教程，比数据库盲目搜索高效得多。&lt;/p&gt;
&lt;h3&gt;中文资料先铺路&lt;/h3&gt;
&lt;p&gt;| 资源 | 适合场景 |
|------|----------|
| 知乎搜索&quot;xxx 方向 论文推荐&quot; | 快速了解领域 |
| B 站论文精读视频 | 跟着过一遍核心论文 |
| 中文综述（知网） | 建立领域全景 |
| 公众号技术文章 | 碎片化补充 |
| GitHub 论文列表 + 代码 | 复现实践 |&lt;/p&gt;
&lt;p&gt;先看中文资料搞清楚基本概念和问题定义，再读英文论文，效率翻倍。&lt;/p&gt;
&lt;h3&gt;去哪搜论文&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Google Scholar    — 最通用，搜标题 + PDF 链接
Semantic Scholar  — AI 辅助，能看到被引情况和影响力
Connected Papers  — 输入一篇论文，画出引用关系图
arXiv             — 预印本，最新的论文都在这里
DBLP              — CS 领域按作者/会议查找
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;第二步：快速筛选&lt;/h2&gt;
&lt;p&gt;本科阶段不需要读几十篇。选 5-8 篇真正有用的就够了。&lt;/p&gt;
&lt;h3&gt;优先级排序&lt;/h3&gt;
&lt;p&gt;| 优先级 | 类型 | 说明 |
|--------|------|------|
| 1 | &lt;strong&gt;中文综述&lt;/strong&gt; | 先搞清楚这个方向在做什么 |
| 2 | &lt;strong&gt;经典论文&lt;/strong&gt;（被引 1000+） | 领域的根基，方法都从这里来的 |
| 3 | &lt;strong&gt;带开源代码的论文&lt;/strong&gt; | 能跑起来理解才深 |
| 4 | &lt;strong&gt;最近两年的综述&lt;/strong&gt;（英文 survey） | 了解当前进展 |
| 5 | &lt;strong&gt;最新的 SOTA&lt;/strong&gt; | 如果想自己做改进 |&lt;/p&gt;
&lt;h3&gt;判断一篇论文值不值得读&lt;/h3&gt;
&lt;p&gt;看这四个东西，1 分钟内决定：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;标题和摘要&lt;/strong&gt; — 解决什么问题？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;图表&lt;/strong&gt; — 方法框架图 + 结果对比表&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结论最后一段&lt;/strong&gt; — 作者自己怎么总结贡献&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub 链接&lt;/strong&gt; — 有代码吗？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果看完这四点还不清楚这篇论文干了什么，大概率是论文写得太差，换一篇。&lt;/p&gt;
&lt;h2&gt;第三步：三遍阅读法&lt;/h2&gt;
&lt;p&gt;来自 S. Keshav 的经典方法，针对本科生简化：&lt;/p&gt;
&lt;h3&gt;第一遍：搞清楚做了什么（10-15 分钟）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;标题、摘要&lt;/li&gt;
&lt;li&gt;引言的第一段和最后一段&lt;/li&gt;
&lt;li&gt;章节标题（跳过数学推导）&lt;/li&gt;
&lt;li&gt;所有的图和表&lt;/li&gt;
&lt;li&gt;结论&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;读完要能回答：&lt;strong&gt;这篇论文解决了什么问题？用的什么方法？效果怎么样？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;大多数论文在这遍就可以停了。对本科生来说，第一遍的信息量已经够用来写课程综述或了解一个方向。&lt;/p&gt;
&lt;h3&gt;第二遍：理解怎么做的（30-60 分钟）&lt;/h3&gt;
&lt;p&gt;只对筛选出来的 3-5 篇核心论文进行第二遍。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通读全文，但跳过太复杂的数学推导&lt;/li&gt;
&lt;li&gt;仔细看方法部分的流程图和伪代码&lt;/li&gt;
&lt;li&gt;看实验设置和结果对比&lt;/li&gt;
&lt;li&gt;在页边用中文标注关键点&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;读完要能向同学口头讲清楚这篇论文的方法流程。&lt;/p&gt;
&lt;h3&gt;第三遍：深入细节（可选，只对最想复现的 1 篇）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;逐行读方法部分，推导关键公式&lt;/li&gt;
&lt;li&gt;对比实验中的每个设置&lt;/li&gt;
&lt;li&gt;跑一下作者的开源代码&lt;/li&gt;
&lt;li&gt;思考：这个方法的缺点是什么？如果我来改进能从哪入手？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本科阶段大部分论文不需要到第三遍。毕设相关的最多 1-2 篇到这个深度。&lt;/p&gt;
&lt;h2&gt;第四步：做笔记&lt;/h2&gt;
&lt;p&gt;读完不记等于白读。不用搞太复杂。&lt;/p&gt;
&lt;h3&gt;最简笔记法&lt;/h3&gt;
&lt;p&gt;每篇论文一段话就行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;# AlphaFold (Jumper et al., 2021, Nature)

## 一句话
用深度学习从氨基酸序列预测蛋白质三维结构，准确率接近实验方法。

## 方法核心
输入序列 → Evoformer(MSA+残基对表示) → Structure Module → 3D 坐标

## 关键结果
CASP14 上中位 GDT 92.4，和实验结构误差在 1Å 以内。

## 我的收获
- 用多序列比对(MSA)引入进化信息这个思路很巧妙
- 端到端训练而不是分步流水线
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;工具选择&lt;/h3&gt;
&lt;p&gt;| 工具 | 适合谁 |
|------|--------|
| &lt;strong&gt;Notion&lt;/strong&gt; | 喜欢结构化，建个论文数据库 |
| &lt;strong&gt;Obsidian&lt;/strong&gt; | 喜欢双向链接，论文之间互相关联 |
| &lt;strong&gt;Typora / VS Code&lt;/strong&gt; | 纯 Markdown，够用就行 |
| &lt;strong&gt;语雀 / 飞书文档&lt;/strong&gt; | 和同学共享笔记 |
| &lt;strong&gt;笔记本手写&lt;/strong&gt; | 对公式推导最有帮助 |&lt;/p&gt;
&lt;p&gt;不要纠结工具，刚开始一张 A4 纸 + 一支笔就够。&lt;/p&gt;
&lt;h2&gt;第五步：辅助工具&lt;/h2&gt;
&lt;h3&gt;英文壁垒？不用硬啃&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 翻译工具
DeepL            # 比谷歌翻译准，适合整段翻译
沉浸式翻译插件    # 浏览器插件，左边原文右边译文
ChatGPT/Claude   # 把一段论文贴进去：&quot;用中文解释这段话&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;但注意&lt;/strong&gt;：翻译只是拐杖，核心术语和关键方法还是要用英文思维理解，否则写论文时会很痛苦。&lt;/p&gt;
&lt;h3&gt;看不懂数学公式？&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;先看文字描述，大部分公式都有文字解释&lt;/li&gt;
&lt;li&gt;看不懂的符号去问 ChatGPT：&quot;这个公式里的每个符号是什么意思&quot;&lt;/li&gt;
&lt;li&gt;找带代码的论文，代码比公式好理解&lt;/li&gt;
&lt;li&gt;同类论文的公式差不多，看多了就熟了&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;本科各阶段的阅读建议&lt;/h2&gt;
&lt;p&gt;| 阶段 | 目标 | 建议 |
|------|------|------|
| &lt;strong&gt;大一/大二&lt;/strong&gt; | 培养兴趣 | 看技术博客和科普文章，偶尔翻翻论文的图 |
| &lt;strong&gt;大二暑期&lt;/strong&gt; | 科研入门 | 1 篇中文综述 + 2-3 篇经典论文（到第二遍） |
| &lt;strong&gt;大三上&lt;/strong&gt; | 确定方向 | 1 篇英文综述 + 5-8 篇经典论文 |
| &lt;strong&gt;大三下/毕设&lt;/strong&gt; | 深入做 | 精读 3-5 篇核心论文 + 复现 1-2 篇的代码 |
| &lt;strong&gt;大四&lt;/strong&gt; | 读研过渡 | 浏览 arXiv 追新 + 每周 2-3 篇速读 |&lt;/p&gt;
&lt;h2&gt;常见误区&lt;/h2&gt;
&lt;p&gt;| 错误做法 | 正确做法 |
|----------|----------|
| 从第一页逐字啃 | 三遍过滤，大部分论文停在第一遍 |
| 一篇看不懂死磕一周 | 换一篇同方向的看，看不懂可能是因为这篇写得太差 |
| 只看不记 | 读完立刻写一段话总结 |
| 害怕英文 | 先看中文资料铺路，再用翻译辅助英文 |
| 只囤积不读 | 每周固定时间读，哪怕只读完第一遍 |
| 追求完全理解 | 60% 理解就够用，多读几篇自然会串起来 |
| 不和代码结合 | 有开源代码的一定要跑一下 |&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;本科读论文的核心心态：&lt;strong&gt;别把读论文当成考试，当成探索&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;读不懂是常态，多读几篇自然就通了。你不是在和论文较劲，你是在用论文帮自己搞清楚一个东西。今天读不懂的，也许下周再回头看就懂了——因为你中间的积累在起作用。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-18T16:00:00.000Z</atom:updated></item><item><title>LaTeX 从入门到熟练：学术排版实用指南</title><link>https://lvdousha26.github.io/blog/latex-tutorial</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/latex-tutorial</guid><description>面向初学者的 LaTeX 实用教程，覆盖基础语法、数学公式、图片表格和模板使用</description><pubDate>Mon, 18 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;为什么要学 LaTeX&lt;/h2&gt;
&lt;p&gt;写论文、课程报告、简历时，Word 排版令人头疼——图片乱跑、公式难看、格式不一致。LaTeX 让你&lt;strong&gt;专注内容，排版交给引擎&lt;/strong&gt;，输出的 PDF 是专业出版级别。&lt;/p&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;p&gt;推荐 &lt;strong&gt;TeX Live&lt;/strong&gt;（跨平台完整发行版），不要装基本版（缺包时会很痛苦）。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Windows: 下载 TeX Live 安装器
# https://tug.org/texlive/

# macOS
brew install --cask mactex

# Linux
sudo apt install texlive-full
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在线编辑器推荐 &lt;a href=&quot;https://www.overleaf.com/&quot;&gt;Overleaf&lt;/a&gt;，免安装、协作方便，适合初学者。&lt;/p&gt;
&lt;h2&gt;第一个文档&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-latex&quot;&gt;\documentclass{article}
\usepackage[UTF8]{ctex}   % 中文支持

\title{我的第一份文档}
\author{绿豆沙}
\date{\today}

\begin{document}
\maketitle

\section{引言}
这是第一段内容。

\section{正文}
Hello \LaTeX！

\end{document}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;编译：&lt;code&gt;xelatex main.tex&lt;/code&gt;（中文推荐 xelatex）。&lt;/p&gt;
&lt;h2&gt;基础结构&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-latex&quot;&gt;% 文档类：article / report / book / beamer(幻灯片)
\documentclass[a4paper,12pt]{article}

% 导言区：加载宏包、设置排版参数
\usepackage[UTF8]{ctex}          % 中文
\usepackage{amsmath,amssymb}     % 数学
\usepackage{graphicx}            % 图片
\usepackage{hyperref}            % 超链接
\usepackage{geometry}            % 页面边距
\geometry{margin=2.5cm}

\begin{document}
% 正文内容在这里
\end{document}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;数学公式&lt;/h2&gt;
&lt;p&gt;LaTeX 最大优势：数学公式精确美观。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-latex&quot;&gt;% 行内公式
$a^2 + b^2 = c^2$

% 独立公式（无编号）
\[
e^{i\pi} + 1 = 0
\]

% 带编号公式
\begin{equation}
\int_0^\infty \frac{\sin x}{x} dx = \frac{\pi}{2}
\end{equation}

% 多行对齐
\begin{align}
f(x) &amp;#x26;= x^2 + 2x + 1 \\
     &amp;#x26;= (x + 1)^2
\end{align}

% 矩阵
\begin{pmatrix}
a &amp;#x26; b \\
c &amp;#x26; d
\end{pmatrix}

% 分段函数
f(x) = \begin{cases}
1, &amp;#x26; x &gt; 0 \\
0, &amp;#x26; x = 0 \\
-1, &amp;#x26; x &amp;#x3C; 0
\end{cases}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常用符号速查：&lt;/p&gt;
&lt;p&gt;| 代码 | 效果 |
|------|------|
| &lt;code&gt;\alpha \beta \gamma&lt;/code&gt; | α β γ |
| &lt;code&gt;\sum_{i=1}^n&lt;/code&gt; | ∑ⁿᵢ₌₁ |
| &lt;code&gt;\lim_{x\to\infty}&lt;/code&gt; | limₓ→∞ |
| &lt;code&gt;\frac{a}{b}&lt;/code&gt; | a/b |
| &lt;code&gt;\sqrt{x}&lt;/code&gt; | √x |
| &lt;code&gt;\leq \geq \neq&lt;/code&gt; | ≤ ≥ ≠ |
| &lt;code&gt;\in \subset \forall \exists&lt;/code&gt; | ∈ ⊂ ∀ ∃ |&lt;/p&gt;
&lt;h2&gt;图片&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-latex&quot;&gt;\usepackage{graphicx}

\begin{figure}[htbp]          % h=here t=top b=bottom p=page
\centering
\includegraphics[width=0.6\textwidth]{image.png}
\caption{图片标题}
\label{fig:myimage}
\end{figure}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;引用图片：&lt;code&gt;如图 \ref{fig:myimage} 所示&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;表格&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-latex&quot;&gt;\begin{table}[htbp]
\centering
\begin{tabular}{|c|l|r|}
\hline
序号 &amp;#x26; 名称 &amp;#x26; 数值 \\
\hline
1 &amp;#x26; Alpha &amp;#x26; 100 \\
2 &amp;#x26; Beta  &amp;#x26; 200 \\
\hline
\end{tabular}
\caption{表格示例}
\label{tab:example}
\end{table}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;|c|l|r|&lt;/code&gt; 表示 3 列，分别居中、左对齐、右对齐，带竖线。嫌手写表格麻烦可以用 &lt;a href=&quot;https://www.tablesgenerator.com/&quot;&gt;Tables Generator&lt;/a&gt; 生成。&lt;/p&gt;
&lt;h2&gt;引用与参考文献&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-latex&quot;&gt;% 使用 BibTeX
\bibliographystyle{plain}
\bibliography{references}   % references.bib 文件

% 引用
正如文献 \cite{key} 所述...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;references.bib&lt;/code&gt; 格式：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bibtex&quot;&gt;@article{key,
  author  = {Author Name},
  title   = {Paper Title},
  journal = {Journal Name},
  year    = {2024},
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Google Scholar / DBLP 提供各论文的 BibTeX 导出，直接复制即可。&lt;/p&gt;
&lt;h2&gt;常用模板&lt;/h2&gt;
&lt;p&gt;| 场景 | 推荐 |
|------|------|
| 中文论文 | &lt;code&gt;ctexart&lt;/code&gt; 文档类 |
| 英文论文 | &lt;code&gt;article&lt;/code&gt; + 期刊模板 |
| 学位论文 | 学校提供的 &lt;code&gt;.cls&lt;/code&gt; 模板 |
| 幻灯片 | &lt;code&gt;beamer&lt;/code&gt; 文档类 |
| 简历 | &lt;code&gt;moderncv&lt;/code&gt; 宏包 |
| 伪代码 | &lt;code&gt;algorithm2e&lt;/code&gt; + &lt;code&gt;algpseudocode&lt;/code&gt; |&lt;/p&gt;
&lt;h2&gt;Overleaf 工作流&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;注册 https://www.overleaf.com&lt;/li&gt;
&lt;li&gt;新建项目 → 选模板或空项目&lt;/li&gt;
&lt;li&gt;在线编辑，实时预览&lt;/li&gt;
&lt;li&gt;协作：分享链接，多人同时编辑&lt;/li&gt;
&lt;li&gt;导出 PDF&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Overleaf 是入门最快的方式，省去本地安装的麻烦。语法熟练后再转向本地 TeX Live 即可。&lt;/p&gt;
&lt;h2&gt;调试技巧&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-latex&quot;&gt;% 常见错误：
! Undefined control sequence.    → 命令拼错了或没加载对应宏包
! Missing $ inserted.            → 在普通文本中用了数学符号，加 $...$
! File `xxx.sty&apos; not found.      → 缺宏包，tlmgr install xxx
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;报错先看第一个错误，后面的往往是连锁反应&lt;/li&gt;
&lt;li&gt;大段添加后编译，不要堆到最后才点编译&lt;/li&gt;
&lt;li&gt;Overleaf 默认自动编译，能更快发现错误&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;| 阶段 | 建议 |
|------|------|
| 入门 | 用 Overleaf，免安装，实时预览 |
| 进阶 | 本地装 TeX Live，用 VS Code + LaTeX Workshop 插件 |
| 高效 | 收集常用模板，用 snippets 补全公式 |
| 协作 | Overleaf Share + Git 同步 |&lt;/p&gt;
&lt;p&gt;LaTeX 学习曲线前陡后缓。前两周会觉得麻烦，之后写公式的速度远超 Word 公式编辑器，且输出质量无可替代。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-18T16:00:00.000Z</atom:updated></item><item><title>PyTorch 入门</title><link>https://lvdousha26.github.io/blog/pytorch-tutorial</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/pytorch-tutorial</guid><description>面向初学者的 PyTorch 实用教程，覆盖张量操作、自动求导、数据加载和模型训练</description><pubDate>Mon, 18 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;为什么选 PyTorch&lt;/h2&gt;
&lt;p&gt;深度学习框架分两大阵营：PyTorch（Meta）和 TensorFlow（Google）。2026 年，PyTorch 已在学术界和工业界全面领先——论文复现、顶会代码、HuggingFace 生态几乎全基于 PyTorch。&lt;/p&gt;
&lt;p&gt;核心优势：&lt;strong&gt;动态计算图&lt;/strong&gt;（define-by-run），调试和修改跟在写 Python 一样自然。&lt;/p&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# CPU 版
pip install torch

# CUDA 版（有 NVIDIA 显卡）
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124

# 验证
python -c &quot;import torch; print(torch.__version__); print(torch.cuda.is_available())&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;张量：PyTorch 的基本单元&lt;/h2&gt;
&lt;p&gt;张量（Tensor）就是多维数组，和 NumPy 的 &lt;code&gt;ndarray&lt;/code&gt; 几乎一样，但可以在 GPU 上运算。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import torch
import numpy as np

# 创建张量
a = torch.tensor([1, 2, 3])
b = torch.zeros(3, 4)           # 全 0
c = torch.ones(2, 3)            # 全 1
d = torch.randn(3, 4)           # 标准正态分布
e = torch.arange(0, 10, 2)     # [0, 2, 4, 6, 8]

# 从 NumPy 互转
arr = np.array([1, 2, 3])
t = torch.from_numpy(arr)       # ndarray → tensor
arr2 = t.numpy()                # tensor → ndarray（仅 CPU 上有效）

# 属性
print(d.shape)      # torch.Size([3, 4])
print(d.dtype)      # torch.float32
print(d.device)     # cpu

# GPU 迁移
if torch.cuda.is_available():
    d = d.cuda()    # 或 d.to(&apos;cuda&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;张量运算&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;x = torch.randn(3, 4)
y = torch.randn(3, 4)

# 逐元素运算
z = x + y        # 加法
z = x * y        # 逐元素乘法（不是矩阵乘法）
z = torch.exp(x)

# 矩阵乘法
z = x @ y.T      # @ 是矩阵乘法
z = torch.mm(x, y.T)   # 等价写法

# 维度操作
x = torch.randn(2, 3, 4)
x = x.reshape(2, 12)        # 变形
x = x.view(-1, 12)          # 类似 reshape，但要求内存连续
x = x.squeeze()             # 去掉大小为 1 的维度
x = x.unsqueeze(0)          # 在位置 0 添加一个维度

# 索引
x[:, 0, :]                  # 类似 NumPy 切片
x[x &gt; 0]                    # 布尔索引
torch.cat([x, y], dim=0)    # 拼接
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;自动求导：深度学习的魔法&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# 需要求导的张量设置 requires_grad=True
x = torch.tensor([2.0, 3.0], requires_grad=True)
y = x[0]**2 + x[1]**3       # y = 4 + 27 = 31

# 反向传播
y.backward()
print(x.grad)   # dy/dx = [2*x0, 3*x1^2] = [4.0, 27.0]

# 梯度清零（每次 backward 前都需要）
x.grad.zero_()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;训练循环中的标准 pattern：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# 典型训练一步
optimizer.zero_grad()   # 清零梯度
loss = model(x, y)      # 前向计算
loss.backward()         # 反向求梯度
optimizer.step()        # 更新参数
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;构建神经网络&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import torch.nn as nn
import torch.nn.functional as F

class SimpleNet(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super().__init__()
        self.fc1 = nn.Linear(input_dim, hidden_dim)
        self.fc2 = nn.Linear(hidden_dim, output_dim)
        self.dropout = nn.Dropout(0.3)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = self.dropout(x)
        x = self.fc2(x)
        return x

model = SimpleNet(784, 256, 10)
print(model)
# 打印参数量
print(f&quot;参数量: {sum(p.numel() for p in model.parameters()):,}&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;常用层速查&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;nn.Linear(in, out)       # 全连接层
nn.Conv2d(in_c, out_c, k)# 二维卷积
nn.BatchNorm2d(c)        # 批归一化
nn.LayerNorm(dim)        # 层归一化（Transformer 标配）
nn.LSTM(in, hidden)      # LSTM 层
nn.Dropout(p)            # Dropout 正则化
nn.Embedding(vocab, dim) # 词嵌入层
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;激活函数&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;F.relu(x)       # 最常用，负数归零
F.gelu(x)       # Transformer 标配
F.sigmoid(x)    # 输出 0~1，二分类
F.tanh(x)       # 输出 -1~1
F.softmax(x, dim=-1)  # 多分类概率
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;数据加载&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from torch.utils.data import DataLoader, Dataset

class MyDataset(Dataset):
    def __init__(self, data, labels):
        self.data = data
        self.labels = labels

    def __len__(self):
        return len(self.data)

    def __getitem__(self, idx):
        return self.data[idx], self.labels[idx]

# 通常使用 torchvision 内置数据集
from torchvision import datasets, transforms

transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))
])

train_data = datasets.MNIST(
    root=&apos;./data&apos;, train=True,
    download=True, transform=transform
)

train_loader = DataLoader(
    train_data, batch_size=64,
    shuffle=True, num_workers=4
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;完整训练循环&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import torch.optim as optim

device = torch.device(&apos;cuda&apos; if torch.cuda.is_available() else &apos;cpu&apos;)
model = SimpleNet(784, 256, 10).to(device)

criterion = nn.CrossEntropyLoss()    # 损失函数
optimizer = optim.Adam(model.parameters(), lr=0.001)

num_epochs = 10
for epoch in range(num_epochs):
    model.train()
    total_loss = 0
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        data = data.view(data.size(0), -1)  # 展平图片

        optimizer.zero_grad()
        output = model(data)
        loss = criterion(output, target)
        loss.backward()
        optimizer.step()

        total_loss += loss.item()

    print(f&quot;Epoch {epoch+1}, Loss: {total_loss/len(train_loader):.4f}&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;评估与预测&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;@torch.no_grad()  # 关闭梯度计算，节省显存
def evaluate(model, loader):
    model.eval()
    correct = 0
    total = 0
    for data, target in loader:
        data, target = data.to(device), target.to(device)
        data = data.view(data.size(0), -1)
        output = model(data)
        _, predicted = output.max(1)       # 取概率最大的类别
        total += target.size(0)
        correct += predicted.eq(target).sum().item()
    return correct / total

print(f&quot;准确率: {evaluate(model, test_loader):.2%}&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;保存与加载&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# 保存（推荐保存 state_dict）
torch.save(model.state_dict(), &apos;model.pth&apos;)
# 保存 checkpoint（含优化器状态，方便断点续训）
torch.save({
    &apos;epoch&apos;: epoch,
    &apos;model_state_dict&apos;: model.state_dict(),
    &apos;optimizer_state_dict&apos;: optimizer.state_dict(),
    &apos;loss&apos;: loss,
}, &apos;checkpoint.pth&apos;)

# 加载
model = SimpleNet(784, 256, 10)
model.load_state_dict(torch.load(&apos;model.pth&apos;))
model.eval()  # 推理模式
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;常见问题排查&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# 维度不匹配：打印每层 shape
print(x.shape)

# GPU 显存溢出
torch.cuda.empty_cache()
# 减小 batch_size 或用梯度累积

# 梯度爆炸/消失
# 打印梯度范数
total_norm = 0
for p in model.parameters():
    if p.grad is not None:
        total_norm += p.grad.norm().item() ** 2
print(f&quot;Gradient norm: {total_norm**0.5:.4f}&quot;)
# &gt; 10 可能爆炸，&amp;#x3C; 1e-6 可能消失

# 过拟合
# 加 Dropout、数据增强、weight decay、早停
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;学习路线&lt;/h2&gt;
&lt;p&gt;| 阶段 | 内容 | 预计时间 |
|------|------|----------|
| 入门 | 张量运算 + 自动求导 | 1 天 |
| 基础 | 自己写 MLP + 训练循环 | 2 天 |
| 进阶 | CNN/LSTM/Transformer + 数据加载 | 1 周 |
| 实战 | 复现一篇论文的代码 | 1-2 周 |
| 进阶 | torch.compile / FSDP / 混合精度 | 边用边学 |&lt;/p&gt;
&lt;h2&gt;常用速查&lt;/h2&gt;
&lt;p&gt;| 操作 | 代码 |
|------|------|
| 张量创建 | &lt;code&gt;torch.randn(n, m)&lt;/code&gt; |
| GPU 迁移 | &lt;code&gt;x.to(&apos;cuda&apos;)&lt;/code&gt; |
| 矩阵乘法 | &lt;code&gt;x @ y.T&lt;/code&gt; |
| 自动求导 | &lt;code&gt;loss.backward()&lt;/code&gt; |
| 定义模型 | &lt;code&gt;class Net(nn.Module):&lt;/code&gt; |
| 损失函数 | &lt;code&gt;nn.CrossEntropyLoss()&lt;/code&gt; |
| 优化器 | &lt;code&gt;optim.Adam(model.parameters(), lr=1e-3)&lt;/code&gt; |
| 数据加载 | &lt;code&gt;DataLoader(dataset, batch_size, shuffle)&lt;/code&gt; |
| 推理模式 | &lt;code&gt;@torch.no_grad()&lt;/code&gt; |
| 保存参数 | &lt;code&gt;torch.save(model.state_dict(), path)&lt;/code&gt; |&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-18T16:00:00.000Z</atom:updated></item><item><title>SSH 入门</title><link>https://lvdousha26.github.io/blog/ssh-tutorial</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/ssh-tutorial</guid><description>面向初学者的 SSH 实用教程，涵盖密钥认证、端口转发和常用配置</description><pubDate>Mon, 18 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;什么是 SSH&lt;/h2&gt;
&lt;p&gt;SSH（Secure Shell）是通过加密通道远程登录服务器的标准协议。不仅用于远程执行命令，还能安全传输文件、转发端口、搭建隧道。&lt;/p&gt;
&lt;h2&gt;基础连接&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 用密码登录
ssh user@192.168.1.100

# 指定端口（默认 22）
ssh -p 2222 user@host

# 执行单条命令
ssh user@host &quot;ls -la /var/log&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;密钥认证：更安全且不用输密码&lt;/h2&gt;
&lt;p&gt;密码登录有两大问题：每次要输，容易暴破。密钥认证是标准做法。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 1. 在本地生成密钥对
ssh-keygen -t ed25519 -C &quot;your@email.com&quot;
# 公钥：~/.ssh/id_ed25519.pub
# 私钥：~/.ssh/id_ed25519 （绝不外传）

# 2. 把公钥复制到服务器
ssh-copy-id user@host

# 3. 之后直接登录，无需密码
ssh user@host
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;推荐 Ed25519 算法而不是 RSA：同等安全强度下密钥更短、速度更快。&lt;/p&gt;
&lt;h2&gt;SSH Config：给每台机器起别名&lt;/h2&gt;
&lt;p&gt;编辑 &lt;code&gt;~/.ssh/config&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Host my-server
    HostName 123.45.67.89
    User root
    Port 2222
    IdentityFile ~/.ssh/my-server.key

Host github
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之后直接 &lt;code&gt;ssh my-server&lt;/code&gt;，不用每次记 IP 和端口。&lt;/p&gt;
&lt;h2&gt;文件传输&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# scp：安全复制文件
scp local.txt user@host:/remote/path/    # 本地上传
scp user@host:/remote/file ./            # 下载到本地
scp -r src/ user@host:/remote/           # 递归传目录
scp -P 2222 file user@host:/path/        # 指定端口

# rsync：增量同步（更快，支持断点续传）
rsync -avz ./dist/ user@host:/var/www/   # 同步目录
rsync -avz --delete ./dist/ user@host:/var/www/  # 删除远程多余文件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;scp 适合传单个文件，rsync 适合大型目录同步和部署。&lt;/p&gt;
&lt;h2&gt;端口转发（隧道）&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 本地端口转发：访问本地 8080 等于访问远程 3000
ssh -L 8080:localhost:3000 user@host
# 现在打开 http://localhost:8080 就能访问远程的 3000 端口

# 远程端口转发：让远程服务器能访问你本地的服务
ssh -R 9090:localhost:3000 user@host

# 动态转发（SOCKS 代理）
ssh -D 1080 user@host
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;本地端口转发最常用：比如远程服务器上跑了 Jupyter，你不需要暴露端口，直接通过 SSH 隧道访问。&lt;/p&gt;
&lt;h2&gt;Keep Alive：防止空闲断连&lt;/h2&gt;
&lt;p&gt;在 &lt;code&gt;~/.ssh/config&lt;/code&gt; 中加入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;每 60 秒发一次心跳，连续 3 次无响应才断开。VS Code Remote 用户必备。&lt;/p&gt;
&lt;h2&gt;安全建议&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 服务器端 /etc/ssh/sshd_config 推荐配置：
PermitRootLogin no              # 禁止 root 直接登录
PasswordAuthentication no        # 禁用密码，只允许密钥
Port 2222                        # 改掉默认 22 端口
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;私钥文件权限必须是 600：&lt;code&gt;chmod 600 ~/.ssh/id_ed25519&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;永远不要分享私钥&lt;/li&gt;
&lt;li&gt;定期 &lt;code&gt;ssh -v&lt;/code&gt; 排查连接问题&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;常用速查&lt;/h2&gt;
&lt;p&gt;| 命令 | 用途 |
|------|------|
| &lt;code&gt;ssh user@host&lt;/code&gt; | 远程登录 |
| &lt;code&gt;ssh-keygen -t ed25519&lt;/code&gt; | 生成密钥对 |
| &lt;code&gt;ssh-copy-id user@host&lt;/code&gt; | 上传公钥 |
| &lt;code&gt;scp file user@host:/path&lt;/code&gt; | 传输文件 |
| &lt;code&gt;rsync -avz src/ dest/&lt;/code&gt; | 同步目录 |
| &lt;code&gt;ssh -L 8080:localhost:3000 proxy&lt;/code&gt; | 本地端口转发 |
| &lt;code&gt;~/.ssh/config&lt;/code&gt; | 连接配置别名 |&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-18T16:00:00.000Z</atom:updated></item><item><title>uv 入门</title><link>https://lvdousha26.github.io/blog/uv-tutorial</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/uv-tutorial</guid><description>面向初学者的 uv 实用教程，用 Rust 写的 pip 替代品，快 10-100 倍</description><pubDate>Mon, 18 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;什么是 uv&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/astral-sh/uv&quot;&gt;uv&lt;/a&gt; 是 Astral（Ruff 的团队）用 Rust 写的 Python 包和项目管理器，一个工具替代 &lt;code&gt;pip&lt;/code&gt;、&lt;code&gt;pip-tools&lt;/code&gt;、&lt;code&gt;virtualenv&lt;/code&gt;、&lt;code&gt;pyenv&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;核心卖点：&lt;strong&gt;快 10-100 倍&lt;/strong&gt;。解析依赖和安装包几乎瞬间完成。&lt;/p&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c &quot;irm https://astral.sh/uv/install.ps1 | iex&quot;

# 或者用 pip
pip install uv
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;包管理（替代 pip）&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 安装包（比 pip install 快 10-100 倍）
uv pip install numpy pandas requests
uv pip install -r requirements.txt

# 卸载
uv pip uninstall numpy

# 列出已安装
uv pip list

# 冻结当前依赖
uv pip freeze &gt; requirements.txt

# 编译依赖（生成精确锁定的依赖文件）
uv pip compile requirements.in -o requirements.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;uv pip compile&lt;/code&gt; 是 pip-tools 的替代，能从宽松的 &lt;code&gt;requirements.in&lt;/code&gt; 生成带版本锁定的 &lt;code&gt;requirements.txt&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;虚拟环境（替代 virtualenv）&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 创建虚拟环境
uv venv
uv venv myenv --python 3.12

# 激活（和标准 venv 一样）
source .venv/bin/activate    # Linux/macOS
.venv\Scripts\activate       # Windows
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Python 版本管理（替代 pyenv）&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 安装指定 Python 版本
uv python install 3.12
uv python install 3.11 3.12 3.13   # 一次装多个

# 列出已安装的 Python
uv python list

# 创建环境时指定版本
uv venv --python 3.12
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;项目管理（uv init）&lt;/h2&gt;
&lt;p&gt;uv 支持类似 &lt;code&gt;poetry&lt;/code&gt; 或 &lt;code&gt;npm&lt;/code&gt; 的项目管理模式：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 初始化项目（创建 pyproject.toml）
uv init my-project
cd my-project

# 添加依赖
uv add numpy pandas
uv add --dev pytest ruff       # 开发依赖

# 运行脚本
uv run python main.py
uv run pytest                  # 直接运行工具

# 锁定依赖
uv lock
uv sync                        # 安装所有依赖
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;uv vs 传统工具&lt;/h2&gt;
&lt;p&gt;| 操作 | 传统方式 | uv |
|------|----------|-----|
| 安装包 | &lt;code&gt;pip install&lt;/code&gt; | &lt;code&gt;uv pip install&lt;/code&gt; |
| 虚拟环境 | &lt;code&gt;python -m venv&lt;/code&gt; | &lt;code&gt;uv venv&lt;/code&gt; |
| 安装 Python | &lt;code&gt;pyenv install&lt;/code&gt; | &lt;code&gt;uv python install&lt;/code&gt; |
| 依赖锁定 | &lt;code&gt;pip-tools&lt;/code&gt; | &lt;code&gt;uv pip compile&lt;/code&gt; |
| 项目管理 | &lt;code&gt;poetry&lt;/code&gt; | &lt;code&gt;uv init / add / run&lt;/code&gt; |&lt;/p&gt;
&lt;p&gt;一个工具打通所有环节，且速度碾压。&lt;/p&gt;
&lt;h2&gt;迁移建议&lt;/h2&gt;
&lt;p&gt;| 场景 | 建议 |
|------|------|
| 新项目 | 直接用 &lt;code&gt;uv init&lt;/code&gt; + &lt;code&gt;uv add&lt;/code&gt; |
| 已有项目 | &lt;code&gt;uv pip install -r requirements.txt&lt;/code&gt; 替换 pip |
| 已有 conda 环境 | 用 uv 替代 pip 部分，conda 管理 Python 版本 |
| CI/CD | 把 &lt;code&gt;pip install&lt;/code&gt; 换成 &lt;code&gt;uv pip install&lt;/code&gt;，构建快很多 |&lt;/p&gt;
&lt;h2&gt;常用速查&lt;/h2&gt;
&lt;p&gt;| 命令 | 用途 |
|------|------|
| &lt;code&gt;uv pip install pkg&lt;/code&gt; | 安装包 |
| &lt;code&gt;uv pip compile requirements.in&lt;/code&gt; | 锁定依赖 |
| &lt;code&gt;uv venv --python 3.12&lt;/code&gt; | 创建虚拟环境 |
| &lt;code&gt;uv python install 3.12&lt;/code&gt; | 安装 Python |
| &lt;code&gt;uv init project&lt;/code&gt; | 初始化项目 |
| &lt;code&gt;uv add pkg&lt;/code&gt; | 添加项目依赖 |
| &lt;code&gt;uv run script.py&lt;/code&gt; | 运行脚本 |
| &lt;code&gt;uv sync&lt;/code&gt; | 同步依赖 |&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-18T16:00:00.000Z</atom:updated></item><item><title>Vim 入门</title><link>https://lvdousha26.github.io/blog/vim-tutorial</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/vim-tutorial</guid><description>面向初学者的 Vim 实用教程，掌握核心操作后编辑效率翻倍</description><pubDate>Mon, 18 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;为什么要学 Vim&lt;/h2&gt;
&lt;p&gt;在服务器上改配置、没有图形界面的环境下，你只能用一个终端编辑器。Vim 是几乎所有 Linux 发行版预装的，学会了在任何机器上都能干活。&lt;/p&gt;
&lt;p&gt;它的设计哲学：&lt;strong&gt;大多数时间你是在看/改代码，不是在敲新代码&lt;/strong&gt;。所以默认是&quot;normal 模式&quot;，键盘变成了一堆快捷操作。&lt;/p&gt;
&lt;h2&gt;三种核心模式&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;        按 i / a / o          按 Esc
编辑 ←──────────── 正常 ────────────→ 命令
      ────────────▶      ←────────────
      按 Esc                 按 : / /
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;| 模式 | 作用 | 进入方式 |
|------|------|----------|
| &lt;strong&gt;正常模式&lt;/strong&gt; | 浏览、删除、复制、移动 | 按 &lt;code&gt;Esc&lt;/code&gt; |
| &lt;strong&gt;插入模式&lt;/strong&gt; | 正常打字输入 | &lt;code&gt;i&lt;/code&gt;(光标前) &lt;code&gt;a&lt;/code&gt;(光标后) &lt;code&gt;o&lt;/code&gt;(下一行) |
| &lt;strong&gt;命令模式&lt;/strong&gt; | 保存、退出、搜索、替换 | &lt;code&gt;:&lt;/code&gt; 或 &lt;code&gt;/&lt;/code&gt; |&lt;/p&gt;
&lt;p&gt;核心原则：&lt;strong&gt;手指不离开键盘，持续停留在主键区&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;移动：丢掉方向键&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;h ← 左    j ↓ 下    k ↑ 上    l → 右

w       跳到下一个单词开头
b       跳到上一个单词开头
e       跳到单词末尾
0       跳到行首
^       跳到行首第一个非空字符
$       跳到行尾
gg      跳到文件开头
G       跳到文件末尾
:42     跳到第 42 行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;为什么不用方向键？因为方向键离主键区太远，每次抬手浪费时间。&lt;/p&gt;
&lt;h2&gt;编辑操作&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-vim&quot;&gt;&quot; 删除
x         删除当前字符
dw        删除一个单词
dd        删除整行
d$        删除到行尾

&quot; 复制粘贴
yy        复制整行
yw        复制一个单词
p         粘贴到光标后
P         粘贴到光标前

&quot; 撤销与重做
u         撤销
Ctrl+r    重做

&quot; 其他
.         重复上一次操作（非常有用的快捷操作）
&gt;&gt;        当前行右缩进
&amp;#x3C;&amp;#x3C;        当前行左缩进
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;搜索与替换&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-vim&quot;&gt;&quot; 搜索：按 / 输入关键词，回车
/search_word     &quot; n 下一个匹配，N 上一个匹配

&quot; 替换全文
:%s/old/new/g    &quot; 替换全文所有匹配

&quot; 替换并逐个确认
:%s/old/new/gc   &quot; y 替换，n 跳过
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;多文件与分屏&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-vim&quot;&gt;:split file2.py       &quot; 水平分屏打开另一个文件
:vsplit file2.py      &quot; 垂直分屏
Ctrl+w hjkl            &quot; 在分屏间移动光标
Ctrl+w =               &quot; 分屏大小均分
:bd                    &quot; 关闭当前 buffer
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;实用配置&lt;/h2&gt;
&lt;p&gt;在 &lt;code&gt;~/.vimrc&lt;/code&gt; 中加入：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-vim&quot;&gt;syntax on              &quot; 语法高亮
set number             &quot; 显示行号
set relativenumber     &quot; 显示相对行号（方便跳转）
set expandtab          &quot; 将 Tab 转换为空格
set tabstop=4          &quot; Tab 显示宽度
set shiftwidth=4       &quot; 缩进宽度
set autoindent         &quot; 自动缩进
set hlsearch           &quot; 高亮搜索结果
set incsearch          &quot; 增量搜索
set ignorecase         &quot; 忽略大小写
set smartcase          &quot; 有大写时区分大小写
set mouse=a            &quot; 支持鼠标
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;最少必要命令&lt;/h2&gt;
&lt;p&gt;一天学会 Vim 不太现实，但记住这 10 个操作就能干活了：&lt;/p&gt;
&lt;p&gt;| 操作 | 命令 |
|------|------|
| 开始编辑 | &lt;code&gt;i&lt;/code&gt; |
| 退出编辑 | &lt;code&gt;Esc&lt;/code&gt; |
| 保存 | &lt;code&gt;:w&lt;/code&gt; |
| 退出 | &lt;code&gt;:q&lt;/code&gt; |
| 不保存强制退出 | &lt;code&gt;:q!&lt;/code&gt; |
| 保存并退出 | &lt;code&gt;:wq&lt;/code&gt; 或 &lt;code&gt;ZZ&lt;/code&gt; |
| 删除一行 | &lt;code&gt;dd&lt;/code&gt; |
| 复制一行 | &lt;code&gt;yy&lt;/code&gt; |
| 粘贴 | &lt;code&gt;p&lt;/code&gt; |
| 撤销 | &lt;code&gt;u&lt;/code&gt; |&lt;/p&gt;
&lt;h2&gt;学习路线&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;先用 &lt;code&gt;vimtutor&lt;/code&gt; 命令（Vim 自带教程）过一遍基础操作&lt;/li&gt;
&lt;li&gt;安装一个终端内的练习工具（如 VimBeater）&lt;/li&gt;
&lt;li&gt;日常改配置、写笔记时强制用 Vim，坚持两周&lt;/li&gt;
&lt;li&gt;逐步加插件（NERDtree、fzf、coc.nvim）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;别一上来就堆插件，先把&lt;strong&gt;移动和编辑&lt;/strong&gt;的基本功练熟。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-18T16:00:00.000Z</atom:updated></item><item><title>WSL 入门</title><link>https://lvdousha26.github.io/blog/wsl-tutorial</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/wsl-tutorial</guid><description>面向初学者的 WSL 实用教程，在 Windows 上无缝使用 Linux 的完整指南</description><pubDate>Mon, 18 May 2026 16:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;什么是 WSL&lt;/h2&gt;
&lt;p&gt;WSL（Windows Subsystem for Linux）让你在 Windows 上直接跑原生 Linux 内核，不需要虚拟机。文件互通、网络共享、GPU 直通——相当于 Windows 自带了一个 Linux 开发环境。&lt;/p&gt;
&lt;p&gt;目前推荐 &lt;strong&gt;WSL 2&lt;/strong&gt;（完整 Linux 内核，性能更好）。&lt;/p&gt;
&lt;h2&gt;安装&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;# PowerShell 管理员模式，一条命令搞定
wsl --install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;默认装 Ubuntu。重启后打开 Ubuntu 终端，设置用户名密码即可。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 查看状态
wsl --status
wsl -l -v          # 列出已安装的发行版

# 关闭 WSL（释放内存，重启虚拟机）
wsl --shutdown
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;安装其他发行版&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 查看可用的发行版
wsl -l -o

# 安装指定发行版
wsl --install -d Debian
wsl --install -d Ubuntu-24.04

# 切换默认
wsl --set-default Ubuntu-24.04
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;文件互通&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 在 WSL 中访问 Windows 文件
cd /mnt/c/Users/用户名/
ls /mnt/e/blog/

# 在 Windows 中访问 WSL 文件
# 资源管理器地址栏输入：
\\wsl$\Ubuntu\home\用户名\
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关键原则：&lt;strong&gt;项目文件放 WSL 内&lt;/strong&gt;（&lt;code&gt;/home/xxx/projects/&lt;/code&gt;），不要放 &lt;code&gt;/mnt/c/&lt;/code&gt;。跨文件系统性能差 10 倍以上。&lt;/p&gt;
&lt;p&gt;VS Code 装 &lt;code&gt;WSL&lt;/code&gt; 扩展后，在 WSL 目录下 &lt;code&gt;code .&lt;/code&gt; 即可打开。&lt;/p&gt;
&lt;h2&gt;开发环境配置&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 更新系统
sudo apt update &amp;#x26;&amp;#x26; sudo apt upgrade -y

# 装开发工具
sudo apt install build-essential git curl wget

# 装 Python（用 uv 管理版本，见 uv 教程）
sudo apt install python3 python3-pip

# 装 Node.js（用 nvm 管理版本）
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash
nvm install 22
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;常用开发工具一键安装&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Git
sudo apt install git

# Docker（通过 Docker Desktop 的 WSL 集成）
# 装 Docker Desktop for Windows，设置中启用 WSL 集成即可

# VS Code Remote
# 在 Windows 装 VS Code + Remote WSL 扩展
# 在 WSL 终端中 code . 自动连接
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;性能与配置&lt;/h2&gt;
&lt;h3&gt;限制内存使用&lt;/h3&gt;
&lt;p&gt;在 Windows 用户目录创建 &lt;code&gt;.wslconfig&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ini&quot;&gt;# C:\Users\你的用户名\.wslconfig
[wsl2]
memory=8GB
processors=4
swap=4GB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不加限制的话 WSL 会吃满内存。&lt;/p&gt;
&lt;h3&gt;网络问题&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 如果 Git 或 apt 很慢，换国内镜像
sudo sed -i &apos;s/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g&apos; /etc/apt/sources.list

# 设置代理（如果开了 Clash）
export http_proxy=http://$(cat /etc/resolv.conf | grep nameserver | awk &apos;{print $2}&apos;):7890
export https_proxy=$http_proxy
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;systemd 支持&lt;/h3&gt;
&lt;p&gt;WSL 2 已默认启用 systemd（&lt;code&gt;/etc/wsl.conf&lt;/code&gt; 中配置）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ini&quot;&gt;[boot]
systemd=true
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;实用技巧&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 在 WSL 中直接运行 Windows 程序
notepad.exe ~/.bashrc            # 用 Windows 记事本编辑
explorer.exe .                   # 打开当前目录的资源管理器

# 在 Windows 终端中运行 WSL 命令
# PowerShell 或 CMD 中：
wsl ls -la
wsl bash -c &quot;cd /home &amp;#x26;&amp;#x26; ./deploy.sh&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;| 命令 | 用途 |
|------|------|
| &lt;code&gt;wsl --install&lt;/code&gt; | 安装 |
| &lt;code&gt;wsl -l -v&lt;/code&gt; | 列出发行版 |
| &lt;code&gt;wsl --shutdown&lt;/code&gt; | 关闭（释放内存） |
| &lt;code&gt;wsl --install -d Name&lt;/code&gt; | 安装其他发行版 |
| &lt;code&gt;code .&lt;/code&gt; | VS Code 打开当前目录 |
| &lt;code&gt;.wslconfig&lt;/code&gt; | 限制资源使用 |
| &lt;code&gt;\\wsl$\&lt;/code&gt; | 从 Windows 访问 WSL 文件 |&lt;/p&gt;
&lt;p&gt;WSL 2 是目前 Windows 上最好的 Linux 开发方案——比虚拟机轻量，比双系统方便。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2026-05-18T16:00:00.000Z</atom:updated></item><item><title>转载台湾IMO领队的IMO游记</title><link>https://lvdousha26.github.io/blog/imo-2006</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/imo-2006</guid><description>转载：台湾 IMO 代表队领队亲述第 47 届 IMO 全程，从选题、考试到成绩协调</description><pubDate>Sun, 18 May 2025 16:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;本文搬运自&lt;a href=&quot;https://www.luogu.com.cn/&quot;&gt;我的洛谷博客&lt;/a&gt;，原作者为台湾 IMO 代表队领队，有节选。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;转载一篇长文节选《记2006第47届IMO》，作者是台湾IMO代表队领队。下面是转载正文（有节选）。&lt;/p&gt;
&lt;p&gt;2006年IMO，地点：斯洛文尼亚。&lt;/p&gt;
&lt;h2&gt;7/07 — 审题之日&lt;/h2&gt;
&lt;p&gt;我住的Hotel Riveria 和隔壁的 Hotel Slovenija（左老师住这里）是连锁旅馆，吃饭在前者，开会和大会所有事务都在后者。我到办公室报到，马上领到了预选题，只有题目没有答案。大会的想法是先让领队试做，这样评估难度才比较准。明天一整天是自由时间，就是给大家作题目，明天傍晚才会发解答。我当场没打开来看，因为附带的东西不少，最重要的是学生的名字千万不能错。&lt;/p&gt;
&lt;p&gt;回到房间室友已经呼呼大睡。招呼他去吃饭，他嘟哝了一下翻身继续睡，我就不叫他了。吃完饭后我也非常累，不想作题目了。虽然室友打着呼，外面露天咖啡吧的现场乐团吵得要命，又唱得不好，但是太累了，我也沉沉睡去。&lt;/p&gt;
&lt;p&gt;早上起来并没有睡得很好，还有点晕晕的。七点五十才去吃早餐。吃完饭后我打开了预选题先随便看了一下。&lt;/p&gt;
&lt;p&gt;Oh my god！代数的后三题全部是不等式，A5 又是对称三元不等式，这显然又是那韩国人出的，一阵胃痛，千万不要选上！更夸张的是，Oh my god！没有函数方程，一题也没有！在台湾拼命复习函数方程，真是气结。然后 Oh my god！几何有十题，这破纪录了。然后我翻到组合……Oh my god！组合第四题 C4 是我出的题目。我大胃痛，这一题我自己觉得是 IMO 第五题难度，难写又难改啊，被大会归类在&quot;中等偏难&quot;。后面还有 C5、C6、C7。最后是数论，看起来没有太令人惊艳。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：本届IMO预选题见浙江大学出版社出版的《国际数学奥林匹克预选题解》这本书。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;九点钟开第一次的Jury Meeting，只宣布了一些事情就解散了。今天的工作是让领队做题目，给意见，下午四点半才会给领队答案。今年协调成绩前和学生完全没有见面，实在很糟，还好今年的学生表达能力都还可以，我只担心丕勋太简洁，其它应该都还可以，希望真的如此。&lt;/p&gt;
&lt;p&gt;一整天我都在想这些题目，有几题无从下手。我预测今年题目会比去年难，想到成绩又一阵晕眩。大会相当人性，可以上网，但是仅限于大厅附近。早上主席特别说，禁止上网是没有意义的，科技这么发达，真的要搞鬼绝对有办法，比如说用手机，或是干脆到路边打电话。今年这样开放上网让大家都很窝心，我用 Skype 打电话回家，非常清楚而且同步，只是好笑的是，带来的 USB 听筒居然不管用，所有的声音还是从笔电的喇叭发出来。所以妈妈的声音就回响到大厅，我们还讲了十分钟！反正大厅也吵得要命很多人在讲话，他们也听不懂台语，还有，听到爸爸的声音实在很好。&lt;/p&gt;
&lt;p&gt;一整天我做题并不太顺利。今年的预选题目不太平衡。组合题都很够水平，然后几何也不错，但数论和代数很偏颇，没有我觉得漂亮的题目。一整天下来不时有各国领队的批注和另解出现，有些一看就知道是强者手笔，比如哥伦比亚和罗马尼亚的领队。&lt;/p&gt;
&lt;p&gt;组合第四题 C4 是我出的。本来就是要考高等数学中的一个定理，只是整个问题完全可以用初等的方法来叙述及解决。一早哥伦比亚的领队就给了批注，说这是研究所组合数学里的某个定理。我倒是不惊讶，因为他是 Stanley 的学生，理当对这个非常熟悉。但是他写那个关键的定理是 Well known，大概组合界的人才觉得这是 well-known。不过因为这个批注，我想 C4 大概不会变成正式题目了。&lt;/p&gt;
&lt;p&gt;下午吃完饭，我睡了一个好觉，把早上的疲惫完全补了。四点半拿到参考解答，稍微看了一下，几个题目实在是太难了，光是官方解答都写了满满两页 A4 纸。那是怎样，学生怎么可能会写！然后这样的题目还不只一题，有四五题。我在想今年台湾的成绩不知会烂成什么地步，想到就胃痛。&lt;/p&gt;
&lt;p&gt;批注陆续出现，下午六点多，出现南非领队对于 C4 的批注，他居然说这一题的条件是多的，是错题。我仔细看了后，直呼不可思议，他根本没看懂题目。孰可忍孰不可忍，我写了一个 comment on comment on C4 送给大会，驳斥他的批注，然后回到房间休息。&lt;/p&gt;
&lt;p&gt;回到房间转念一想，其实这很不礼貌，我可以更圆融的。比如先找到他，再请他把批注撤掉，不需要这样公开说他错。数学固然一翻两瞪眼，只有对与错，但是我的批注太针对性，设身处地如果发生在我身上，我会觉得很没面子——这是人之常情。再者，这题目是我出的，这样更不好，万一选到成为正式题目（虽然看来不可能），或者没选到也一样，最后总是大家知道这是台湾出的。对照我手边的驳斥，一看就显得我小家子气。&lt;/p&gt;
&lt;p&gt;就这样，我愈想愈不对，于是我又赶回去办公室，说我要撤掉我的批注。他们已经要开始印了，而且在南非的批注上写：请看台湾领队对此批注的批注——这实在太明显了。刚好大会负责题目的总负责人 Andrej 在场，我说明了情况，说我的批注太有针对性，不礼貌怕伤了和气。他非常理解，说：我来处理。于是他马上帮我找来了南非的领队，是个客气的老先生。我们讨论了一下子，他终于知道他看错题目了，然后答应负责人把批注撤掉，这事情就这样圆满解决。我心情大好，大会负责人很有担当，我这样处理很好，老先生也很明理。&lt;/p&gt;
&lt;p&gt;晚上是某总理的晚宴。室友澳门领队，和大陆领队，香港领队都穿得非常正式。我只打领带没有西装，实在有点羞赧。结果一集合才发现我们是爆正式的。有好几个人都只穿着牛仔裤 T-shirt。我们先走到隔壁的五星饭店，在大厅站者喝一杯鸡尾酒，然后总理致词。十分钟后上二楼吃饭，我已经有点醉了。其实菜色不怎么样，服务和气氛和装潢好是真的。我终于第一次喝了气泡矿泉水，如同两年前肚毛的评语，像没有糖的雪碧，说不出地怪。&lt;/p&gt;
&lt;p&gt;菜色普通，唯一快乐的是烟熏牛肉加哈密瓜，这是去年在意大利旅游认识的日本人 Masa 请客时我知道的名菜，还真是好吃。环顾四周，好像同桌的都不知道这要混在一起吃。我高高兴兴地吃了两盘。看到这里的人一定要试试，教官强力推荐，烟熏牛肉加哈密瓜，不要怀疑，两个一起吃，意外的美味。&lt;/p&gt;
&lt;p&gt;酒足饭饱后大家聊开，大陆领队（LSH）是做财务数学，澳门领队做代数几何，都是有在做研究的。我们讨论最近解决的 Poincare 猜想，谈一谈奥林匹亚数学在各地的情况，还有一些数学消息。这是愉快的晚餐。完了后我们到沿岸的夜市逛了一下，都是在卖手工艺品，还蛮精致的。风景很好，凉风徐徐，相当舒服。明天晚上来照一些相。&lt;/p&gt;
&lt;p&gt;明天要开始投票选题目了，今年的成绩千万不要太夸张。&lt;/p&gt;
&lt;h2&gt;7/08 — 选题之日&lt;/h2&gt;
&lt;p&gt;早上九点开始的选题会议非常值得一记。选题委员会就排排坐在我旁边，这五个可是奥林匹亚界有名的人。先由选题委员会主席 Andrej（也身兼分数总协调，就是昨天帮我找来南非领队的那个头头），先做今年题目的大略介绍，一共有一百三十五题的各国投稿，然后剩下大家手上的 30 题。所以我应该高兴的，进到预选题是不容易的。&lt;/p&gt;
&lt;p&gt;一早左老师要发礼物，问我交换试题要不要一起发。我说且慢，因为我们的交换题目有一题（第三题）和预选题 C2 有相关。虽然 C2 技巧不同，但是图形是一样的至少占一点便宜。如果现在发题目，各国领队看到我们的第三题，C2 就不会选了。左老师一听也觉得有道理，于是交换题目和礼物按下不发，决定见机行事。&lt;/p&gt;
&lt;p&gt;整个过程以以下模式进行：一开始主席设定一个议题，大家充分表达意见，然后提案，然后表决。&lt;/p&gt;
&lt;p&gt;选题正式开始。主席问有没有对任何题目有意见。首先是 N7，有人反应这是一个已知问题的推广，于是投票马上就剔除。我有预感我的 C4 也会被踢掉。然后是 A5，希腊领队说可能见过，又提不出证据。然后是我的 C4，哥伦比亚领队说题目很好，但是可能有极少数学生知道。主席说暂且先保留。然后是 C3，某领队质疑和伊朗刚刚发下交换的伊朗竞赛题很像，伊朗领队也承认是很像，因此投票又剔除。所以你看，我早上的顾虑是有道理的。&lt;/p&gt;
&lt;p&gt;然后有领队提议 N4（本届IMO第5题）其实非常代数，应该移到代数。大家都不满意今年的代数预选题。选题委员会做了解释，主席要大家记住这是跨领域即可。然后四个分类再给意见。代数没人有意见。来到组合。&lt;/p&gt;
&lt;p&gt;德国领队又建议把 C4 去掉，原因同上，他说我们不能冒险。结果投票，41:27 票通过。哎呀，我在国际数学奥林匹亚第一个进入预选题的问题，就这样被封杀了。当场我有点难过，但是后来想想也好，因为如果真的选上了，我会大伤脑筋。这一题真的很难写，也很难改。不要忘了，最后是我要上场协调成绩。这样就变成挖个陷阱自己跳，跟两年前我出的 APMO 2005-4 那题救火员一样，出得大家叫苦连天，最后全台湾没人作对，没必要。能进预选题实际上我已经很高兴了，而且的确有可能有学生可能知道高等数学的背景。&lt;/p&gt;
&lt;p&gt;几何也没人有意见，数论没什么大问题。接着再讨论难易度何者先选，一番意见后主席裁示先选难题，休息到 11:15。开到这里已经知道，主席其实很微妙地主导议题及选题的偏好，我大叹不妙，大会的气氛是今年题目&quot;必须&quot;比较难。其实会发言的领队就那几个，有些真的是无脑。强的领队发言一言九鼎，烂的就是一直要讲一直要讲。&lt;/p&gt;
&lt;p&gt;休息时间时发生了一件惊讶的事。Andrej 主动过来找我，说我们两个在希腊曾经是室友！我想了一下，天啊！真的是！虽然只室友一天，但是他出现时是深夜，离开时又是半夜，而且白天他忙着当筹备会的观察员，我根本没跟他讲几句话。最后开时他还在我行李箱上放了一件纪念 T-shirt。&lt;/p&gt;
&lt;p&gt;休息期间每个人拿到一张投票单，没被踢掉的题目中，各国领队勾选每选的易、中、难，以及平凡、还可以、漂亮。这将是选题的重要依据。&lt;/p&gt;
&lt;p&gt;再度开会。决定了仿照去年，先选三六一组，再选一四一组，然后二和五个别考虑。此时大家拿到投票结果，开始选三六题。经过一番提议及投票最后留下 A6、C5、C6、C7、G8、G10。我私心非常不希望选到 C5、C6 因为这会非常难改，A6 不等式不容易（本届IMO第3题），但是一翻两瞪眼，算不出来就没分，反而好改。加上今年台湾队的情况，我觉得这一题不等式学生会有机会。G8 是困难几何，是我们的强项，我极力赞成。G10 是我们不可能做出来的组合几何（本届IMO第6题），但是现在看来有机会选上。此题和之前我编的组合几何讲义中的一个习题有一点点关系。但是今年没有特别上课，只是发给学生。然后又和两年前我给当年代表队模考的某题目有一点点关系，但是那份资料今年没给，虽然都只有一点点关系。因此我此时懊恼而胃痛不已。&lt;/p&gt;
&lt;p&gt;一番提议后出现五组候选：(A6,G10) (G10,C5) (G10,C6) (C5,G8) (A6,C5)，然后开始投票。投票是每一轮都去掉最低票。首先 (A6,C5) 先被去掉，然后 (C5,G8) 被去掉，然后 (C6,G10) 去掉（我相当扼腕，C6 是非常漂亮的题目）。这整个过程中票数都非常接近，都只有两三票的差别。剩下两个 (A6,G10)、(C5,G10)。所以 G10 已经出线。&lt;/p&gt;
&lt;p&gt;我考虑甚多。我希望 C2 被选上。然后我非常不希望 A5 的三元不等式选上，这题很明显，又是韩国人出的。然后学生已经有错误印象，这种不等式可以暴力，但这一题如果暴力会是灾难，万一选上了会很糟。台湾学生代数能力并不差，A6 固然困难，但是应该可以有一点点进展。比起 C5 的组合，难改又难猜答案，协调分数又困难，实在不是好选择。最后，如果选了 C5，则 C2 就出局了。因此我投了 (A6,G10)。&lt;/p&gt;
&lt;p&gt;结果 (A6,G10) 以 41 票对 (C5,G10) 的 39 票胜出，我的天啊，这实在太刺激了。很明显，虽然大家没明说，但我们都心知肚明，A6 会是第三题，G10 会是第六题。这时组合既然 C3、C4 已经出局，势必只有 C1、C2 可以选，这两题学生应该没问题。如果接下来选一题偏难几何放在 2、5，对我们大大有利。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：A代数，C组合，G几何，N数论。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;时间已到中午。美国领队对这两题，特别是 A6，非常不以为然。他说这些领队根本是选自己不会的题目，没有真的去作作看。其实他讲的没错，我昨天试做了 A6，真的很不容易。我说，我原先的预测是再怎么样 C5 或 C6 会选上一题，这两题都是好题目。结果没有，以组合学家的角度来看我有点遗憾。不过这样也好，大家来拼一二四五。呼应了出国前我跟学生的叮咛：今年题目铁定难，因为前两年简单，加上回到 IMO 发源的东欧洲。所以不要太想着三、六，把一二四五好好做完。现在三、六题根本没什希望，这未尝不是是好事。这样变成有点柳暗花明的感觉。以协调分数来看，最难搞的 C5、C6 已经没有希望了。我现在要祈祷，有一题困难的常规几何在二五题。&lt;/p&gt;
&lt;p&gt;下午开始选一四题时，那些来玩的弱国意见很多，当然主要想法就是不要让学生挂蛋。最后选出了 A1、C1、C2、G1、G2、N1、N3 候选。一番讨论和投票后得到以下组合：(N1,A1)(A1,G1)(N1,G1)(A1,N3)(N3,G1)(N1,G2)(A1,G2)。我心中最好的状况是二五题是 C2 和一题几何——这样对台湾最有利。这样我别无选择，势必要投 (N1,A1)、(A1,N3)。&lt;/p&gt;
&lt;p&gt;事与愿违，IMO 弱国非常希望学生可以拿到分数，因此偏好几何的第一题要选。相当不妙。结果第一轮 (A1,G1)、(A1,G2) 被刷掉，第二轮 (A1,N3) 被刷掉，第三轮 (N3,G1) 被刷掉，第四轮 (N1,A1) 被刷掉，第五轮 (N1,G2) 被刷掉。留下了 (N1,G1)。这状况一喜一忧。忧的是我们的几何强项就这样没了，真的很呕。喜的是这样 C2 势必要选了。&lt;/p&gt;
&lt;p&gt;接着选二五题。35:34 决定先选组合题，再配个其它题。此时居然有人提议 C5，而且还有不少人附议！这疯了吗，这会变成有史以来最难的 IMO。匈牙利领队暨大会主席适时讲了一些反对意见，投票 C5、C1 依次刷掉，顺利选上 C2。&lt;/p&gt;
&lt;p&gt;剩下一题。大家决议继续。现在情势是：第二题会是 C2，然后会要选个第五题。要有代数味道的第五题。剩下的代数 A1-A5 大家都不喜欢，没什么选择，只留下 N3、N4、N5 还有点代数味道。首先 N5 被去掉，留下两题。我觉得 N3 学生可以做，但是要当第五题不够份量。我相信认真弄过 IMO 的人感觉都是一样的。于是此时现场明显分为两派，IMO 审美平衡派，和成绩至上派。&lt;/p&gt;
&lt;p&gt;我非常挣扎，我相信大家也很挣扎。因为刚刚去掉 N5 时，N3 和 N4 都是 40 票。现在只有二选一了，真的很难很难抉择。结果，41:41，同票！全场哗然，大家心中都很难定夺啊。主席裁示充分讨论。最后表决，N4 以 45:37 胜出。我投哪一边呢？不告诉你。&lt;/p&gt;
&lt;p&gt;大家都很累了，但是还是一鼓作气，把顺序也决定。这没什么选择，因为三六题已经固定，一共只剩下四个提案，四个提案中有两个率先出局（NNAGCG、NCAGNG），结果 GCANNG 以 41:37 胜过 GNANCG。就这样，决定了今年 IMO 的六个题目。听说是十年来，第一次一天内就解决的。我不甚满意，但是也只能接受。&lt;/p&gt;
&lt;h2&gt;7/09 — 翻译之日及世界杯之日&lt;/h2&gt;
&lt;p&gt;现在是晚上的十一点二十分，外面不时有汽车狂鸣喇叭呼啸而过，想必是意大利人。半小时前他们赢得了世界杯，我也看得热血沸腾。就在欧洲，2006 年的世界杯我在欧洲。&lt;/p&gt;
&lt;p&gt;早上九点到会场才发现九点是英文版的确定会议。我听了一下子觉得非常无聊，一群人在咬文嚼字。十一点才开会来确定英文版的试题，然后大会说明如何翻译及上传档案。第二题经过七嘴八舌的讨论后，愈改愈乱，实在很受不了。英国领队受命当临时主席，挡掉了一些无厘头的提议。英文版就这样确定了。&lt;/p&gt;
&lt;p&gt;Andrej 接着讲翻译及上传档案。今年的制度设计相当制式化，要用大会提供的模版，然后把各自语言的试题放进去，最后上传档案。一定要用大会提供的格式档案，所以台湾自己带来的完全没用。负责翻译题目的左老师完全不知情，还在外面努力翻译题目。此时我发现大会提供的系统上传时会出大问题，繁体和简体档会传到同一个位置 &quot;Chinese&quot;，后上传的会覆盖掉先传的档。赶快去找 Andrej，中午问题就解决了，把中文分成繁体 Chinese (traditional) 和简体 Chinese (simplified) 两个，处理得非常明确有效率。&lt;/p&gt;
&lt;p&gt;但是我和 Andrej 讨论一下发现问题更大，因为每个学生可以选两个语言的题目卷，除了台湾用繁体，大陆和港澳用简体以外，一共还有来自十几个国家二十几个华裔学生也选 &quot;Chinese&quot;，那现在问题来了，这些学生是繁体还是简体？我说我不可能知道，所以工作人员多一个新工作，要通知那些国家的副领队再和学生重新确认。&lt;/p&gt;
&lt;p&gt;吃饭时总是几个华人凑在一起。其实亚洲人多半一样，一方面个性内向，二方面英文不好就不会去主动攀谈。西方人看亚洲人还是带着轻视的心理。我这几天试着去和一些不熟的领队聊天，结果发现有些很和善，有些也是很难亲近，算了。快吃完时美国领队主动过来找我聊聊，相谈甚欢。美国领队是华人，对中国人和美国人文化差异有相当大的感慨。美国是一个非常竞争的社会，也是一个鼓励奋斗的社会，但是就是因为竞争和鼓励奋斗，才会这么强，才有这么多顶尖的人才。然后他对那些咬文嚼字的领队非常不以为然，因为做不了题，就只好在这上面做文章，证明自己有贡献，我笑了，真是一针见血，所见略同。&lt;/p&gt;
&lt;p&gt;月底就要到美国了。我准备好了吗？这个不上进就被吞噬的社会？我能生存吗？我自己都不知道。昨天在人行道上聊到 Tao 要拿费尔兹奖了，我的心里又一阵翻腾。&lt;/p&gt;
&lt;p&gt;下午继续翻译。换了大会的模版，弄了很久，但不管怎样，我们总算确定了一个版本。要上传时左老师的计算机又突然无法联机，我又跑回去拿我的计算机。无论如何，我们上传了一个翻译版本，放下心中一块石头。办公室也传来台湾学生已经安全抵达的消息。&lt;/p&gt;
&lt;p&gt;此时已经五点四十分，就要开 APMO 会议了。APMO 会议相当沈闷，台湾今年第三名，输美国和韩国，只小胜日本一点点。这是意料中，也没有太惊讶。在财务报告后我问是否能把 APMO 也逐年做成年鉴，把预选题也全放进来。这当场给主席很大的压力。他说也许他今年能做，但是明后年换人接手了，是否有人要做就很难说了。这个意见终究被搁置没有再讨论。接下来选接着三年的负责国家。在没有人要干的情况下，韩国如愿连任。&lt;/p&gt;
&lt;p&gt;七点了才去吃饭。吃完饭想回办公室把下午上传的版本作确认签名，路上迎面遇到选题委员 Savchev，他的脸色非常不好看，主动拉着我抱怨了一堆（Savchev 当初 1998 年台湾办 IMO 时有来台湾选题，是数学竞赛界长老级的人物），他说他看到我，很有亲切感。我们在人行道上讲了快十五分钟有，主要问题是第六题大会官方定版后，大陆和美国领队都去跟他说学生有可能将边的符号 b 当作是边的边长。然后，他问我有没有可能会这样。我说以中文的用法来看，&quot;有可能&quot;会误解题目。他脸色更臭了。因为大陆美国是强队，一旦有学生误会，这可是严重的事。然后他更恼的是，又不是没有开会，为什么在定版开会时不讲话，定版了才要说有问题。我一面安慰他，也答应他我一定再把台湾的题目好好看一看，保证让学生不会有误会。&lt;/p&gt;
&lt;p&gt;听他这样一说，我也紧张起来，赶快上去再看看已经上传的繁体中文版，和大陆简体中文版作比较。比了才发现，大陆根本不照着大会的行文和用语，完全翻成他们习惯的用法。我和左老师乖乖翻译，反而绑手绑脚，显得非常不自然。两相比较就发现大陆翻译好甚多，于是我们把几题改成大陆的版本。左老师明显累了回去休息，我上传，签名，然后到大厅去看世界杯决赛。&lt;/p&gt;
&lt;p&gt;此时已经是 1:1。但是我无心观战，坐了十分钟，一面我一直想着题目，愈想愈慌张。万一学生真的被误导怎么办。乖乖，又到计算机室去仔细看一看。然后再修正了几个地方，传了第二个版本，然后对了又对，才签名。&lt;/p&gt;
&lt;p&gt;身心俱疲走回旅馆——世界杯结束了，我在欧洲，我居然没看到，好难过。但是上天疼好人，一到门口才发现，打加时赛！而且是加时赛的下半场刚开始。门口的电视墙聚集了各国的领队和房客约有三十来人，站者、坐着或喝啤酒。一下子我就发现大部分的人支持意大利，因为是邻居的关系吧。于是我看了十五分钟非常精彩的冠军赛，包括关键的齐达内光头顶胸，红牌出场。居然。居然打到点球大战 PK，而我躬逢其盛，在 2006 的世界杯决赛，同步在欧洲，体会欧洲人的疯狂。&lt;/p&gt;
&lt;p&gt;法国第二颗 PK 没进的那一剎那，坐我旁边的一个非常慈祥和蔼的老太太，站起来发出了一个根本不是人类所能发出的尖叫声音。坐我前面不远处的一个领队显然喝醉了，非常激动，看起来就是足球流氓。坐我旁边的澳门领队，也是我的室友，说：这家伙爱喝酒，每年喝醉了都这样。意大利确定获胜的那一剎那，全场振臂欢呼，我也兴奋地跳了起来。四周都是欢呼声。我看着屏幕上同步的罗马、米兰、拿波里的意大利旗海挥舞，赛场意大利球员和教练抱在一起痛快地发泄，一面跟着高兴，心里却是有点落寞。&lt;/p&gt;
&lt;p&gt;和室友回寝室闲聊了一下，就各自休息了。&lt;/p&gt;
&lt;h2&gt;7/10 — 评分标准之日&lt;/h2&gt;
&lt;p&gt;早上 11:00 才开会，讨论评分标准，因此我本想应该有一些时间可以好好弄清楚这几道题目。我九点就到了会场，想静下来好好想题目，但是新加坡领队说，广告牌上怎么贴了两个版本的繁体中文版？我吓了一跳，去找工作人员更正。然后更吓一跳的是，快要十点时工作人员来找我，说我昨天传的档案他们抓不到。于是我又连忙跑回房间拿档案给工作人员，一来一去半个小时又过去了。结果只把第五题弄了大概，时间就过去了。&lt;/p&gt;
&lt;p&gt;讨论评分标准的会议一开始就很劲爆，伊朗领队早上给了一个用 Lagrange 乘数法作第三题的漂亮方法，这个问题变成微积分可以解，而且还很标准化。英国领队于是提议换题目，换成 N5 当作第三题，他的论点是去年的第三题不等式可以用 Muirhead 定理来证，网络上已经被学生骂到臭头，现在今年又来一个可以用微积分的，是不是太不好。他建议 N5 因为题目短，可以及时翻译。我心里是赞成的，因为 N5 用到费马小定理，是我们熟悉的。但是当初大家根本不考虑 N5，我也根本不考虑，是因为去年就考了费马小定理，今年再考说不过去。换的机会微乎其微。&lt;/p&gt;
&lt;p&gt;大会此时非常严肃，选题委员 Kuzma 上来说明 Lagrange 乘数法的确是方法之一。主席很技巧地不让这个议题成案，后来就不了了之。此时坐在我旁边的 Andrej、Savchev、Kuzma 都长长叹了一口气（因为座位的巧妙分配，我的旁边就是五个选题委员）。我可以想见他们的压力。如果真换题目，可是大工程，所有翻译要重来，太可怕了。&lt;/p&gt;
&lt;p&gt;接下来的讨论评分标准。过程相当无聊。每一题的 chief coordinator 上来展示标准，大家有许多的意见，然后下午再提出定版。就这样中午了。下午继续讨论，一题一题确定了评分标准。特别是第五题，第一步要降到 k=2，第二步要处理 k=2。如果学生直接说，我在哪哪可以看到这个问题可以降到 k=2 的情况，则原本大会的标准是从原来的两分变成一分都没有。这是好事，不能鼓励学生乱背。&lt;/p&gt;
&lt;p&gt;开会时比较有时间仔细看了几个题目。我想一、四一定没问题，二、五只要学生不紧张应该还好——第五题的不动点技巧颇巧妙，但是函数方程讲义如果他们好好吸收，应该还可以。第二题是估构题，是这几年我一直强调的组合题大趋势，奇偶分析加数学归纳法，也应该还好。第三题学生可以因式分解拿一分，接下来我就完全没把握有多少学生作得出来。第六题几乎铁定全挂。这样看起来，今年真的不妙，如果二五有任一题挂掉，就完蛋了。但是既然第三题有 Lagrange 乘数法的方法，也许哲宇或仲恒这两个学过微积分的有一点机会，其它四个人就要看初等变形的功力。至此我预测了最佳状况和最糟状况是 159、125。看着办吧。&lt;/p&gt;
&lt;p&gt;晚上到邻近五分钟车程的一个小半岛 Piran 游览。这是一个类似墨西哥银城和九分混合体的小港，依山而建，相当美丽。Piron 是小提琴家 Tartini 的故乡。广场上有他的雕像，拿着小提琴。我们从广场出发，跟着导游走来走去，最后回到广场。中途经过一些教堂和钟楼。由山上远远往下看，是清可见底的干净。有个老先生全裸在游泳，一下看到这么高的地方有一堆相机，马上面朝下泡在水里。我拿起相机，一面说，啊，美人鱼。旁边的众领队一直笑，也拿起相机跟拍，实在对不起老阿伯。&lt;/p&gt;
&lt;p&gt;导游是观光系打工的学生。他说，对岸那一片灯光就是意大利了。我问，斯洛维尼亚有海军吗？答案是，我们有一艘军舰，还有几艘比较小的船。但是&quot;走得最快的是橡皮巡逻艇&quot;。&lt;/p&gt;
&lt;p&gt;回到广场，本想自己走回旅馆，走二十分钟就到了。但是想上厕所，只好作罢。游览车上和孟加拉国的领队同坐，他拿着论文，物理弦理论的 M-理论。我又想起我的研究。回来才发现大旅馆根本不只三家，路边这三家的后面还有，而且全部是同一家集团的，完全垄断。到柜台看到了价目表，四星的单人房一天要 150 欧元，就是台币六千元。我在这里住十天，就是说主办单位要花台币六万元。IMO 大会当然会讨价还价，但是最多给你杀一半吧，总共 90 个国家的领队，一共也要 300 万。工作人员、副领队、学生、分数协调员、委员会、场地、交通、旅游，都还没算。IMO 已经变成要很有钱才能办的活动，这实在太可怕了。难怪今年委员会找了几个国家的领队问愿不愿意办往后的 IMO，没有一个领队敢说愿意，这种工程，没有国家或是企业的强力后援，是包不得的。&lt;/p&gt;
&lt;h2&gt;7/11 — 开幕之日&lt;/h2&gt;
&lt;p&gt;现在是晚上的九点钟。大厅的钢琴传来肖邦的琴声，波兰舞曲。日本领队正在弹琴，非常年轻的小伙子，大概不到 25 岁。弹得不错，水平以上。参加这种比赛的最大好处，就是你会知道世界上有这么多优秀的聪明的人，然后你就知道自己要更努力。现在是贝多芬热情奏鸣曲第一乐章。这一首略失败，错音太多，应该见好就收。&lt;/p&gt;
&lt;p&gt;今天早上是自由活动时间。我本来想去游泳，但是想想还是快把答案弄清楚比较实际。把第一题和第二题第四题都整理了一下。第五题晚上来弄。然后读了第六题的答案。Alas。我真希望政江今年有来。这个题目是真的有挑战性的。去年前年的满分，我知道他有点遗憾，不够爽快。今年这个题目如果能满分，那就真的是不简单了。&lt;/p&gt;
&lt;p&gt;我边看第六题，&quot;一个凸多边形以每边为底在形内作一个最大的三角形。证明所有的三角形面积至少是原凸多边形面积的两倍&quot;，边赞叹，这个会有多少学生作得出来？这种技巧？没有奥林匹亚经验的人绝对无法体会我在说什么，无法体会找出顶尖学生的迷人和悸动。&lt;/p&gt;
&lt;p&gt;就这样领队们风尘仆仆搭了两个小时的车到利比安那，只为了开幕典礼。我们在二楼，另一边的老师以及选手们在一楼。我占到了最佳位置，二楼第一排正中间。不久傅老师洪老师以及缪老师在一楼出现，再不久吕政次也出现。我们挥手，真是他相遇故知。学生们终于出现，他们看来气色不错，今年台湾队的导游居然是可爱的女生。我和学生快乐地笑着隔着一层楼互相挥手。一面我心里想，明后天你们就笑不出来了，你们不知道今年的题目有多难。&lt;/p&gt;
&lt;p&gt;即使是第三次参加开幕典礼，我仍然很兴奋。大会一开始播放了斯洛维尼亚的国家形象宣传影片。这个国家太年轻，只有自然风景。但是背景音乐太棒，是慷慨激昂的民谣，导演的画面运镜取景和音乐配合得天衣无缝。我看着看着，眼泪又掉下来。我很容易为各个民族的原始深层力量感动。&lt;/p&gt;
&lt;p&gt;司仪是一个讲话的嗲声让我起鸡皮疙瘩的美丽小姐，她的声音实在是，我无法形容。接着是国歌，全场起立。七位女生，无伴奏重唱，唱得相当好。一番行礼如仪，市长讲话，IMO 主席讲话，&quot;教育及体育&quot;部长讲话以及揭幕，宣布大会正式开始。三个音乐家出来表演民谣。吹一段唱一段，有趣的是音乐和人声是不同的调式，刚好差完全五度，相当特殊。&lt;/p&gt;
&lt;p&gt;接着是每年最有趣的各国学生上台。一如往常，许多国家拿着国旗上台，丢糖果以及搞怪的国家也不少。哥伦比亚丢咖啡，澳大利亚丢糖果。意大利在台上表演最后十二码球进球的慢动作回放，全场轰动（法国队一定非常不是滋味），日本在台上表演相扑。各队一面上台，大会一面从旋转的地球中定位拉近这个国家，然后打出六个选手的姓名。每年看到这个都很感动。就这么一个地球，打打杀杀是为了什么。昨晚的新闻是印度孟买火车的连环爆炸，以色列和黎巴嫩一触即发。&lt;/p&gt;
&lt;p&gt;大陆和台湾一如往常，都不拿国旗上台，没有必要互相刺激。大会今年的机制也让国旗没有出现的可能，我不知道这是不是特别细心考虑。其实这几天我和港、澳、大陆的领队都很熟，我们根本不想让政治跑进来这种学生的活动。&lt;/p&gt;
&lt;p&gt;台湾队的学生上台了。上台前司仪还特别讲了一些话，这是地球另一边的国家。奕玮走第一个，接着是宜安、子乔、哲宇、丕勋、仲恒。今年只让六个学生上台，去年是副领队也跟着上台（去年我是副领队，我们脱帽作一个绅士鞠躬）。今年我们的学生中规中矩，一点花样也没，上台、挥手、下台。真是又好气又好笑。&lt;/p&gt;
&lt;p&gt;之后我们这些在二楼的领队们先行退席，我们绕着河走了一下欣赏河岸风光，真的是很美丽。利比安那大学有个欢迎仪式，场地和法庭一模一样，但是实在太热了，草草结束。接着在两个房间里举行拥挤的下午茶，驱车回到 Portoroz。&lt;/p&gt;
&lt;p&gt;今天的目的就是看学生。一整天这样过去。明天要考试了。&lt;/p&gt;
&lt;h2&gt;7/12 — 竞赛第一天&lt;/h2&gt;
&lt;p&gt;九点钟，所有领队聚集在会场。学生上场了。&lt;/p&gt;
&lt;p&gt;学生开始考试，半个小时内学生可以问问题。学生的问题会先传真到大会，出现在一个大屏幕上。领队就去领问题，领完而待解决的问题会出现在第二个屏幕上。然后排队向大会报告你要怎么回答学生的问题，经所有领队认可后才可以。大会会把学生的问题用实物投影机打在大屏幕上，大家同意后，领队写下答案并签名，然后大会传回考场给学生。&lt;/p&gt;
&lt;p&gt;这实在太刺激了。因为学生的问题如潮水涌出，那些看到自己国家代码的领队就很紧张，因为问题不在于回答，在于排队。要排很久才排得到回答。所以等待答案的学生会心急如焚。就这样，四十分钟顺利过去，还好第一天台湾队没有问题。&lt;/p&gt;
&lt;p&gt;现在时间已经是 10:06，考试已经一个小时，但是还有十多个问题等着回答。中间有一些问题僵持不下，就诉诸表决。大部分的问题都卡在第二题的题意，澳大利亚领队到中途建议干脆重新回答，回答得清楚一点，前面已经回答的再回答一遍。这受到大家激烈的反对。科威特的一个学生问，可不可以用波斯文写答案，问题是他们的领队根本不懂波斯文，真的这样没人能改。大会主席提议 no，又受到一堆质疑，说对学生不公平。伊朗领队反问科威特领队那学生能不能写阿拉伯文，结果是可以，问题这样解决。&lt;/p&gt;
&lt;p&gt;中午大会安排去某个钟乳石洞游览。我实在没什么兴趣，天下的钟乳石洞都是一样的。反正就是黑漆漆地寒冷，灯光一打五彩缤纷，垦丁、云南、墨西哥，我已经看了好几个。唯一让我动心的是斯洛维尼亚这个钟乳石洞有一种特殊的鱼，有四只脚，而且肤色就像人的肤色。中午我跟同桌的华人领队们说我大概不去了，想读一点书。&lt;/p&gt;
&lt;p&gt;于是偷得了一个下午的时间。整个下午我坐在 Lobby，读着论文，有一点点的感觉了，但是仍然不知道这要干嘛用。其间 Andrej 忙来忙去，然后过来问我如果我会一直待在 Lobby，今年他们请了两个中文的翻译，会请他们过来找我。我继续念我的书，然后计算机室传来热烈的讨论声，我趋前一看，才发现所有今天中午同桌的中国、香港、澳门、台湾、孟加拉国领队全部都没去，全部在计算机室上网。为什么这么容易被暗示，这是一个有趣的课题。&lt;/p&gt;
&lt;p&gt;讨论声音来自建立 Mathlinks 网站的那个学生。我于是和他聊了一下，他非常多话，有企图心，英文流利，想要做一些事。他还有很多计划，比如多国语言的接口。我问他要经营这样的网站钱从哪来？他说他现在靠着和 AOPS 网站的卖书只能勉强打平，现在想办法推出一个在线要收费的训练课程，希望用这个来挣一点经费。一面我是很佩服他的，年轻人就是不怕困难有冲劲。但是我也很想跟他说，对数学这么有兴趣不应该只局限在对数学竞赛有兴趣。数学竞赛的题目再怎么漂亮，就是轻薄短小的小品，还有学问的无穷尽深邃的大海等着探索。我当然没有对他说。这是我自己经过十年才悟到的道理啊。&lt;/p&gt;
&lt;p&gt;晚上吃饭时和孟加拉国领队同坐。我们已经变成好朋友了。他父亲是经济教授，姊姊是作家，他自己在物理系教书，年纪跟我差不多大。我们聊着选选手的一些轶事，他也抱怨有些学生空有才气没有教养，态度非常 rude。所以有些资优生被排斥不是没有道理的。&lt;/p&gt;
&lt;p&gt;吃完饭，学生试卷已经出现。Andrej 在下午很自豪跟我说，他们今年破纪录快，领队回来前他们一定会把考卷全部影印分类好。结果真的办到了。我拿到考卷看了一下，哲宇的第三题居然一个字也没动，然后第二题也是错的。第一题一如预料全作出来，第二题除了哲宇外应该也都 OK，虽然还没细看。第三题让我高兴了一下，奕玮和丕勋居然弄出来了，好小子，明天不要失常，就有两面金牌了！&lt;/p&gt;
&lt;p&gt;回到寝室我稍微仔细看了第一题，全对没问题。第三题奕玮稳稳七分，丕勋还没细看，但应该也没问题。气结的是因式分解价值一分，居然四个人都没有写出来。这么简单的事情就这样少了四分。而且只要会因式分解接下来就可以找到切入点了，真是有点生气。第二题是大麻烦，目前看到的是除了哲宇外都应该可以过关。要再细细读。第二题是第一个协调分数的题目，千万不要出问题。&lt;/p&gt;
&lt;p&gt;今天选手们算是有发挥水平，考得还好。好的开始是成功的一半。加油。&lt;/p&gt;
&lt;h2&gt;7/13 — 竞赛第二天&lt;/h2&gt;
&lt;p&gt;现在是早上九点四十分。看起来学生提问是结束了，我大大喘了一口气，台湾的学生没有提问题。我最担心会误解题意的第六题安全过关。&lt;/p&gt;
&lt;p&gt;第一天的考试结果谣言满天飞。数学奥林匹亚是非常有趣的比赛，理论上这是学生的个人赛，但是实际上每个人都关心团体成绩。而中美俄这三国几乎是不可动摇的前三名，然后第四到第十五名实力都差不多。我每次都跟学生说只要是第十名加减五都是正常范围，事实上台湾队参加也总是在这个范围内。各国第一天的答题情况充满了耳语，听说听说听说，要改考卷的领队（就是教官我啦）压力就很大。听说大陆队第三题满贯，韩国队三位，但是美国队似乎全爆。我们只有两位，我实在不甚满意。&lt;/p&gt;
&lt;p&gt;今天的题目我只希望学生好好把握第四题和第五题。第六题几乎是不可能的。如果四五都把握，至少会有银牌。两个星期离家在外面实在太久了，我已经很想回去。但是重头戏才刚开始。&lt;/p&gt;
&lt;p&gt;早上把行李搬到大厅，要换旅馆了。待下午副领队洪老师来，会一起住到 Hotel Neptune。接下来是我和他上场了。下午没什么事，我读了一点论文。我希望维持第一天的情况，四五题都顺利，放弃第六题，那这样成绩就不会太难看。&lt;/p&gt;
&lt;p&gt;六点时，一路跟在学生那边的傅老师、洪老师和缪老师抵达。三人脸色都不甚好看，傅老师劈头第一句话就是，第五题只有一个做出来。第四题有两个学生做出来了却忘记有负数解，以大会评分标准要扣一分。Oh my god，这简直是晴天霹雳。我当场脸色一定是青的。这样今年要落到十五名外了。&lt;/p&gt;
&lt;p&gt;当下我实在非常火，作不出来想不出来的就算了，但是那些会的被扣分实在冤枉。在台湾时千交代万交代，如果是会的题目，就稳稳地拿七分，不要东漏西漏扣分。你知道，不会的题目要拿一分两分是比登天还难。现在好了，平白丢了两分，在第四名到第十五名这一群国家的排名内，两分可能会掉三四名。&lt;/p&gt;
&lt;p&gt;吃完饭我拿到学生的解答，这简直是灾难。因为第五题卡太久，第六题全部空白。我的心情非常沉重。第五题有两个大步骤，两步其实都不容易。我们只有三个学生能做出第一步，然后第一天爆掉的哲宇看起来也有弄出第二步，弥补了第一天的失常。但是方法看起来完全不同，写了满满八页，也不知真的是不是做出来了，要详细读一读。&lt;/p&gt;
&lt;p&gt;明天学生会过来一个下午，有机会见面，后天才协调第五题，应该来得及。睡前读了学生的解答，明天协调的是第二题、第三题、第四题。这些应该是好处理的。但是万万我没想到，我太天真了，接下来的两天才是惊心动魄的开始。&lt;/p&gt;
&lt;h2&gt;7/14 — 协调成绩第一天&lt;/h2&gt;
&lt;p&gt;早上 8:00，开始协调成绩。按照大会排的顺序，台湾队首先是 10:30 第二题。大会协调分成许多桌，各司其职。一如往年，前二十名的强队在同一桌，以免标准不一致。&lt;/p&gt;
&lt;p&gt;什么是协调成绩呢，就是大会先留影印本，连夜把答案改出来得到一个成绩。我是领队，和副领队洪老师一起也改一份，得到一个成绩。然后两边当场摊牌。如果一致就两边签名成交，两边不一致就很麻烦，我就要开始努力解释学生的答案，努力争取分数。这时候满场英文飞来飞去，两边都非常努力，我拉高，对方拉低。去年我是副领队，台湾麻烦题的协调大部分都是我下场，所以我倒不紧张。协调的过程就是不要动气，要有耐心，要释出善意，不要无理取闹，慢慢讲就是了。&lt;/p&gt;
&lt;p&gt;第二题我们六个学生（按顺序是奕玮、宜安、子乔、哲宇、丕勋、仲恒）他们估计的分数是 777747。想得美，我看了一下那个 4 根据评分标准只有一分。其它的我看了一下，三个用数学归纳法，两个用对应。大会在大厅贴了一张大海报列出所有的协调时间表。如果双方成交了就用荧光笔画掉，因此所有人很清楚哪些国家在哪些题已经协调完毕。所有国家的部分分数就会贴在另外一面墙上，如同揭榜。大家都很关心成绩，广告牌前万头钻动，很是热闹。&lt;/p&gt;
&lt;p&gt;每个国家每一题排定的时间是半小时。所以在我十点半进去之前理论上有五个国家协调完了。但是十点半一到，我才发现前面所有第二题排在我们前面协调分数的队伍都没有签名。包括保加利亚、韩国、美国，这些全是前十名的强队，全部没有签名。我有不祥的预兆，这一题会非常难搞。&lt;/p&gt;
&lt;p&gt;果然不妙。顶头坐的是 Savchev，选题委员会的大老，以及另一位协调员。这表示这一题绝对没有模糊空间。Savchev 前几天跟我聊的还很开心，现在公事公办，完全就是正直不阿的样子。他问我，你觉得台湾分数怎样，我当然开高价，说，有一个学生错一点，其它都对吧。我说，777747。乖乖，他拿出他的笔记，我瞄了一下。他开的价码是 177117。我简直晕倒，这表示他们觉得有三题完全错，因为那个 1 是显然容易可以得到的。&lt;/p&gt;
&lt;p&gt;我们先把三个 7 确定了，即使如此，他也要我一行一行口译成英文，确定这是完美的 7。但不管怎样，签了三个 7。然后是丕勋的 1。我们在这一题搞了 20 分钟，双方完全没有交集。丕勋写了一页，但是主要的论证只有四行，而且写得极端语焉不详，先用例子稍微说明一下，然后所有接下来才最该要书写的步骤和证明都只浓缩在模糊难以辨识的三个点 &quot;...&quot;。对方两个协调员完全无法接受。&lt;/p&gt;
&lt;p&gt;时间已经到了，我们约了明天中午继续。应 Savchev 要求，我把丕勋的四行翻成英文写下来，让他回去研究。此时我还觉得 ok，因为丕勋基本上的想法和已经得 7 的仲恒是一样的，只是讲得&quot;非常不清楚&quot;，我特别强调其实丕勋的意思是&quot;以此类推&quot;，特别是他有写&quot;...&quot;，所以我想这整个问题可以解决。至于哲宇和奕玮反正我有底，一个错一个对，签名是迟早的问题。就这样结束了第二题的协调，明天再议。&lt;/p&gt;
&lt;p&gt;剩下五题中有四题非常明显。我们的第一题是绝对的 777777 满分，第四题是毫无疑问的是 777667，第三题是毫无疑问的 700070，第六题是惨兮兮的 000000。所以我急着想插队，将这些解决掉，为学生三点会来海边，我可以跟他们再度确认最麻烦的第二题和第五题。经过一番努力，终于在三点前我连续插队四次成功，把这四个问题全部解决，然后等学生到来。&lt;/p&gt;
&lt;p&gt;此时子乔、宜安、仲恒都有三题 7。这三个人的第五题除了仲恒写了无用的寥寥数行外都没写，应该是稳稳的 0。所以这三个人今年是 21 分。以去年的标准这只有铜牌。实在很糟。&lt;/p&gt;
&lt;p&gt;学生到了，我带大家到冰店去坐。我当然高兴不起来，学生脸色也很不好，如果只看总分，去年我们的总分是 190 排第七名，今年即使按照&quot;学生他们的&quot;乐观估计只有 150，但是按大会的评分标准，其实不到 145。但不管怎样，学生总是辛苦了，在考试的当儿，没有人是随便考的。今年卡在第五题是意外的，那个技巧学生完全想不出来。&lt;/p&gt;
&lt;p&gt;在冰店，我和学生来看考卷，其它老师负责陪导游 Marijansa（阳沙）聊天。当然我不免对学生抱怨了一下，为什么要掉那个部分分数，实在很不值得。首先我把第二题三个还没确定的分数和学生讨论了。我要完全确定学生的想法，哪里多写哪里误写等等。我们一致同意第二题奕玮和丕勋应该可以 7、6，哲宇只有 1。然后进到第五题。奕玮 3、丕勋 3 很快就有共识，剩下是哲宇的 7。&lt;/p&gt;
&lt;p&gt;我要他从头把整整八张纸的证明一步一步过给我看。乖乖，光是这个我们花了三十分钟，然后——我们发现这个证明是错的。根据大会标准，只能拿到 3 分。我简直晴天霹雳，哲宇也晴天霹雳，整个人都傻了。不只总分又少 4 分，哲宇搞不好连铜牌都不保了。他是考前我们公认实力最好的一个啊。&lt;/p&gt;
&lt;p&gt;事情总是要作下去，最难过的是学生。我们终究把冰吃完了，然后我跟大家讲了一些话。晚上我把剩下的二五题详细走过一遍，哲宇的第五题我自己作了满满两页的笔记，明天准备发挥我三寸不烂之舌，多一分算一分。确定完已经接近十二点，于是睡了。&lt;/p&gt;
&lt;h2&gt;7/15 — 协调成绩第二天&lt;/h2&gt;
&lt;p&gt;今天实在太刺激了。我已经好久没有这样云霄飞车的心情了。&lt;/p&gt;
&lt;p&gt;原本排定一大早协调第六题已经在昨天插队完成，因此早上轮空，要到中午 12:00 才继续第二题，而第五题是 16:30。我们就聚在 Lobby 不停看着部分成绩出来，心里七上八下。&lt;/p&gt;
&lt;p&gt;快接近中午时突然大会请我去当大陆队第五题的翻译。在一个学生的答案他们有极大的歧见，大陆说 7 分，协调员说 4 分。大陆的两位老师英文都不太溜，然后协调员老教授的东欧口音有点特殊，因此找我过去当翻译。（这整件事是不是很有趣……）以我看，那学生是对的，但是写得不清楚。两位大陆队的老师昨天一整晚几乎没睡，忙着把第六题学生的答案逐句翻译成英文，根本眼睛里都还是血丝，哪有头脑可以想。其间我忠实地当场口译两边的话。协调员一度想赶快处理这题，竟然转而问我，你觉得这个对吗？我吓了一跳，很客气地说，这个我不能表示意见，因为我的职责是翻译，不应该给意见。总之，他们仍然没有交集，于是两边决定先搁置换下一队，大陆等下一轮轮空再讨论。&lt;/p&gt;
&lt;p&gt;就这样回到大厅，没几分钟居然工作人员主动找我说台湾能不能来协调第五题？我当然好，早作早结束。我当然很轻松，因为协调员几分钟前才见过面，而且我想他们对我印象还不错。奕玮 3，子乔和宜安 0 是很快就有共识。然后是哲宇。这个写了满满八张纸，结果是错误的解答。&lt;/p&gt;
&lt;p&gt;我跟协调员说，这份卷子有小错误，我觉得是 6 分。我也瞄到协调员给的成绩，果然只有 3 分。接下来又是 20 分钟的昏天黑地，我非常努力让他们知道整个证明的架构，因为哲宇的想法跟标准解答完全不一样，虽然是错解，但是中间有一些环节是可以通的。我心里的底线是 4 分，3 分我无法接受。经过非常努力而诚恳的沟通后，我想他们完全能感受到我的诚恳，这不是来吵架，是来沟通的。协调员说，6 分太多了，他们建议 5。我喜出望外，马上接受。剩下最后一份仲恒，我觉得是 0，但是我说，这个学生有一点东西，如果有 1 分我会非常高兴。协调员研究了一下子，决定给 1。&lt;/p&gt;
&lt;p&gt;走出协调场地我真的很高兴，这样等于赚到 3 分，而且真的是赚到的。一方面协调顺利很高兴，另一方面很不平衡，努力这么久，然后大家意外在这一题垮掉，搞成这样。你知道数学只有六题，一题作不出来就差非常非常多。但事情就是发生了，算了一算现在是 145，以历届的标准这大概是二十多名。好不容易当了领队出来，今年却可能会是台湾有史以来的最烂成绩，掉出二十名外。傅老师一直安慰我说不会啦，不可能掉出二十名。反正，我开始调适自己，吃完中饭，我觉得我好了一些些，准备迎接回国后记者的乱写乱报导。&lt;/p&gt;
&lt;p&gt;只剩下第二题了的三份考卷了，我的底限是 7、6、1。我太天真了。&lt;/p&gt;
&lt;p&gt;本来约中午协调继续未完的第二题，但是乖乖，中午十二点，理论上已经是协调结束的时候了。但是前二十名的国家&quot;只有两队&quot;签名，新加坡和加拿大。这表示其它十八队都不接受协调员的成绩。我问了新加坡领队到底怎么一回事？他说，他们很坚持啊。此时大会出现一张布告，说第二题有一个看起来对，实际上是假解法（伪证），只有一分。有非常非常多的学生这样写，然后各国都没发现这是错的。协调员非常坚持，只要这样写就一律没分。我没看到这张布告。&lt;/p&gt;
&lt;p&gt;反正吃完饭，我进去弄第二题了。好极了，重重踢到铁板，哲宇的 1 我无话可说，只能同意。然后他们说奕玮的 7 是假解法，他们只给一分。我脸色大变。然后丕勋的算法叙述及证明，协调员说&quot;算法的证明要有 1. 算法的步骤定义 2. 证明他有我们要性质 3. 此算法会停止&quot;，丕勋的 1、2、3 只浓缩成三个点 &quot;...&quot;，而且他给的例子有极大的瑕疵，接下来的变化完全没有考虑。协调员强调这一题所有的评分以学生写出来的白纸黑字为准，和领队的&quot;诠释&quot;无关，这一题所有论证只有 &quot;...&quot; 他们不能给任何分数。协调员也强调他们的标准是全部一致，所有这样写的都只有一分，还翻出一些国家的考卷给我看。&lt;/p&gt;
&lt;p&gt;又搞了二十分钟，两边僵持不下，我拒绝签名，7、6 变成 1、1，少掉 11 分，那还得了。我说晚点我再过来。Savchev 说，因为他很喜欢我，他很诚心的建议，这不是时间的问题，是数学对错的问题，这个假解法太精巧，很难被发现，但是假解法就是假解法，数学只有对错。他们的标准是一致的。我说，我了解，但是我要再确定。&lt;/p&gt;
&lt;p&gt;洪老师把傅老师找来了。我们一起商讨对策，我们根本没有对策，因为我看到了那张布告，然后的确，奕玮是假解法，这错得太精巧了。大会在这一题必定坚持，这两份考卷的确都是 1、1。这时代表团里实在是超级低气压。我实在非常沮丧。&lt;/p&gt;
&lt;p&gt;在沉默的气压下，我再把奕玮的考卷翻一遍。老天啊！奕玮把这题写了两遍。第一遍写得乱七八糟，第二遍是整理过的。但是第二遍是假解法，第一遍的前一半是对的！这简直是绝望中的一线光明。&lt;/p&gt;
&lt;p&gt;近三点我进去协调。丕勋的 1 只好认了，然后我说奕玮 4 分。Savchev 非常讶异，我说学生写了另外一个版本，有一半是对的。他更讶异了，因为他没看到。我翻出来给他们看，然后经过约十分钟，我们签下了 4。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：正是这 4 分帮助该选手获得当年台湾唯一 IMO 金牌。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;就这样今年的成绩全部确定。奕玮 28，宜安 21，子乔 21，丕勋 25，哲宇 19，仲恒 22。大概是二银四铜。已经没感觉了。剩下的时间我根本不想留在大厅，缪老师和洪老师也不好受，我们三个就约了去海泳。总之，泡一泡水，天光水影，把不愉快的事情忘掉。&lt;/p&gt;
&lt;p&gt;晚餐后回到大厅，九点要开领队会议，确定得奖标准。在众人的耳语中我听出今年分数非常低，金牌可能只有 28。我吓了一跳，连忙找了一台计算机看成绩。这是喜出望外，台湾队居然暂居第九名！一直到刚刚我都很确定会在二十五名左右。只剩下两个国家分数还没出来。我心情一片大好，数学不比其它科，只考六题，四到十五名的国家几乎程度相同，就看临场表现。这样最糟也是十一，是完全可以接受的正常成绩。&lt;/p&gt;
&lt;p&gt;我开始涌出保前十名的渴望，但非常不妙，另两个国家是……去年出了一个拿满分荣获特别奖选手的摩尔多瓦，以及总是在前十名的保加利亚。此时台湾 136 分排第九，分数已经确定。摩尔多瓦 133 排第十，剩下第六题。第六题绝大部分国家都没人作对，但是摩尔多瓦有特别的选手。不久，成绩确定。果然摩尔多瓦加上七分 140，把台湾队挤到第十。&lt;/p&gt;
&lt;p&gt;剩下保加利亚，我开始紧张。保加利亚现在 102，差我们 34 分，看起来没竞争力。但是问题是，还没出来的成绩是第二题。保加利亚是竞赛强国，今年第二题美国和中国是满分 42，所以保加利亚如果超过 34 分，我们就爆了，而这很有可能。你看看，这是怎样的一个情况，要开大会了，然后保加利亚分数迟迟不出来，然后看起来完全无关的台湾领队，在穷紧张。&lt;/p&gt;
&lt;p&gt;大会延了半小时开始，两个国家不服协调上诉大会。第一个，表决不给分。第二个，保加利亚，表决，不给分。这时，我确定我们保住前十，真是高兴极。&lt;/p&gt;
&lt;p&gt;接着决定奖牌线，28 金、19 银、15 铜。就这样，我们拿到一金五银，非常完美的结果。&lt;/p&gt;
&lt;p&gt;开完会已经十一点半，但是真的很高兴，这次出来的队伍师生彼此都知道比前两年稍弱，但是现在一金五银总分第十，总算还是不负使命。终于可以睡个好觉了。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2025-05-18T16:00:00.000Z</atom:updated></item><item><title>2019 qbxt 普及营济南游记</title><link>https://lvdousha26.github.io/blog/qbxt-jinan-2019</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/qbxt-jinan-2019</guid><description>初一暑假第一次参加 OI 培训的见闻与回忆</description><pubDate>Sun, 18 May 2025 16:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;本文搬运自&lt;a href=&quot;https://www.luogu.com.cn/&quot;&gt;我的洛谷博客&lt;/a&gt;，原文写于 2019 年。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;第一次去外面培训机构上课，既紧张又兴奋。但是只有我一个人。在鲁粮精品酒店，里大明湖很近但并没有去，遗憾。舍友day0都去旅游了。发了本子和笔，还有你的名字的营员证。&lt;/p&gt;
&lt;p&gt;舍友大我两三岁，那时我初一毕业，现在他们应该已经退役上大学了吧，不知道后来怎么样了，没留联系方式，甚至连名字都不知道，不是忘了，是当时就不知道。有两个舍友，其中一个是临沂实验中学的，去省选班，一个去DP图论班，似乎一个是准高二一个是准高一，印象很深的是舍友在宿舍玩一个单机枪战游戏，不是GTA5。现在也不知道是什么。大我三岁的舍友在玩永夜抄，还邀请我一起玩，但我太菜了~那一年2019年方舟刚出不久，4月？他们两个在床上交流方舟。&lt;/p&gt;
&lt;p&gt;第一个讲师是钟浩曦,然后是梁家铭，赵和旭，钟皓曦告诉我们STL很慢。有人拍了钟皓曦和赵和旭的照片。&lt;/p&gt;
&lt;p&gt;zhhx讲了他的网名是为了避免和zhx起重zhhx胸肌很发达，可以左边动一下右边动一下（看QQ空间发现的。zhhx还现场表演了一下。&lt;/p&gt;
&lt;p&gt;&quot;赵合肥&quot;&lt;/p&gt;
&lt;p&gt;zhhhx对我们谈了他的理想。&lt;/p&gt;
&lt;p&gt;在火车站遇到了zhhx。&lt;/p&gt;
&lt;p&gt;zhx空间里全是秀恩爱撒狗粮。&lt;/p&gt;
&lt;p&gt;有人拍了zhx和zhhx的黑照。&lt;/p&gt;
&lt;p&gt;那时讲课的题不是bzoj就是loj poj hdu，在洛谷上找很麻烦。似乎老师没有洛谷号。已经是又一代oier了。&lt;/p&gt;
&lt;p&gt;陈博坐在我左边。后来他成了我的学长。&lt;/p&gt;
&lt;p&gt;那时还没有新冠......&lt;/p&gt;
&lt;p&gt;模拟赛Rk3拿了个键盘
~~人生巅峰~~&lt;/p&gt;
&lt;p&gt;怕以后忘掉所以用了真名。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2025-05-18T16:00:00.000Z</atom:updated></item><item><title>Hello World</title><link>https://lvdousha26.github.io/blog/hello-world</link><guid isPermaLink="true">https://lvdousha26.github.io/blog/hello-world</guid><description>第一篇文章</description><pubDate>Wed, 19 Mar 2025 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Welcome to &lt;a href=&quot;https://hexo.io/&quot;&gt;Hexo&lt;/a&gt;! This is your very first post. Check &lt;a href=&quot;https://hexo.io/docs/&quot;&gt;documentation&lt;/a&gt; for more info. If you get any problems when using Hexo, you can find the answer in &lt;a href=&quot;https://hexo.io/docs/troubleshooting.html&quot;&gt;troubleshooting&lt;/a&gt; or you can ask me on &lt;a href=&quot;https://github.com/hexojs/hexo/issues&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Quick Start&lt;/h2&gt;
&lt;h3&gt;Create a new post&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ hexo new &quot;My New Post&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;More info: &lt;a href=&quot;https://hexo.io/docs/writing.html&quot;&gt;Writing&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Run server&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ hexo server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;More info: &lt;a href=&quot;https://hexo.io/docs/server.html&quot;&gt;Server&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Generate static files&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ hexo generate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;More info: &lt;a href=&quot;https://hexo.io/docs/generating.html&quot;&gt;Generating&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Deploy to remote sites&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ hexo deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;More info: &lt;a href=&quot;https://hexo.io/docs/one-command-deployment.html&quot;&gt;Deployment&lt;/a&gt;&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/><atom:updated>2025-03-19T16:00:00.000Z</atom:updated></item></channel></rss>