<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>ctyyy</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://tysweb.pages.dev/</id>
  <link href="https://tysweb.pages.dev/" rel="alternate"/>
  <link href="https://tysweb.pages.dev/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, ctyyy</rights>
  <subtitle>Record myself</subtitle>
  <title>ctyyy的博客</title>
  <updated>2026-09-07T01:31:21.933Z</updated>
  <entry>
    <author>
      <name>ctyyy</name>
    </author>
    <category term="Multi-agent system for MDT" scheme="https://tysweb.pages.dev/categories/Multi-agent-system-for-MDT/"/>
    <category term="多智能体" scheme="https://tysweb.pages.dev/tags/%E5%A4%9A%E6%99%BA%E8%83%BD%E4%BD%93/"/>
    <category term="MDT" scheme="https://tysweb.pages.dev/tags/MDT/"/>
    <content>
      <![CDATA[<blockquote><p>这一组决定你对”多智能体””MDT””综述定位”的基本理解。读的时候不要追求记住每个细节，要追求”能用自己的话讲清楚一个完整故事”。</p></blockquote><h1 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h1><table><thead><tr><th>#</th><th>文献（按参考编号）</th><th>论文原名称</th><th>对应综述章节</th><th>要学到的核心内容</th><th>读完要能回答的问题</th></tr></thead><tbody><tr><td>1</td><td>44. Konzmann et al. (2026) LLM in tumor boards: systematic review</td><td>Applications of large language models in tumor boards: a systematic review</td><td>引言、4.3</td><td>现有 MDT+LLM 综述怎么定义范围、怎么组织证据、结论是什么；这是你的”锚点综述”</td><td>它与你的综述本质区别是什么？哪些内容是它没覆盖的？</td></tr><tr><td>2</td><td>33. Guo et al. (2024) LLM-based multi-agents survey</td><td>Large language model based multi-agents: a survey of progress and challenges</td><td>3.1、3.2</td><td>LLM 智能体的定义（工具、RAG、记忆、规划、反思）；多智能体的通用分类</td><td>“智能体”和”多智能体”怎么定义？为什么需要多个智能体？</td></tr><tr><td>3‌✅</td><td>54. Li, X. et al. (2024) LLM-based MAS: workflow, infrastructure, challenges</td><td>A survey on LLM-based multi-agent systems: workflow, infrastructure, and challenges</td><td>3.1、4.5</td><td>多智能体从工作流、基础设施、挑战三个角度的全景框架</td><td>多智能体系统为什么难做？瓶颈在哪几层？</td></tr><tr><td>4✅</td><td>96. Yao et al. (2026) AI hospitals survey</td><td>LLM-based multi-agent systems for clinical workflows: a survey of AI hospitals</td><td>3.1、3.3、3.5</td><td>医疗多智能体如何组织临床工作流；AI 医院类模拟环境如何评测</td><td>AI 医院类工作与肿瘤 MDT 场景的异同？</td></tr><tr><td>5✅⭐</td><td>92. Xiong et al. (2026) MAS for medicine: accountable orchestration</td><td>Not just one agent: LLM-based multi-agent systems for medicine from answer generation to accountable workflow orchestration</td><td>3.1、4.1</td><td>医疗多智能体从”生成答案”到”工作流编排”的演变；可问责性</td><td>医疗多智能体为什么强调”可问责”？</td></tr><tr><td>6✅</td><td>84. Tang et al. (2024) MedAgents</td><td>MedAgents: large language models as collaborators for zero-shot medical reasoning</td><td>3.2.1、3.4</td><td>最早的医疗多智能体框架之一：角色化、协作讨论、零样本推理</td><td>角色扮演为什么能提升医学推理？MedAgents 的流程长什么样？</td></tr><tr><td>7</td><td>43. Kim et al. (2024) MDAgents</td><td>MDAgents: an adaptive collaboration of LLMs for medical decision-making</td><td>3.2.1、3.2.3、3.4</td><td>自适应协作：根据任务难度选择独诊&#x2F;团队；这是”协作+层级”的交界</td><td>自适应协作解决了什么问题？它和固定团队的区别？</td></tr><tr><td>8</td><td>13&#x2F;15. Chen, K. et al. MDTeamGPT (2025&#x2F;2026)</td><td>MDTeamGPT: a self-evolving LLM-based multi-agent framework for multi-disciplinary team medical consultation；MDTeamGPT: mitigating context collapse and enabling self-evolution in medical multi-agent reasoning</td><td>3.2.4、3.4、3.6.2</td><td>共识聚合+残余讨论+知识库；”上下文崩塌”问题</td><td>上下文崩塌是什么？系统怎么缓解？</td></tr><tr><td>9</td><td>58. Liu, Q. et al. (2026) EvoMDT</td><td>EvoMDT: a self-evolving multi-agent system for structured clinical decision-making in multi-cancer</td><td>3.2.4、3.4、4.2</td><td>自进化 MDT 系统：根据专家反馈和结局信号更新提示词、权重、检索范围</td><td>自进化在 MDT 中如何实现？它和普通多智能体的差异？</td></tr><tr><td>10</td><td>85. Vasilev et al. (2025) MTBBench</td><td>MTBBench: a multimodal sequential clinical decision-making benchmark in oncology</td><td>3.5、4.4</td><td>肿瘤会诊专用基准：多模态、纵向、证据调和</td><td>MTBBench 为什么比通用基准更适合 MDT？它测出了什么失败？</td></tr><tr><td>11</td><td>104. Zhu, Y. et al. (2025) MedAgentAudit</td><td>Auditing medical multi-agent AI reveals risks of false consensus</td><td>3.2.2、3.6.1、4.5</td><td>审计多智能体执行日志；虚假一致、沉默同意、未激活专科推理</td><td>审计发现了哪几类协作失败？为什么”辩论”不一定可靠？</td></tr><tr><td>12</td><td>27. Gallifant et al. (2025) TRIPOD-LLM</td><td>The TRIPOD-LLM reporting guideline for studies using large language models</td><td>3.6.4、4.5</td><td>LLM 研究报告的最低报告要求</td><td>TRIPOD-LLM 有几个条目？它如何支撑你综述的”评测不足”论点？</td></tr></tbody></table><hr><h1 id="文献"><a href="#文献" class="headerlink" title="文献"></a>文献</h1><h2 id="①A-survey-on-LLM-based-multi-agent-systems-workflow-infrastructure-and-challenges"><a href="#①A-survey-on-LLM-based-multi-agent-systems-workflow-infrastructure-and-challenges" class="headerlink" title="①A survey on LLM-based multi-agent systems: workflow, infrastructure, and challenges"></a>①A survey on LLM-based multi-agent systems: workflow, infrastructure, and challenges</h2><h3 id="论文框架"><a href="#论文框架" class="headerlink" title="论文框架"></a>论文框架</h3><p>论文在引言部分给出一个统一的智能体框架，包含五个部分：</p><ol><li>Profile：agent 如何被创建和选用？</li><li>Perception：agent 如何感知环境信息、丰富自己的知识库？</li><li>SelfAction：agent 如何利用记忆机制储存信息、如何推理复杂任务？</li><li>Mutual interaction：多 agent 系统中，智能体之间如何相互通信？</li><li>Evolution：智能体如何通过自我批评实现自我进步？</li></ol><h3 id="MAS算法支撑"><a href="#MAS算法支撑" class="headerlink" title="MAS算法支撑"></a>MAS算法支撑</h3><p>每个 agent 都能独立感知环境并做出决策，也可以通过模拟现实世界中的协作模式（合作、竞争、分层组织）与其他智能体交互，从而提高整体协作效率。这类系统通常融合控制理论与强化学习方法实现，MARL 算法是核心。Marllib（论文引用的 MARL 库）用四个维度区分这些算法：</p><ol><li>task patterns</li><li>agent types</li><li>learning styles</li><li>knowledge sharing</li></ol><h3 id="MAS系统的结构分类"><a href="#MAS系统的结构分类" class="headerlink" title="MAS系统的结构分类"></a>MAS系统的结构分类</h3><p><code>[25]</code> 根据 MAS 的特征将其分为两类，这是层次划分：</p><ol><li>agent-level（智能体层面）：看单个智能体本身长什么样，比如它有哪些能力、是同质还是异质。</li><li>system-level（系统层面）：看整个系统怎么组织，比如通信方式、控制结构。</li></ol><p><code>[26]</code> 用两个维度交叉出四种原型，这是维度划分：</p><ol><li><p>agent heterogeneity（智能体异质性）：智能体是全都一样，还是各不相同；</p><ul><li>homogeneous（同质智能体）：几个智能体能力、角色相同，干类似的活；</li><li>heterogeneous（异质智能体）：每个智能体有不同专长，靠各自能力互补协作。</li></ul><p>放在 MDT 里看：五个”影像科医生智能体”一起读片子就是同质；一个肿瘤内科、一个影像科、一个病理科组队就是异质。异质组合的价值在于互补。<u>结构越灵活，系统越能适应不同任务和环境变化；异质智能体之间能互补、产生协同效应</u></p></li><li><p>communication level（通信水平）：智能体之间通信是少还是多、是平级还是分层</p></li></ol><p>其中通信水平可以用 <code>[23]</code> 给出的【通信机制 &#x3D; 通信范式（通信协议）+ 通信结构 + 通信内容】进一步刻画：</p><ul><li><p><code>[27]</code> 提出通信范式的四维框架，并重点区分了两类系统：</p><ul><li>blackboard（黑板系统）：所有 agent 共享一块”黑板”，把消息写上去、其他人自己来读，类似共享消息池；</li><li>message-based（消息系统）：agent 之间直接发消息，点对点传；</li></ul></li><li><p>通信结构分为四种类型：去中心化、集中式、分层、嵌套。</p></li></ul><h3 id="MAS-profile"><a href="#MAS-profile" class="headerlink" title="MAS profile"></a>MAS profile</h3><h4 id="上下文生成方法：“先有任务，再定制画像”"><a href="#上下文生成方法：“先有任务，再定制画像”" class="headerlink" title="上下文生成方法：“先有任务，再定制画像”"></a>上下文生成方法：“先有任务，再定制画像”</h4><p>根据特定上下文或用户的具体要求，agent 配置文件可能包含不同类型和内容的信息，可以据此生成智能体画像。这种上下文化生成方法会基于复杂任务的环境，灵活决定智能体档案的类型和内容，确保与任务需求对齐。但它是”一次性”的，而且劳动密集：每个新场景都要重新生成一遍智能体档案。</p><p>这种做法的成本高，但与任务的契合程度也高。</p><h4 id="预定义方法：-“先造好人才池，任务来了再挑人”"><a href="#预定义方法：-“先造好人才池，任务来了再挑人”" class="headerlink" title="预定义方法： “先造好人才池，任务来了再挑人”"></a>预定义方法： “先造好人才池，任务来了再挑人”</h4><p>这种方法先让 LLM 定义多个 agent，共同构成智能体池。面对特定场景时，从池中挑选合适的 agent 执行相关子任务。通常 LLM 会在提示中写明 agent 配置文件的组成和属性，据此生成具有不同特征的 agent；随后由人工或 LLM 挑选合适的 agent；最后 LLM 负责更新智能体的状态信息，方便它们恢复或继续之后的操作。</p><p>这种做法的成本低，但与任务的契合程度也低。</p><h4 id="基于学习的方法"><a href="#基于学习的方法" class="headerlink" title="基于学习的方法"></a>基于学习的方法</h4><p>介于前两种方法之间：在为特定场景定义 agent 配置文件的同时，也能省下大量时间。不过生成新智能体时存在潜在问题，比如大模型幻觉、生成的配置文件与相应任务不匹配。</p><h3 id="MAS-Mutual-interaction"><a href="#MAS-Mutual-interaction" class="headerlink" title="MAS Mutual interaction"></a>MAS Mutual interaction</h3><p>MAS 的相互交互可以分为三个基本组成部分：</p><ul><li>Message Delivery（消息传递）</li><li>Interaction Structure（交互结构）</li><li>Interaction Scene（交互场景）</li></ul><h4 id="Message-Delivery"><a href="#Message-Delivery" class="headerlink" title="Message Delivery"></a>Message Delivery</h4><p>消息通常以文本形式记录和传输，也有一些工作整合了多模态信息，比如视觉和音频数据。消息的内容会随任务分配和交互场景动态变化，通常包含历史和当前状态信息，以及其他智能体的通信消息。</p><p>消息传递通常由任务分配、与其他智能体的交互或外部控制信号触发；智能体也可以先把消息存进共享内存池，让其他智能体从中检索。</p><h4 id="Interaction-Structure"><a href="#Interaction-Structure" class="headerlink" title="Interaction Structure"></a>Interaction Structure</h4><p>交互结构定义了多智能体系统内的通信框架，通常基于消息内容进行组织和安排，给智能体分配不同的角色与责任。交互结构可分为四种类型：</p><ul><li><p>分层式（Hierarchy）：不同级别的智能体扮演不同角色，高级和低级之间有明确区分。高级智能体通常做监督，负责关键决策，向下级智能体发布指令。这种模式模仿传统组织结构，通过明确划分权力和责任边界来提高效率。</p></li><li><p>去中心化（Decentralized）：智能体在不需要中央权威的对等网络中直接相互通信。这种结构促进智能体之间的平等，交互更灵活、更动态，还能减轻单个大语言模型的计算负担、增强系统鲁棒性；不过在大规模系统中，协调和通信开销会变得明显，可能影响整体性能。</p></li><li><p>集中式（Centralized）：由一个或一组中心智能体协调整个系统，管理和编排所有智能体之间的交互。控制权集中简化了决策过程、避免潜在冲突、提高整体效率；但系统依赖中心智能体，容易单点故障、受通信延迟影响，难以快速响应环境变化。</p></li><li><p>共享消息池（Shared Message Pool）：智能体通过共享消息池发布和订阅信息，按需获取相关信息，不需要点对点直接通信。好处是通信过程简化、信息传递的复杂性降低、消息管理统一；但多个智能体同时访问共享消息池，可能带来争用和同步问题。</p></li></ul><h4 id="Interaction-Scene"><a href="#Interaction-Scene" class="headerlink" title="Interaction Scene"></a>Interaction Scene</h4><p>按场景内容，MAS 中的交互可分为三类：</p><ul><li><p>通信场景（communication）：智能体通过交换信息进行协调和决策。信息交换可以是直接的，比如通过特定通信渠道传输每个智能体的状态、计划和建议；也可以是间接的，比如共享关于环境、任务或其他智能体的知识。</p></li><li><p>任务执行（task execution）：关注智能体如何按照预定义的任务分配执行特定行动，比如角色扮演游戏、分布式任务分配等。</p></li><li><p>环境探索（environment exploration）：要求智能体利用感知和学习机制，在未知环境中不断适应和优化自己的行为，既包括模拟环境，也包括真实物理环境。</p></li></ul><p>按场景中智能体之间的关系，又可分为三类：</p><ul><li><p>协作式（Cooperative.）：智能体共同工作以实现共同目标。现有的多智能体协作模型主要分为：</p><ul><li>无序协作：搭一个允许多个 ChatGPT 实例通信、提供反馈、集体思考的网络，让智能体自然协作，不设固定角色分工。</li><li>有序协作：把标准操作程序（SOPs）编码成提示序列，让智能体按分配的角色和专业知识执行特定任务。</li></ul></li><li><p>对抗型（Adversarial.）：智能体之间是竞争关系，各自追求自身利益最大化。基本流程包括目标设定、策略制定、交互游戏和结果评估：先设定目标最大化自身利益，再根据对手的行为基准制定竞争策略；交互游戏阶段通过交互实施策略，争取最大利益；最后评估结果、调整策略应对后续竞争。</p></li><li><p>混合型（Mixed.）：结合协作与对抗的特点，要求智能体在合作与竞争之间找平衡，可再细分为并行和层次化两种：</p><ul><li>并行（Parallel）：多个智能体在不同任务上独立协作，共享一部分信息但互不干扰。每个智能体负责生成答案的独立部分，最后汇总成完整响应，响应生成快、效率高。</li><li>层次化（Hierarchical）：智能体之间呈树状结构。父节点设定全局目标、分解任务并分配给子节点；子节点执行具体任务并提供反馈；父节点根据反馈调整全局策略，优化整体任务执行。</li></ul></li></ul><h3 id="MAS-Evolution"><a href="#MAS-Evolution" class="headerlink" title="MAS Evolution"></a>MAS Evolution</h3><h4 id="Evolution-source"><a href="#Evolution-source" class="headerlink" title="Evolution source"></a>Evolution source</h4><h5 id="Environment-Feedback-（环境反馈）"><a href="#Environment-Feedback-（环境反馈）" class="headerlink" title="Environment Feedback.（环境反馈）"></a>Environment Feedback.（环境反馈）</h5><p>环境反馈指智能体在现实世界或虚拟环境中感知到的信息，通常是智能体的决策和行动改变了环境之后产生的变化信息。这类反馈充当奖励信号，告诉智能体行动的后果。</p><h5 id="Agents-Interaction-（智能体交互）"><a href="#Agents-Interaction-（智能体交互）" class="headerlink" title="Agents Interaction.（智能体交互）"></a>Agents Interaction.（智能体交互）</h5><p>在多智能体系统中，交互信息指智能体之间协作信息的交换，包括其他智能体对某个智能体决策或行动的评估、状态更新，以及智能体之间的上下文通信。</p><h5 id="Human-Feedback-（人类反馈）"><a href="#Human-Feedback-（人类反馈）" class="headerlink" title="Human Feedback.（人类反馈）"></a>Human Feedback.（人类反馈）</h5><p>人类反馈是由人提供的指导性信号，用来引导智能体做出更好的决策和行动，从而提升其认知能力。</p><h4 id="Evolution-methods"><a href="#Evolution-methods" class="headerlink" title="Evolution methods"></a>Evolution methods</h4><h5 id="Fine-tuning（微调）"><a href="#Fine-tuning（微调）" class="headerlink" title="Fine-tuning（微调）"></a>Fine-tuning（微调）</h5><ul><li>Full Fine-tuning（全模型微调）：更新预训练模型的所有参数，让它适应特定的新任务。计算上昂贵、耗时，新任务数据有限时还有过拟合的风险。</li><li>Repurposing（重新使用）：通常只对预训练模型的特定层（一般是高层）做微调，低层保持不变。</li><li>Additional Parameter Fine-tuning（额外参数微调）：给原始模型加一组额外参数（Adapter、LowRank Adaptation（LoRA）、Prefix Tuning），不改预训练参数也能高效微调。</li></ul><h5 id="Feedback-Learning（反馈学习）"><a href="#Feedback-Learning（反馈学习）" class="headerlink" title="Feedback Learning（反馈学习）"></a>Feedback Learning（反馈学习）</h5><p>反馈学习把反馈信息当作上下文，让智能体无需更新权重即可迭代”强化”策略生成。</p><h5 id="Prompt-Engineering-提示词工程"><a href="#Prompt-Engineering-提示词工程" class="headerlink" title="Prompt Engineering.(提示词工程)"></a>Prompt Engineering.(提示词工程)</h5><p>用精心设计的提示和反馈作为上下文线索。只优化提示、不改模型权重，就能显著提高模型性能。做法是给输入提示添加特定前缀，让模型生成时参考更多上下文信息，输出更相关、更准确。</p><h5 id="Reinforcement-Learning-（强化学习）"><a href="#Reinforcement-Learning-（强化学习）" class="headerlink" title="Reinforcement Learning.（强化学习）"></a>Reinforcement Learning.（强化学习）</h5><p>强化学习里，智能体通过与环境的交互学习最优策略。每个行动都会产生相应的反馈（奖励或惩罚），智能体据此不断调整策略，最大化累积奖励。核心是试错和优化：通过多次试错，逐渐学会在不同情境下做出最优决策。</p><h4 id="Agents-adjustment"><a href="#Agents-adjustment" class="headerlink" title="Agents adjustment"></a>Agents adjustment</h4><p>进化机制的一个关键方面，是持续更新智能体现有的知识和经验，或在执行前优化当前的决策和行为。目的是加深智能体的认知能力，增强它对复杂、动态环境的响应能力；通过迭代学习和适应，智能体能在不断变化的情境中保持性能。</p><h5 id="Memory-Update-（记忆更新）"><a href="#Memory-Update-（记忆更新）" class="headerlink" title="Memory Update.（记忆更新）"></a>Memory Update.（记忆更新）</h5><p>一种重要做法是扩展、加深智能体的自我意识和学习经验：让智能体利用<u>记忆机制，</u>基于收集到的反馈进行自我反思，经过抽象、总结和综合，把新获得的知识和经验存进记忆或外部数据库。</p><h5 id="Self-Reflection-（自我反思）"><a href="#Self-Reflection-（自我反思）" class="headerlink" title="Self-Reflection.（自我反思）"></a>Self-Reflection.（自我反思）</h5><p>以往的研究大多在加强智能体零样本任务决策和高效执行的能力；一种更通用的做法是，让智能体根据反馈和通信记录调整自己的初始目标和规划策略，实现动态演进。</p><h5 id="Dynamic-Generation-（动态生成）"><a href="#Dynamic-Generation-（动态生成）" class="headerlink" title="Dynamic Generation.（动态生成）"></a>Dynamic Generation.（动态生成）</h5><p>有些情况下，重点是让多智能体系统自主维护、持续运行。考虑到环境的复杂性，系统可以动态生成或移除执行特定任务的智能体，调整系统规模。</p><h2 id="②LLM-based-multi-agent-systems-for-clinical-workflows-a-survey-of-AI-hospitals"><a href="#②LLM-based-multi-agent-systems-for-clinical-workflows-a-survey-of-AI-hospitals" class="headerlink" title="②LLM-based multi-agent systems for clinical workflows: a survey of AI hospitals"></a>②LLM-based multi-agent systems for clinical workflows: a survey of AI hospitals</h2><h3 id="论文框架-1"><a href="#论文框架-1" class="headerlink" title="论文框架"></a>论文框架</h3><p>论文提出了人工智能医院（AI hospital）的概念：</p><p>人工智能医院指工作流程级的多智能体临床模拟或部署，具有明确的角色、跨交接的共享状态、基于证据的工具、安全门和纵向跟踪。这是”像医院一样运转”的最低条件。一个系统可以只做<u>会诊、分诊、出院、医学教育或心理健康随访</u>，但只有当它的行动被组织为”跨角色、跨阶段、有持久上下文、有明确问责、有可审计日志”的流程时，才算进入 AI hospital 的范围。</p><table><thead><tr><th>步骤</th><th>干什么</th></tr></thead><tbody><tr><td>Triage（分诊）</td><td>判断紧急程度，收集第一份结构化信号，例如急危重症等级、红旗警示、初步证据链接</td></tr><tr><td>Consult（会诊）</td><td>更新初步诊断，把证据链接到建议的行动，并明确还需要澄清什么</td></tr><tr><td>Discharge（出院）</td><td>把当前方案转化成患者指导、随访计划和升级标准</td></tr></tbody></table><p><u>不同于医疗保健聊天机器人，这里的重点是明确的状态和切换、操作感知评估，以及作为分阶段协议而不是松散声明的部署准备情况。</u></p><p>普通的医疗保健机器人</p><ul><li>关注”模型能不能答对问题”；</li><li>每个回答、每轮对话基本独立，答完就算完；</li><li>评测以最终答案的准确率、F1、人工评分为主；</li><li>说”可以部署”往往只靠一个 benchmark 分数，算是一个”松散声明”（loose claim）。</li></ul><p>AI hospital</p><ul><li>病例不是”问一句答一句”，而是有持久状态：分诊产生急危重等级，会诊更新初步诊断并附上证据，出院把方案转成随访计划；</li><li>不只看最终诊断准不准，还看过程与运营指标：交接完整性、证据覆盖率、升级是否及时、该阻止而没阻止、延迟、人工介入次数、日志能否回放；</li><li>论文不承认”benchmark 高 &#x3D; 能部署”，而是给出 IRL1–IRL6 的分级协议：先在模拟环境（IRL1–2），再到真实数据影子回放、人机共决试点（IRL3–4），最后才限范围上线、多中心铺开（IRL5–6）；每一级晋升都必须提供指定证据，比如回放证据链、升级召回率、零 PHI 泄露、漂移监控等，达不到就卡在那一级。</li></ul><h3 id="系统设计规范"><a href="#系统设计规范" class="headerlink" title="系统设计规范"></a>系统设计规范</h3><h4 id="角色和交接"><a href="#角色和交接" class="headerlink" title="角色和交接"></a>角色和交接</h4><p>第一个设计决策是：工作流程是否真正需要多个角色。单个代理可能足以完成狭窄的、低风险的步骤，再加上强有力的人工审查。当案例跨越护理阶段、专业或批准边界时，多代理结构就有用了：所有权会变化，下一个角色必须继承明确的状态，而不是去猜。</p><ol><li>面向患者的角色：决定哪些信息进入工作流程。价值不只是多几个专业人员，而是能明确责任归属、把专业领域的预设前提摆到明面上，并在工作流程继续推进之前化解分歧。</li><li>规划和编排角色：把案例分解为多个步骤，确定还缺哪些信息，并对案例进行接待、分类、咨询或后续处理。当系统必须协调多个本地决策时，比如分诊输出决定咨询代理下一步问什么、或哪个服务接收患者，这些角色非常有用。</li><li>评判、批评和记录角色：当工作流程需要明确的协调、指南检查或可审计的摘要，而不是一轮自由形式的讨论时，法官、评论家、决策和记录角色就有用了。实践中，多智能体开销主要在这些责任函数可测量时才合理，而不只是当模型能生成更多推理分支时。</li></ol><p>⭐ 在这一步我们要有一个大概的设计，即这个病例应该有几个agent负责？</p><h4 id="记忆、证据和工具"><a href="#记忆、证据和工具" class="headerlink" title="记忆、证据和工具"></a>记忆、证据和工具</h4><p>第二项设计考量是，确定角色交接完成后，下一岗位需要获取哪些信息。完成分诊之后，接手的咨询处理人员不应该再去揣测病情危急程度信号、现存问题、已开具的检查项目，以及当前诊疗方案背后的依据。下面的设计思想让实例可以恢复、证据可以归属：</p><ol><li>长期记忆和证据来源（Long-term memory and evidence sources.）：设计问题不只是”知识存在哪里”，还有如何恢复每个支持项、给它们做版本控制、并把它们和后续操作联系起来。</li><li>工作记忆和切换恢复（Working memory and handoff recovery.）：工作记忆携带跨角色的活动案例状态。实际中就是摘要、中间决策、证据 ID、悬而未决的问题和升级标记，让新代理可以恢复工作流程，而无需从头重建。</li><li>执行和验证工具（Execution and verification tools.）：它们把”计划该不该通过”变成可以在流程里执行的检查，并且能记录”过了没有、依据是什么、是谁执行、用的哪个版本的指南”，相当于多智能体系统里的”安检门”。<ul><li>临床决策树、计算器：对分诊、剂量、禁忌证做显式的指南检查，比如”这个剂量是否超指南上限”；</li><li>虚拟 EHR 工具：在受控环境里模拟读写电子病历，暴露证据来源和阶段性失败；</li><li>LLM-as-KB 式工具：用 LLM 当知识库做灵活综合，但一旦进入工作流，必须带显式溯源（provenance）。</li></ul></li><li>多模式和研究工具（Multimodal and research tools.）：它们不是”提高一点准确率的插件”，而是把证据和行动变成可审计的工作流对象——每次工具调用都要留下日志、来源、版本，以后能回放、能追责。<ul><li>多模态工具：把影像、病理切片、传感器等非文本证据和后续推理绑定，确保诊断结论确实锚定在”系统看到了什么”上，比如影像报告必须有 image-to-report 链接、图片 ID、预处理版本；</li><li>研究工具：执行代码、结构化分析、研究自动化，比如跑数据分析脚本、做统计计算，主要用于科研工作流，强调过程可复现。</li></ul></li></ol><p>⭐    在这一步我们应该把agent的权威性树立起来</p><p>证据访问工具负责”找到依据”；</p><p>执行&#x2F;验证工具负责”这一步能不能过、能不能执行”；（不是泛泛的”能不能执行医学决策”，而是”这步决策能不能通过显式规则检查并留下执行痕迹”）</p><p>多模态工具负责”图片&#x2F;传感器证据没有脱离决策链”；（不是”判断决策是否在医学范畴”，而是”判断决策是否锚定在真实观察到的证据上”）</p><p>研究工具负责”科研动作可复现”。</p><h4 id="推理、控制和升级"><a href="#推理、控制和升级" class="headerlink" title="推理、控制和升级"></a>推理、控制和升级</h4><p>第三个设计决策是控制。重点不在于推理看起来有多复杂，而在于指导行动的政策是什么。在类似医院的工作流程中，系统必须在继续执行、要求缺失证据、放弃、升级之间做决定。因此，有用的可观察结果是遗漏、分歧、弃权、证据覆盖、延迟和回滚行为。</p><ol><li>直接推理（Direct reasoning.）：任务明确、指导面稳定时，单路径推理效果最好。</li><li>多路径推理（Multi-path reasoning.）：工作流程确实存在多方专业视角差异，或还有悬而未决的不确定性时，可以用并行分支、充分研讨或投票机制处理。</li><li>反馈来源（Feedback sources.）：反馈来自临床医生、工具、知识库，或交互中的后续回合。外部反馈通过新证据或专家修正更新计划。</li><li>控制策略与关卡（Control policies and gates.）：一套实用的系统不是一味增强推理，而是提供一个自主权限调节旋钮，界定工作流何时继续执行、何时请求补充缺失依据、何时选择不做判断、何时向上升级处置。</li></ol><h3 id="临床直接工作流（工作流的设计）"><a href="#临床直接工作流（工作流的设计）" class="headerlink" title="临床直接工作流（工作流的设计）"></a>临床直接工作流（工作流的设计）</h3><p>主要临床工作流类别，差异在于系统<u>处于诊疗路径的哪个环节，以及哪一类故障风险占主导地位</u>。同一架构在某一类工作流下可能表现尚可，换到另一类就会显得脆弱，因为工作流不同，对交接质量、证据关联和升级处置策略的要求也不同。</p><ol><li><p>端到端临床工作流仿真与虚拟病房：这类场景和分诊、会诊、出院这套实际运行案例最贴近。系统必须补全缺失的临床证据，在多轮交互里更新诊断假设，并跨多个角色、多个诊疗阶段保存业务状态。这类方案的核心价值在于<u>阶段级可观测性</u>：不只是对最终输出打分，还能定位证据缺失的位置、交接失效的环节，以及本应触发升级处置的节点。</p></li><li><p>会诊、多学科协作与复杂决策：当专科特有约束或持续存在的临床不确定性，让单一推理路径容易失效时，这类工作流就显得重要。代表性系统会主动追问补充信息、动态更新鉴别诊断、整合结构化临床证据，或针对罕见复杂病例召集多学科团队会诊。</p></li><li><p>分诊、患者分流、诊疗交接与出院沟通：这类工作流受业务运行约束影响最大。输入信息噪声多，审批权责边界频繁出现；评判质量的标准是交接信息是否完整、下游环节是否可用，而不是单一诊断结果。面向患者的交接任务（出院告知与随访准备）把这一点体现得最明显：系统必须留存已确定的诊疗结论、已向患者告知的内容，以及仍需升级处置的事项。这类场景里，工作流日志是任务定义的固有组成部分，不是事后附加的产物。</p></li></ol><h3 id="人工智能模型的评估和部署的准备"><a href="#人工智能模型的评估和部署的准备" class="headerlink" title="人工智能模型的评估和部署的准备"></a>人工智能模型的评估和部署的准备</h3><p>AI 医院场景下的模型评估，正从孤立的考试式测评，转向交互式患者任务、覆盖多类临床任务的基准套件、虚拟电子病历（virtual-EHR）环境，以及前瞻性预实验研究。针对工作流级系统，评估对象不只是最终输出，还包括各执行步骤与交接环节的行为表现。</p><p>我们把上述评估信号整理成四层评估体系：安全层、流程层、结果层、运维层。以「分诊→会诊→出院」这条业务流程举例：</p><ul><li>安全层：判断危险诊疗建议是否被拦截；</li><li>流程层：核查每一步是否携带完整业务状态与证据依据；</li><li>结果层：判断最终处置方案或健康宣教内容是否准确、具备实用价值；</li><li>运维层：统计该工作流产生的时延、Token 开销以及人力成本。</li></ul><p>所以同一次模型运行记录要支持复现回放、审计核查与运行分析，而不是只输出一个最终分数。</p><h4 id="从模型能力到工作流可观测指标"><a href="#从模型能力到工作流可观测指标" class="headerlink" title="从模型能力到工作流可观测指标"></a>从模型能力到工作流可观测指标</h4><p>在某个场景里，一项模型能力是否有价值，取决于它能不能改变<u>工作流可观测指标</u>、日志采集要求，或可被合理赋予的自主权限等级。只说”推理更好、检索更多、工具用得更勤”不够。有用的声明是：系统现在能<u>安全地做什么、必须记录哪些额外证据，以及哪种更强的自主声明变得合理</u>。</p><ol><li>改变工作流可观测指标（workflow observable）：某个能力让系统在流程里的可测量行为变好了，例如高危步骤不再默默确诊而是正确推迟&#x2F;升级、会诊输出开始带病历链接的证据、下一个角色拿到的交接更干净、医嘱能带溯源执行。</li><li>改变日志采集要求（logging obligation）：因为这项能力，出现了”必须新增记录什么”的义务，例如要记录理由编码的弃权（reason-coded abstention）、升级精确率&#x2F;召回率、工具成功&#x2F;失败、跨模态一致性、工具&#x2F;指南版本。</li><li>改变可被合理赋予的自主权限等级（level of autonomy that can be justified）：这项能力让系统”有资格”往上走一级自主权限，例如从”人说了算”到”自动建议但高危步骤必须人工批准”，再到”有监督的自主执行”。</li></ol><p>论文给的具体例子（Table 2）：</p><table><thead><tr><th>能力</th><th>应出现的可观测工作流变化</th><th>要记录的日志&#x2F;指标</th><th>支撑的更强自主声明</th></tr></thead><tbody><tr><td>更好的校准&#x2F;弃权</td><td>高危步骤推迟或升级，而不是默默确诊</td><td>理由编码弃权、升级精确率&#x2F;召回率、override 结果</td><td>需要批准的试点&#x2F;受监控的高危门控</td></tr><tr><td>证据锚定检索</td><td>会诊&#x2F;出院输出带病历链接证据而非无引用断言</td><td>引用覆盖率、证据门通过率、引用与记录一致性</td><td>可回放证据链的影子评估</td></tr><tr><td>长上下文&#x2F;纵向状态</td><td>后续角色拿到更干净的交接、跨就诊可回放</td><td>交接完整性、回放成功率、跨就诊一致性</td><td>纵向影子回放、多就诊评估</td></tr><tr><td>可靠的工具&#x2F;计算器</td><td>受管制的检查和行动带溯源执行</td><td>工具成功&#x2F;失败、指南依从率@步骤、回滚率</td><td>分诊&#x2F;医嘱&#x2F;出院检查的受控使用</td></tr><tr><td>多模态锚定</td><td>影像类判断链接到真实观察到的证据</td><td>跨模态一致性、影像到报告链接</td><td>影像&#x2F;监控工作流的可审计提交</td></tr></tbody></table><p>所以这句话可以简单理解成：<u>“模型更厉害”不是结论，只有当它变成”流程里能看见、能记录、能支撑更高自主级别”的变化时，才算有价值。</u></p><h4 id="基准（benchmark）分数高-≠-可以部署"><a href="#基准（benchmark）分数高-≠-可以部署" class="headerlink" title="基准（benchmark）分数高 ≠ 可以部署"></a>基准（benchmark）分数高 ≠ 可以部署</h4><p>基准问的是”在一个设计好的任务里，它能不能表现好”；部署就绪问的是”把回放、升级、运营一起检查之后，它声称的那级自主权还站得住吗”。放在 MDT 里：某 MDT 系统在诊断准确率基准上拿了高分，不等于它能在会诊里安全运行——你还要看它跨专科交接是否完整、遇到分歧有没有正确升级、有没有能回放的证据链和过程&#x2F;运营日志。</p><h4 id="基于IRL的从沙盒环境到正式部署"><a href="#基于IRL的从沙盒环境到正式部署" class="headerlink" title="基于IRL的从沙盒环境到正式部署"></a>基于IRL的从沙盒环境到正式部署</h4><p>把部署拆成三个阶段、六个等级（IRL1–IRL6）。IRL 阈值是”协议默认值”，不是普适常量，必须按任务风险、站点政策、基线对照、可接受失败预算来校准；所以它更像”治理模板”，而不是一劳永逸的数字。每个等级规定两件事：允许的最高自主权是什么，以及要晋升到下一级必须先拿出什么证据。</p><p>三个阶段：</p><ol><li>Simulation（模拟）：IRL1 静态&#x2F;脚本化沙盒、IRL2 加噪声&#x2F;缺信息&#x2F;对抗性模拟。系统只能在沙盒里跑，重点看”不安全输出率、越狱抵抗、引用覆盖率”。</li><li>Replay &#x2F; Pilot（回放 &#x2F; 试点）：IRL3 在真实数据上影子回放（模型提出、人决定，无实时影响）、IRL4 有限的人机共决试点（低风险步骤可自动建议、高风险步骤必须人工批准）。证据开始要求”可回放证据链、交接完整性、升级召回率、零 PHI 泄露”。</li><li>Rollout（铺开）：IRL5 限范围上线、带端到端监控（自动默认 + 例外人工复核）、IRL6 跨站点&#x2F;多语言规模化（有监督自主 + 定期审计）。要求漂移仪表盘、事件响应、跨站点一致性、ROI。</li></ol><h4 id="合成数据用于生成-压力测试用的证据不是部署用的证据"><a href="#合成数据用于生成-压力测试用的证据不是部署用的证据" class="headerlink" title="合成数据用于生成&#x2F;压力测试用的证据不是部署用的证据"></a>合成数据用于生成&#x2F;压力测试用的证据不是部署用的证据</h4><p>合成数据用于训练和压力测试：生成对话、工作流状态转换、缺信息病例、交互模式——这些在真实数据里往往很难大规模采集。在医疗里能扩大覆盖范围、减少直接隐私暴露。但合成数据有明确局限：合成工作流会扭曲真实分布，prevalence（疾病比例）、coordination patterns（协作模式）、error surfaces（错误面）都可能和现实不一样。所以在沙盒生成的”看似成功”的表现，不能直接外推到真实环境。</p><p>“用合成的假病历跑通了一次会诊”根本不等于”这系统能在真实病房上线”；合成数据只是训练和压测的好工具，不能拿来证明部署就绪。</p><h4 id="失败的五种模式和路线图"><a href="#失败的五种模式和路线图" class="headerlink" title="失败的五种模式和路线图"></a>失败的五种模式和路线图</h4><p>AI hospital 的失败很少只出在单个模块里，而是表现为跨角色、记忆、工具、控制的”工作流级崩溃”。</p><p>五种失败模式（Table 5）</p><table><thead><tr><th>失败模式</th><th>是什么</th><th>最先出现在哪</th><th>设计应对</th></tr></thead><tbody><tr><td>Longitudinal drift（纵向漂移）</td><td>把历史状态和当前状态混在一起、跨次就诊不一致、无法重建”后来的动作为什么由之前的动作推出”</td><td>随访、慢病、心理健康交互</td><td>workflow-aware 记忆 + 可回放的纵向痕迹</td></tr><tr><td>Capacity-blind planning（无视容量的规划）</td><td>方案在临床上说得通，却忽略床位、人力、转运延迟、队列负载</td><td>床位管理、路由、转病房</td><td>压力测试影子回放、队列感知模拟、TTD&#x2F;吞吐量&#x2F;延迟尾部不回归检查</td></tr><tr><td>Ungated deviation &#x2F; weak escalation（无门控越轨、弱升级）</td><td>偏离指南却不说明理由，或高危病例该弃权&#x2F;升级却没做</td><td>分诊、出院、预授权、剂量</td><td>指南版本化、理由编码的越轨日志、引用覆盖率、升级精确率&#x2F;召回率</td></tr><tr><td>Untraceable action chains（不可追踪动作链）</td><td>交接、医嘱、EHR 调用失去溯源，事后无法重建”谁在什么证据、什么版本&#x2F;权限下操作的”</td><td>EHR 联动动作、医嘱、交接</td><td>provenance-first 连接器、签名交接、回滚状态</td></tr><tr><td>Drift, jailbreak, cost shock（漂移、越狱、成本冲击）</td><td>部署后护栏行为漂移、提示被越狱、token&#x2F;延迟成本失控导致不安全或不可用</td><td>任何有外部用户&#x2F;工具的已部署工作流</td><td>定期红队测试、越狱通过率、回滚手册、成本护栏、canary 发布</td></tr></tbody></table><p>系统通向可审计、可负责任部署的路线图</p><p>短期进步不靠”多加讨论轮次”，而靠 workflow-aware 记忆、容量耦合的规划、校准好的升级策略、可审计溯源、带明确晋升门的部署手册；也就是”把状态、证据和运营控制得更紧”，而不是单纯”生成更强”。</p><p>⭐生成更强并不天然包含控制更紧。 一个模型即使生成能力很强，也可能：</p><ul><li>状态交接丢字段（生成的摘要再流畅，也可能漏掉关键信息）；</li><li>证据没有溯源（说得头头是道，却查不到依据）；</li><li>该升级不升级（高危病例也硬着头皮下结论）；</li><li>越轨不记录（偏离指南却不留理由）；</li><li>运营上失败（无视床位、延迟、成本）。</li></ul><p>建立共享报告协议（shared reporting protocol）非常有用——把工作流可观测指标、最小日志、升级覆盖率、回放证据、运营成本放在一起报告，这样系统才能放在”部署声明真正成立”的层面上被比较。</p><p>从长远来看，AI hospitals 可以看作”医疗世界模型的工作流级近似”——它维护状态、通过工具和临床接口行动、观察下游后果、在部分可观测性下重新规划。但这个视角只有在”部署证据按分阶段协议来”时才可信。</p><h3 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h3><p>人工智能医院应当被理解为工作流层面基于大语言模型的多智能体临床系统，而不是一个个独立的问答智能体。核心设计问题包括：每个业务步骤由谁负责执行；每次信息交接会保留哪些状态与证据；以及采用何种控制策略来管理流程继续执行、放弃决策与升级人工处置。</p><p>基于这一视角，评估工作应当聚焦安全、流程、结果、运维四大维度下的工作流可观测指标；系统部署则需要配套完备埋点、可直接审计的日志，以及分阶段的真实世界（IRL）准入闸门。因此，这份综述最具备复用价值的成果，不只是一套系统分类体系，更是一套面向部分可观测条件下、有状态、证据驱动、工具介导的临床工作流的结果报告与上线管控框架。</p><h2 id="③Not-just-one-agent-LLM-based-multi-agent-systems-for-medicine-from-answer-generation-to-accountable-workflow-orchestration"><a href="#③Not-just-one-agent-LLM-based-multi-agent-systems-for-medicine-from-answer-generation-to-accountable-workflow-orchestration" class="headerlink" title="③Not just one agent: LLM-based multi-agent systems for medicine from answer generation to accountable workflow orchestration"></a>③Not just one agent: LLM-based multi-agent systems for medicine from answer generation to accountable workflow orchestration</h2><h3 id="摘要"><a href="#摘要" class="headerlink" title="摘要"></a>摘要</h3><p>医学 MAS 不应作为更大的 LLM 工作流来评估，而应作为临床协调基础设施，在人工与智能体团队之间重新分配证据、责任和风险。</p><p>论文提出的 MDT 风格 MAS 运行流程：</p><p><img src="/2026/08/16/%E6%96%87%E7%AB%A0%E9%AA%A8%E6%9E%B6%EF%BC%8812%E7%AF%87%EF%BC%89/Xiong2026_Figure2_MDT-style_multi-agent.png" alt="Xiong2026_Figure2_MDT-style_multi-agent"></p><h3 id="评估系统和临床验证标准"><a href="#评估系统和临床验证标准" class="headerlink" title="评估系统和临床验证标准"></a>评估系统和临床验证标准</h3><h4 id="基本框架"><a href="#基本框架" class="headerlink" title="基本框架"></a>基本框架</h4><p><img src="/2026/08/16/%E6%96%87%E7%AB%A0%E9%AA%A8%E6%9E%B6%EF%BC%8812%E7%AF%87%EF%BC%89/Xiong2026_Figure5_evaluation_framework.png" alt="Xiong2026_Figure5_evaluation_framework"></p><p>左侧总结了结果级、过程级和部署级的评估维度；右侧重点介绍了比较性和高级验证方法，以及鲁棒性、效率和代表性基准数据集和任务。</p><h4 id="评估指标"><a href="#评估指标" class="headerlink" title="评估指标"></a>评估指标</h4><ol><li>结局层：对医学 MAS 的评估首先要保留基本结果级指标，如诊断准确率、召回率、F1 分数、top-k 命中率、治疗建议一致性以及指南一致性。这些指标能说明系统结论是否具有临床可接受性，但解释不了这些结论是如何形成的。</li><li>过程层：对 MAS 来说，更关键的问题是协作过程本身是否可靠，包括任务路由是否恰当、智能体之间的信息交接是否完整、外部工具使用是否正确、证据来源是否清晰，以及在多轮协作后结论是否缺乏正当理由地漂移。</li><li>部署层：从”跑分好看”到”能不能进真实医院”，即临床可执行性。看输出能否被真实临床执行：比如医嘱集不只是判对错，而是让医生按 accuracy &#x2F; usefulness &#x2F; feasibility &#x2F; impact 评分；以及多阶段工作流（分诊→检验→诊断→治疗）能否保持连续完整。</li></ol><h4 id="高级评估方法：时间回溯"><a href="#高级评估方法：时间回溯" class="headerlink" title="高级评估方法：时间回溯"></a>高级评估方法：时间回溯</h4><p>时间回测的关键思想并非回顾性重做案例，而是把 MAS 放在案例结束前的某个历史时间点，只允许它访问当时真正可获取的信息。这用来评估共享状态和中间证据是否足以支持早期决策。</p><p><u>关键临床信息往往并非一次性提供，而是通过患者智能体与系统智能体之间的交互逐步揭示。因此必须把询问过程纳入评估，避免对 MAS 能力过度乐观。</u>相关研究已开始使用对话轮次、诊断数量、交互时长和时间效率作为补充指标，把评估从静态终点分数推向过程级动态性能。<u>对于依赖纵向疾病轨迹和持续状态更新的系统，时间切片尤为必要，因为它能防止信息泄露把”回顾性正确性”伪装成”实时协作能力”。</u></p><h4 id="鲁棒性、运行效率"><a href="#鲁棒性、运行效率" class="headerlink" title="鲁棒性、运行效率"></a>鲁棒性、运行效率</h4><p>相比单个代理，医学多代理系统更容易出现链式脆弱性：一个错误的检索步骤、不恰当的路由决策或扭曲的中间摘要，可能会被继承、放大，并在下游节点固化为团队结论。因此，鲁棒性评估不应只关注端点错误率，还应该检查系统能否吸收错误、暴露冲突、追踪证据并回滚异常。</p><p>运营效率也应作为核心评估维度，因为 MAS 的部署价值取决于额外协作成本是否带来净收益。临床规模的工作量研究已经表明，准确率、延迟和 token 消耗必须一起报告；否则就不可能判断多智能体编排是否真正优于单智能体处理。</p><h4 id="当前医学-MAS-用到的评测数据集和基准"><a href="#当前医学-MAS-用到的评测数据集和基准" class="headerlink" title="当前医学 MAS 用到的评测数据集和基准"></a>当前医学 MAS 用到的评测数据集和基准</h4><p>当前对医学多智能体系统的评估主要围绕六类任务展开：</p><ol><li>动态问询 &#x2F; 渐进信息披露 → 测信息获取和交互组织能力 <code>[98]</code></li><li>住院路径 → 测多阶段角色转换下的稳定性 <code>[104]</code></li><li>纵向病程 → 测共享状态和早期预测能力 <code>[63]</code></li><li>安全评估框架 → 测不同拓扑下脆弱性和风险扩散 <code>[112]</code></li><li>成本敏感诊断 → 测运营成本与升级策略权衡 <code>[118]</code></li><li>多模态推理 → 测跨模态集成 <code>[115]</code></li></ol><p>Representative evaluation datasets and benchmarks for medical MAS（代表性数据集&#x2F;基准清单）（这些数据集在论文里的用途为”评测基准”）</p><table><thead><tr><th>数据集&#x2F;基准</th><th>数据来源与类型</th><th>主要任务场景</th><th>主要评估能力</th><th>常用指标</th><th>代表性文献</th></tr></thead><tbody><tr><td>JAMA Clinical Challenges（JAMA 临床挑战）</td><td>JAMA 临床挑战病例（从 1,519 例中筛出 815 例）</td><td>动态诊断与渐进式信息披露</td><td>问询组织、信息获取、动态诊断收敛</td><td>准确率、对话轮数</td><td>[98]</td></tr><tr><td>MIMIC 系列（MIMIC-III&#x2F;IV）</td><td>真实住院 EHR、ICU 数据和病程记录</td><td>住院路径、任务编排、实体抽取、因果分析、成本敏感诊断</td><td>工作流连续性、共享状态建模、运行效率</td><td>准确率、F1、AUC、token 使用量、延迟</td><td>[7, 87, 104, 118]</td></tr><tr><td>PDSQI-9 + MIMIC-III&#x2F;ProbSum</td><td>医学文档摘要与质量评分量表</td><td>医学文本生成质量的自动评审</td><td>自动评审与专家的一致性、评审结果可靠性</td><td>ICC、Krippendorff’s alpha、Gwet’s AC2</td><td>[117]</td></tr><tr><td>VHA 纵向临床笔记（CARE-AD）</td><td>美国退伍军人健康管理局（VHA）的长期病历与临床笔记</td><td>阿尔茨海默病早期预测</td><td>长期记忆、共享状态、时间切片预测</td><td>准确率、精确率、召回率、F1</td><td>[63]</td></tr><tr><td>VUMC 真实医嘱集</td><td>范德堡大学医学中心的真实医嘱集与知识库</td><td>医嘱集优化与临床可执行性评估</td><td>输出可执行性、人机一致性、专家筛选</td><td>专家评分、Cohen’s kappa</td><td>[47]</td></tr><tr><td>临床规模混合任务集</td><td>PubMed 文献、EHR 出院小结和剂量计算任务</td><td>检索、抽取、计算的混合负载</td><td>稳定性、可扩展性、运行效率</td><td>准确率、延迟、token 成本</td><td>[7]</td></tr></tbody></table><p>这些数据集把医学 MAS 评测从静态问答推向 process（过程）、time（时间&#x2F;时序）、deployment（部署）三个维度。但任务定义不一致、过程标注不足、报告标准分散。应该统一报告 outcomes、路由日志、工具调用、证据链、分歧状态、资源消耗。</p><p>⭐六类分类只是现状描述，作者的落点是”需要一个最小报告框架让六类评测能横向比较”。final score 无法反推内部发生了什么，而医学 MAS 的增量价值恰恰在内部：路由决策对不对、工具调用是否规范、证据链完不完整、分歧是怎么消解的、协作花了多少资源都是无法通过单一MAS输出的，所以作者给出了统一的基准性清单</p><h3 id="面临的挑战"><a href="#面临的挑战" class="headerlink" title="面临的挑战"></a>面临的挑战</h3><table><thead><tr><th>Xiong 2026 风险（具体机制&#x2F;数字）</th><th>草稿对应小节</th></tr></thead><tbody><tr><td>5.1.1 级联误差放大（下游把上游错误当前提，经改写&#x2F;总结&#x2F;裁决固化；无反驳&#x2F;纠正&#x2F;升级机制时多轮讨论会把错误变成集体共识）</td><td>3.6.1 虚假一致 + 3.6.2 上下文崩塌&#x2F;过度自信</td></tr><tr><td>5.1.2 共识偏见（集中裁决受模型家族偏置、多数意见或使用僵化的静态协作工作流可能会把表面一致当高质量共识）</td><td>3.6.1 虚假一致&#x2F;沉默同意</td></tr><tr><td>5.1.3 记忆污染（共享状态被错误中间判断污染、长期病程线索丢失）</td><td>3.6.2 上下文崩塌 + 3.6.3 隐私</td></tr><tr><td>5.2.1 隐私边界扩展（AgentLeak：MAS 总体隐私暴露约为单智能体的 1.6 倍；缓存&#x2F;复制&#x2F;复用）</td><td>3.6.3 安全与隐私</td></tr><tr><td>5.2.2 问责结构复杂化（单智能体系统中的错误通常可以相对容易地追溯到模型、训练数据或部署实体。在多智能体系统 (MAS)中,一旦规划、检索、推理、验证和执行被分配到不同的角色,责任链条就会变长。<u>为了解决这个问题,当前研究不再将责任仅仅视为事后归因, 而是试图将其嵌入系统设计中。</u>）</td><td>3.6.3 安全与隐私</td></tr><tr><td>5.2.3 偏见的链式放大（多智能体系统(MAS)并不比单一智能体更公平或更可靠。临床医生可能过度信任系统输出,未能及时识别错误、偏见或不完整证据。）</td><td>3.6.1 + 3.6.3</td></tr><tr><td>5.3 监管&#x2F;标准化缺失（无商业部署、无 FDA 批准&#x2F;CE 标志、无前瞻上市后性能；分阶段部署：静默 → 监督 → 有界试点 → 审计 → 撤回标准）</td><td>3.6.4 评测不足与报告 + 4.4 研究空白 + 4.2 成熟度</td></tr></tbody></table><h3 id="未来的方向（技术创新路径）"><a href="#未来的方向（技术创新路径）" class="headerlink" title="未来的方向（技术创新路径）"></a>未来的方向（技术创新路径）</h3><p>医学 MAS 的可靠推理既需要结构化知识约束，也需要可控的人机协作。知识图谱、循证关系（遵循证据做决策）和患者特定信息不应只是作为检索到的片段被被动输入，而应成为跨智能体共享的结构化支架，明确约束推理路径。<u>因此，未来的医学 MAS 更可能演化为受知识约束、由人与 AI 共同治理的临床系统（人机协作的价值在于把人类判断放在高风险节点，而不是事后复核输出），而不是完全自主的封闭智能体</u>集群。</p><h2 id="④MedAgents-large-language-models-as-collaborators-for-zero-shot-medical-reasoning"><a href="#④MedAgents-large-language-models-as-collaborators-for-zero-shot-medical-reasoning" class="headerlink" title="④MedAgents: large language models as collaborators for zero-shot medical reasoning"></a>④MedAgents: large language models as collaborators for zero-shot medical reasoning</h2><h3 id="MedAgents的五阶段流程图"><a href="#MedAgents的五阶段流程图" class="headerlink" title="MedAgents的五阶段流程图"></a>MedAgents的五阶段流程图</h3><p><img src="/2026/08/16/%E6%96%87%E7%AB%A0%E9%AA%A8%E6%9E%B6%EF%BC%8812%E7%AF%87%EF%BC%89/MedAgents_Figure1_%E7%BA%AF%E6%B5%81%E7%A8%8B%E5%9B%BE.png" alt="MedAgents_Figure1_纯流程图"></p><h3 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h3><p>⭐这个方法全程自动，从input到output全程不需要人</p><ul><li><code>q</code> &#x3D; 题目（question）</li><li><code>op</code> &#x3D; 一堆选项，<code>o1...ok</code> 就是第 1 到第 k 个选项</li><li><code>QD</code> &#x3D; 问域专家（question-domain experts），默认 5 个，专门分析题目属于什么专科&#96; </li><li><code>OD</code> &#x3D; 选项域专家（option-domain experts），默认 2 个，专门判断每个选项对不对</li><li><code>QA</code>&#x2F;<code>OA</code> &#x3D; 这两拨专家写出的分析</li><li><code>Repo</code> &#x3D; 汇总报告，<code>Repof</code> 是最终全员同意的报告</li><li><code>ans</code> &#x3D; 最终答案</li><li><code>r...</code>&#x2F;<code>prompt...</code> &#x3D; 角色描述和指示语，把它们当成“给 LLM 的工牌 + 任务单”就行</li></ul><h4 id="1-组建专家小组"><a href="#1-组建专家小组" class="headerlink" title="1. 组建专家小组"></a>1. 组建专家小组</h4><p>论文里的“不同专家”不是真医生、也不是独立模型，而是同一个大模型在每次调用时换一个系统角色描述和任务提示：一次让它自称心内科主任，另一次让它自称消化科主任，再让另一组扮演“专门挑选项毛病”的专家。区别全在 <code>prompt</code> 和角色设定上，参数都是公开的 GPT-3.5&#x2F;GPT-4，论文实验提到 <code>temperature=1.0</code>，所以同一角色反复调用时输出还带随机性。</p><p>QD &#x3D; LLM(q, rqd, prompt<del>qd</del>)：拿题目问模型“这题需要哪些专科”；</p><p>OD &#x3D; LLM(q, op, rod, prompt<del>od</del>)：再问模型“要判断这些选项，还需要哪些专科”。</p><h4 id="2-每个LLM独立写意见"><a href="#2-每个LLM独立写意见" class="headerlink" title="2. 每个LLM独立写意见"></a>2. 每个LLM独立写意见</h4><p>qa<del>i</del>（LLM）&#x3D; LLM(q, qd<del>i</del>, rqa, prompt<del>qa</del>)：让问域专家 qd<del>i</del> 只针对题目写分析。</p><p>oa<del>i</del> （LLM）&#x3D; LLM(q, op, od<del>i</del>, QA, roa, prompt<del>oa</del>)：让选项域专家 od<del>i</del> 拿着题目、所有选项，还附上问域专家的分析，逐个评估选项。</p><p>先让内科、外科这些“管题的人”各写一段病情分析；再把他们的分析交给“管选项的人”，让他们结合分析去判断每个选项为什么对、为什么错。这里的关键点是信息传递顺序：先有题目分析，选项分析才能做。</p><h4 id="3-报告与汇总"><a href="#3-报告与汇总" class="headerlink" title="3. 报告与汇总"></a>3. 报告与汇总</h4><p>即把不同LLM role 意见合成一份会诊报告</p><p>Repo &#x3D; LLM(QA, OA, r<del>rs</del>, prompt<del>rs</del>)：把所有专家分析丢给一个“报告助手”，提炼成“关键知识 + 总分析”。</p><h4 id="4-协作会诊"><a href="#4-协作会诊" class="headerlink" title="4.协作会诊"></a>4.协作会诊</h4><p>即多轮投票，改到全员通过为止</p><p>问题和选项的领域专家数量设置为: <code>m = 5, n = 2 PubMedQA 为 (m = 4, n = 2)</code>。最大尝试次数<code> t</code> 设置为 5。 我们为每个数据集随机采样 300 个示例,并 在它们上进行实验。统计上,我们方法的价格 为 100 个 <code>QA</code> 示例的 1.41 元(每个问题约 ¢1.4 元),每个示例的推理时间约为 40s。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">Algorithm <span class="number">1</span>: Collaborative Consultation</span><br><span class="line">Input: Domain experts D = &#123;d1, ..., dn&#125;, initial report R0, Model M,</span><br><span class="line">       maximum attempts t, prompts &#123;p_vote, p_mod, p_rev&#125;</span><br><span class="line">Output: Final report R_f</span><br><span class="line"></span><br><span class="line"><span class="comment">// Initialize variables</span></span><br><span class="line">noconf_lag ← True, ntry ← <span class="number">0</span></span><br><span class="line">R_cur ← R0, Mods ← ∅</span><br><span class="line"></span><br><span class="line"><span class="comment">// Iterative review</span></span><br><span class="line"><span class="keyword">while</span> noconf_lag is True and ntry &lt; t <span class="keyword">do</span></span><br><span class="line">    ntry ← ntry + <span class="number">1</span></span><br><span class="line">    noconf_lag ← False</span><br><span class="line"></span><br><span class="line">    <span class="comment">// vote for the report</span></span><br><span class="line">    <span class="keyword">for</span> i in <span class="number">1</span>, ..., n <span class="keyword">do</span></span><br><span class="line">        vote_i ← M(R_cur, d_i, p_vote)</span><br><span class="line"></span><br><span class="line">        <span class="comment">// propose modifications</span></span><br><span class="line">        <span class="keyword">if</span> vote_i is no then</span><br><span class="line">            Mod_i ← M(R_cur, d_i, p_mod)</span><br><span class="line">            Update Mods with Mod_i</span><br><span class="line">            noconf_lag ← True</span><br><span class="line">        end</span><br><span class="line">    end</span><br><span class="line"></span><br><span class="line">    <span class="comment">// modify the report</span></span><br><span class="line">    <span class="keyword">if</span> noconf_lag is True then</span><br><span class="line">        R_cur ← M(R_cur, Mods, p_rev)</span><br><span class="line">    end</span><br><span class="line">end</span><br><span class="line"><span class="keyword">return</span> R_f ← R_cur</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line">Algorithm <span class="number">1</span>: 协作会诊（Collaborative Consultation）</span><br><span class="line">输入：专家集合 D = &#123;d1, ..., dn&#125;</span><br><span class="line">     初始报告 R0，大模型 M，最大讨论轮数 t</span><br><span class="line">     提示词 &#123;p_vote：投票, p_mod：提修改意见, p_rev：改写报告&#125;</span><br><span class="line">输出：最终报告 R_f</span><br><span class="line"></span><br><span class="line"><span class="comment">// 初始化</span></span><br><span class="line">noconf_flag ← True     <span class="comment">// 是否仍有人不同意，初始假设“还有意见”</span></span><br><span class="line">ntry ← <span class="number">0</span>               <span class="comment">// 已讨论轮数</span></span><br><span class="line">R_cur ← R0             <span class="comment">// 当前报告从初稿 R0 开始</span></span><br><span class="line">Mods ← ∅               <span class="comment">// 收集到的修改意见集合</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 迭代评审：只要还有人反对，且没超过轮数上限，就一直开会</span></span><br><span class="line"><span class="keyword">while</span> noconf_flag 为 True 且 ntry &lt; t <span class="keyword">do</span></span><br><span class="line">    ntry ← ntry + <span class="number">1</span>        <span class="comment">// 开始新一轮</span></span><br><span class="line">    noconf_flag ← False    <span class="comment">// 先假设这一轮能全员通过</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 第一步：所有专家对当前报告投票</span></span><br><span class="line">    <span class="keyword">for</span> i in <span class="number">1</span>, ..., n <span class="keyword">do</span></span><br><span class="line">        vote_i ← M(R_cur, d_i, p_vote)   <span class="comment">// 让专家 d_i 读报告，回答 yes/no</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 第二步：投 no 的专家必须给出修改意见</span></span><br><span class="line">        <span class="keyword">if</span> vote_i 为 no then</span><br><span class="line">            Mod_i ← M(R_cur, d_i, p_mod) <span class="comment">// 问这位专家：哪里反对？怎么改？</span></span><br><span class="line">            把 Mod_i 加入 Mods            <span class="comment">// 收集意见</span></span><br><span class="line">            noconf_flag ← True           <span class="comment">// 有人反对，说明还没有通过</span></span><br><span class="line">        end</span><br><span class="line">    end</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 第三步：根据全部修改意见改写报告</span></span><br><span class="line">    <span class="keyword">if</span> noconf_flag 为 True then</span><br><span class="line">        R_cur ← M(R_cur, Mods, p_rev)   <span class="comment">// 把原报告 + 所有意见交给 LLM 重写</span></span><br><span class="line">    end</span><br><span class="line">end</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> R_f ← R_cur   <span class="comment">// 返回最终报告：全员同意，或达到 t 轮强制停止</span></span><br></pre></td></tr></table></figure><h4 id="5-决策"><a href="#5-决策" class="headerlink" title="5. 决策"></a>5. 决策</h4><p><u>要求大模型</u>拍板</p><p><code>ans = LLM(q, op, Repof, promptdm)</code>：让“医学决策者”根据最终一致报告，从选项里选出答案。</p><h3 id="分析（因为LLM毕竟是个黑盒子）"><a href="#分析（因为LLM毕竟是个黑盒子）" class="headerlink" title="分析（因为LLM毕竟是个黑盒子）"></a>分析（因为LLM毕竟是个黑盒子）</h3><h4 id="向内agent分析"><a href="#向内agent分析" class="headerlink" title="向内agent分析"></a>向内agent分析</h4><p>五阶段里，每个中间步骤到底有没有用？做法是在 MedQA 上一个一个“加装”阶段，看准确率怎么变：</p><table><thead><tr><th>配置</th><th>MedQA 准确率</th><th>相比上一档</th></tr></thead><tbody><tr><td>Direct Prompting（直接问答案）</td><td>49.0%</td><td>起点</td></tr><tr><td>CoT Prompting（只加思维链）</td><td>55.0%</td><td>+6.0</td></tr><tr><td>+ Analysis（加个体专家分析）</td><td>62.0%</td><td><strong>+7.0</strong></td></tr><tr><td>+ Summarization（加报告汇总）</td><td>65.0%</td><td>+3.0</td></tr><tr><td>+ Consultation（加协作会诊）</td><td>67.0%</td><td>+2.0</td></tr></tbody></table><p>结论很明确：<strong>每个环节都贡献提升，但贡献不平等</strong>。个体专家分析是最大增量（+7），说明“角色化让 LLM 把知识挖出来”是整个框架的主力；报告汇总再补 3 分，会诊只再补 2 分，后面两位主要起验证和修正作用，不是性能引擎。</p><h4 id="向外agent分析"><a href="#向外agent分析" class="headerlink" title="向外agent分析"></a>向外agent分析</h4><h5 id="同一个模型，换一种多人协作的组织方式，能把知识用得更好吗？"><a href="#同一个模型，换一种多人协作的组织方式，能把知识用得更好吗？" class="headerlink" title="同一个模型，换一种多人协作的组织方式，能把知识用得更好吗？"></a>同一个模型，换一种多人协作的组织方式，能把知识用得更好吗？</h5><p><strong>同一个模型下的变量有三个：</strong></p><ol><li>Few-shot：在提问之前给模型几个手写的示范例子，格式是 <code>Q: 问题 A: 答案是...</code>。</li><li>Few-shot CoT：示范例子不变，但每个例子里都多写一段推理过程，也就是先给理由、再给答案。</li><li>SC（Self-Consistency，自洽采样）：同一个问题采样多条推理链，最后少数服从多数。论文自己的实现是采样 5 次、temperature 设为 0.7</li></ol><p><strong>结果：</strong></p><ol><li>大幅超过“直接问答案”的零样本基线。GPT-4 上平均分从 80.6 提到 86.7，高出约 6 分；GPT-3.5 上从 67.8 提到 72.1。<u>即不用微调、不用检索，靠协作流程就能赢过裸模型。</u></li><li>零样本条件下追平甚至压过“带示例”的强基线 Few-shot CoT+SC。GPT-4 是 86.7 对 85.4，GPT-3.5 是 72.1 对 71.6。这意味着 MedAgents 达到了 few-shot 提示的水平，却不需要任何人写示范例子。</li><li>收益不均衡，不能宣称处处都赢。比如 GPT-3.5 在 PubMedQA 上 MedAgents 只有 72.9，低于 Zero-shot CoT + SC 的 75.7。Table 2 里还能看到另一个现象：单独的 CoT 在某些数据集上反而掉分，比如 GPT-4 的 MedQA 从 Zero-shot 73.0 降到 Zero-shot CoT 61.8。论文把这解释为医疗领域 CoT 可能诱发幻觉，而多智能体角色扮演能缓解这个问题。</li></ol><p>MedAgents 在九套静态医学题上，零样本、无训练、无 RAG，却同时做到了“远超裸模型、追平最强带示范提示”的效果；但收益要看数据集，不是所有地方都更优。</p><h5 id="和其他开源模型相比怎么样？"><a href="#和其他开源模型相比怎么样？" class="headerlink" title="和其他开源模型相比怎么样？"></a>和其他开源模型相比怎么样？</h5><p>这些开源医学微调模型当时不够强（ 2024 年前后的模型水平，后来 Llama、Qwen 等开源模型进步很快，开源也是可能打过闭源的），追不上通用大模型，于是作者干脆不往“微调医学模型”这个方向走，改用 GPT 加多智能体提示流程。</p><p>⭐所以早期医疗 MAS 普遍搭在 GPT 等闭源 API 上，而不是开源模型上。</p><h4 id="Agent数量"><a href="#Agent数量" class="headerlink" title="Agent数量"></a>Agent数量</h4><p> Agent 数量不是越多越好。论文证明加专家确实比不加好；最优数量各数据集一致，是 5 个问题域专家加 2 个选项域专家。<u>再加多或配比不对，收益并不继续涨</u>。</p><h4 id="多样性-vs-同质化"><a href="#多样性-vs-同质化" class="headerlink" title="多样性 vs 同质化"></a>多样性 vs 同质化</h4><p><strong>测试集介绍</strong></p><table><thead><tr><th>名称</th><th>全称&#x2F;来源</th><th>考什么</th><th>题目形式</th><th>论文里的规模</th></tr></thead><tbody><tr><td>MedQA</td><td>美国执业医师资格考试风格题库</td><td>临床推理、诊断、治疗决策</td><td>四到五选一</td><td>1273 题</td></tr><tr><td>MedMCQA</td><td>印度医学院入学考试（AIIMS&#x2F;NEET PG）</td><td>医学基础知识与临床题</td><td>四选一</td><td>约 6.1K 题</td></tr><tr><td>PubMedQA</td><td>基于 PubMed 论文摘要的问答集</td><td>医学文献理解与推断</td><td>Yes &#x2F; No &#x2F; Maybe</td><td>500 题</td></tr><tr><td>MMLU</td><td>通用“大规模多任务语言理解”基准</td><td>涵盖各学科，不只是医学</td><td>四选一多项选择</td><td>取 6 个医学子任务共 1089 题</td></tr></tbody></table><p><strong>测试结果</strong></p><table><thead><tr><th>配置（都是 6 个左右专家）</th><th>MedQA</th><th>MedMCQA</th></tr></thead><tbody><tr><td>6 个不同领域</td><td>64.1</td><td>59.3</td></tr><tr><td>6 个相同领域</td><td>59.2</td><td>58.1</td></tr><tr><td>5 个相同领域</td><td>57.5</td><td>57.3</td></tr><tr><td>4 个相同领域</td><td>55.9</td><td>57.0</td></tr></tbody></table><p>同样的人数，把领域换成重复的，分数一路往下掉。领域多样性要比专家数量更重要。</p><p><strong>补充：删掉哪个领域的agent影响最大？</strong></p><p>删最相关领域明显掉分，删最不相关领域反而轻微提升。也就是说专家不是“请得越多越好”，请错人（选了可有可无甚至多余的专业）会拖后腿，专家组合的相关性很重要。</p><h4 id="缺点分析"><a href="#缺点分析" class="headerlink" title="缺点分析"></a>缺点分析</h4><p>主要分析系统答错的时候，错在哪里。</p><p>论文随机抽了 MedQA 和 MedMCQA 里的 40 个错误案例做人工分类，把错误归成四类：</p><ol><li>Lack of Domain Knowledge：模型不知道这个医学知识；</li><li>Mis-retrieval of Domain Knowledge：知识学过，但调用错了或没用到对的上下文；</li><li>Consistency Errors：对同一句话给出前后矛盾的反应；</li><li>CoT Errors：推理链本身推导错误。</li></ol><p>约 <u>77%</u>的错误来自前两类合并的“领域知识问题”（缺乏 + 误检索）。多数失败不是“推理不会推”，而是“知识本身超出 LLM 内部范围”。作者也承认这个问题：协作能把已有知识组织起来，但补不了缺失的知识。</p><h3 id="局限性"><a href="#局限性" class="headerlink" title="局限性"></a>局限性</h3><ol><li>大语言模型内部的参数化知识会随时间推移发生过时，因此需要持续投入工作以维持该框架的时效性。</li><li>在框架的不同阶段接入多种不同模型，会是一个颇具研究价值的探索方向。</li><li>该框架在低资源语言场景下适用性有限。将本框架适配到更多低资源语言，能够在一定程度上满足这些语言地区的特定医疗需求。</li></ol><h2 id="⑤MDAgents-an-adaptive-collaboration-of-LLMs-for-medical-decision-making"><a href="#⑤MDAgents-an-adaptive-collaboration-of-LLMs-for-medical-decision-making" class="headerlink" title="⑤MDAgents: an adaptive collaboration of LLMs for medical decision-making"></a>⑤MDAgents: an adaptive collaboration of LLMs for medical decision-making</h2><p>从单个的llm创造多个会话来模拟医生到创建agent来管理，然后演变为多个agent互相协调，最后提出不应该用LLM 工作流来评估这个工作流程，而是使用AI加医生</p>]]>
    </content>
    <id>https://tysweb.pages.dev/2026/08/16/%E6%96%87%E7%AB%A0%E9%AA%A8%E6%9E%B6%EF%BC%8812%E7%AF%87%EF%BC%89/</id>
    <link href="https://tysweb.pages.dev/2026/08/16/%E6%96%87%E7%AB%A0%E9%AA%A8%E6%9E%B6%EF%BC%8812%E7%AF%87%EF%BC%89/"/>
    <published>2026-08-16T08:38:13.000Z</published>
    <summary>
      <![CDATA[<blockquote>
<p>这一组决定你对”多智能体””MDT””综述定位”的基本理解。读的时候不要追求记住每个细节，要追求”能用自己的话讲清楚一个完整故事”。</p>
</blockquote>
<h1 id="目录"><a href="#目录" class="header]]>
    </summary>
    <title>文章骨架（12篇）</title>
    <updated>2026-09-07T01:31:21.933Z</updated>
  </entry>
  <entry>
    <author>
      <name>ctyyy</name>
    </author>
    <category term="大模型" scheme="https://tysweb.pages.dev/categories/%E5%A4%A7%E6%A8%A1%E5%9E%8B/"/>
    <category term="AI" scheme="https://tysweb.pages.dev/tags/AI/"/>
    <category term="Prompt" scheme="https://tysweb.pages.dev/tags/Prompt/"/>
    <content>
      <![CDATA[<h1 id="一个项目的提示词（220k-stars）-英文"><a href="#一个项目的提示词（220k-stars）-英文" class="headerlink" title="一个项目的提示词（220k stars）[英文]"></a>一个项目的提示词（220k stars）[英文]</h1><p>Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed.</p><p><strong>Tradeoff:</strong> These guidelines bias toward caution over speed. For trivial tasks, use judgment.</p><h2 id="1-Think-Before-Coding"><a href="#1-Think-Before-Coding" class="headerlink" title="1. Think Before Coding"></a>1. Think Before Coding</h2><p><strong>Don’t assume. Don’t hide confusion. Surface tradeoffs.</strong></p><p>Before implementing:</p><ul><li>State your assumptions explicitly. If uncertain, ask.</li><li>If multiple interpretations exist, present them - don’t pick silently.</li><li>If a simpler approach exists, say so. Push back when warranted.</li><li>If something is unclear, stop. Name what’s confusing. Ask.</li></ul><h2 id="2-Simplicity-First"><a href="#2-Simplicity-First" class="headerlink" title="2. Simplicity First"></a>2. Simplicity First</h2><p><strong>Minimum code that solves the problem. Nothing speculative.</strong></p><ul><li>No features beyond what was asked.</li><li>No abstractions for single-use code.</li><li>No “flexibility” or “configurability” that wasn’t requested.</li><li>No error handling for impossible scenarios.</li><li>If you write 200 lines and it could be 50, rewrite it.</li></ul><p>Ask yourself: “Would a senior engineer say this is overcomplicated?” If yes, simplify.</p><h2 id="3-Surgical-Changes"><a href="#3-Surgical-Changes" class="headerlink" title="3. Surgical Changes"></a>3. Surgical Changes</h2><p><strong>Touch only what you must. Clean up only your own mess.</strong></p><p>When editing existing code:</p><ul><li>Don’t “improve” adjacent code, comments, or formatting.</li><li>Don’t refactor things that aren’t broken.</li><li>Match existing style, even if you’d do it differently.</li><li>If you notice unrelated dead code, mention it - don’t delete it.</li></ul><p>When your changes create orphans:</p><ul><li>Remove imports&#x2F;variables&#x2F;functions that YOUR changes made unused.</li><li>Don’t remove pre-existing dead code unless asked.</li></ul><p>The test: Every changed line should trace directly to the user’s request.</p><h2 id="4-Goal-Driven-Execution"><a href="#4-Goal-Driven-Execution" class="headerlink" title="4. Goal-Driven Execution"></a>4. Goal-Driven Execution</h2><p><strong>Define success criteria. Loop until verified.</strong></p><p>Transform tasks into verifiable goals:</p><ul><li>“Add validation” → “Write tests for invalid inputs, then make them pass”</li><li>“Fix the bug” → “Write a test that reproduces it, then make it pass”</li><li>“Refactor X” → “Ensure tests pass before and after”</li></ul><p>For multi-step tasks, state a brief plan:</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="bullet">1.</span> [Step] → verify: [check]</span><br><span class="line"><span class="bullet">2.</span> [Step] → verify: [check]</span><br><span class="line"><span class="bullet">3.</span> [Step] → verify: [check]</span><br></pre></td></tr></table></figure><p>Strong success criteria let you loop independently. Weak criteria (“make it work”) require constant clarification.</p><p><strong>These guidelines are working if:</strong> fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, and clarifying questions come before implementation rather than after mistakes.</p><h1 id="一个项目的提示词（220k-stars）-中文"><a href="#一个项目的提示词（220k-stars）-中文" class="headerlink" title="一个项目的提示词（220k stars）[中文]"></a>一个项目的提示词（220k stars）[中文]</h1><p>减少大模型编码常见错误的行为准则</p><p>可根据项目实际需求，与项目专属指令合并使用。</p><p><strong>权衡说明</strong>：这套准则优先偏向稳妥，而非追求开发速度。处理简单琐碎任务时，可灵活判断取舍。</p><h2 id="1-编码前先思考"><a href="#1-编码前先思考" class="headerlink" title="1. 编码前先思考"></a>1. 编码前先思考</h2><p><strong>不要主观臆断，不要掩盖疑问，主动摆出方案取舍。</strong></p><p>在写代码实现功能之前：</p><ul><li>明确写出你的前置假设。存在不确定点时，主动提问确认。</li><li>如果需求存在多种解读，全部列出来，不要私自选定某一种。</li><li>如果有更简单的实现思路，主动说明；必要时对复杂方案提出异议。</li><li>遇到模糊不清的地方就暂停，点明困惑点，发起询问。</li></ul><h2 id="2-优先追求简洁"><a href="#2-优先追求简洁" class="headerlink" title="2. 优先追求简洁"></a>2. 优先追求简洁</h2><p><strong>用最少的代码解决问题，不做没有依据的超前设计。</strong></p><ul><li>绝不实现需求之外的额外功能。</li><li>只使用一次的代码，不要强行做抽象封装。</li><li>没有明确要求，不要额外增加灵活性、可配置能力。</li><li>不必处理理论上不可能发生的异常场景。</li><li>如果写了 200 行代码，但 50 行就可以完成，就重新精简。</li></ul><p>自我审视：资深工程师会不会认为这段代码过度复杂？ 如果答案是肯定的，就做简化。</p><h2 id="3-精准改动代码"><a href="#3-精准改动代码" class="headerlink" title="3. 精准改动代码"></a>3. 精准改动代码</h2><p><strong>只修改必须改动的部分；仅清理自己改动产生的冗余。</strong></p><p>修改已有代码时：</p><ul><li>不要顺手 “优化” 无关代码、注释、代码格式。</li><li>不要重构没有问题的代码。</li><li>遵从项目现有的代码风格，即便你习惯另一种写法。</li><li>如果发现无关的无效旧代码，只做标注提醒，不要直接删除。</li></ul><p>当你的改动产生无用代码时：</p><ul><li>删掉**由本次改动导致不再使用的导入、变量、函数。</li><li>原本就存在的无效旧代码，未经要求不要删除。</li></ul><p>校验标准：每一行被修改的代码，都应当和用户的需求直接对应。</p><h2 id="4-以目标驱动执行"><a href="#4-以目标驱动执行" class="headerlink" title="4. 以目标驱动执行"></a>4. 以目标驱动执行</h2><p><strong>明确验收标准，迭代直到验证通过。</strong></p><p>把开发任务转化成可验证的目标：</p><ul><li>“增加校验逻辑” → “编写非法输入的测试用例，再让用例全部通过”</li><li>“修复 Bug” → “编写可以复现问题的测试用例，再修复使用例通过”</li><li>“重构模块 X” → “保证重构前后全部测试用例均可运行通过”</li></ul><p>多步骤任务，先输出简短执行计划：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">1. [步骤] → 验证点：[检查项]</span><br><span class="line">2. [步骤] → 验证点：[检查项]</span><br><span class="line">3. [步骤] → 验证点：[检查项]</span><br></pre></td></tr></table></figure><p>清晰可落地的成功标准，可以自主迭代；模糊的目标（例如 “把它弄好”）则需要反复确认需求。</p><p><strong>这套准则生效的标志</strong>：代码差异中无效改动变少；因过度设计而返工的情况减少；疑问和确认发生在编码之前，而非出错之后。</p>]]>
    </content>
    <id>https://tysweb.pages.dev/2026/08/13/Prompt-Engineering/</id>
    <link href="https://tysweb.pages.dev/2026/08/13/Prompt-Engineering/"/>
    <published>2026-08-13T10:52:27.000Z</published>
    <summary>
      <![CDATA[<h1 id="一个项目的提示词（220k-stars）-英文"><a href="#一个项目的提示词（220k-stars）-英文" class="headerlink" title="一个项目的提示词（220k stars）[英文]"></a>一个项目的提示词（220k st]]>
    </summary>
    <title>Prompt Engineering</title>
    <updated>2026-09-07T01:31:21.861Z</updated>
  </entry>
  <entry>
    <author>
      <name>ctyyy</name>
    </author>
    <category term="随笔" scheme="https://tysweb.pages.dev/tags/%E9%9A%8F%E7%AC%94/"/>
    <content>
      <![CDATA[<h1 id="朋友家网DNS给我网址解析到成人网站"><a href="#朋友家网DNS给我网址解析到成人网站" class="headerlink" title="朋友家网DNS给我网址解析到成人网站"></a>朋友家网DNS给我网址解析到成人网站</h1><h2 id="问题展示"><a href="#问题展示" class="headerlink" title="问题展示"></a>问题展示</h2><p><video src="2026-08-13 16-32-12.mp4" controls preload="metadata"></video></p><h2 id="找出问题"><a href="#找出问题" class="headerlink" title="找出问题"></a>找出问题</h2><p><strong>终端实际解析的ip</strong></p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nslookup opencode.ai</span><br></pre></td></tr></table></figure><p><img src="/2026/08/13/%E9%82%A3%E4%BA%9B%E5%B9%B4%E9%82%A3%E4%BA%9B%E4%BA%8B%E9%82%A3%E4%BA%9Bbug/image-20260813165027516.png" alt="image-20260813165027516"></p><p><code>27.124.x.x </code>这个 IP 段就非常可疑——这是 AnyIP 或 IP 广播服务的常见范围，一般这种ip就被劫持了。</p><p><strong>让我看一下真实的DNS是什么？</strong></p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nslookup opencode.ai 8.8.8.8</span><br></pre></td></tr></table></figure><p><img src="/2026/08/13/%E9%82%A3%E4%BA%9B%E5%B9%B4%E9%82%A3%E4%BA%9B%E4%BA%8B%E9%82%A3%E4%BA%9Bbug/image-20260813165622510.png" alt="image-20260813165622510"></p><p>确定了，被 194.169.55.201这个DNS服务器在劫持流量</p><h2 id="问题解决"><a href="#问题解决" class="headerlink" title="问题解决"></a>问题解决</h2><p><strong>如果ISP没有被劫持，DHCP（路由器）也没有被劫持，后台修改DNS为自动就行了</strong></p><blockquote><p>ISP：上层网关开发商，路由器的WAN口（WAN &#x3D; Wide Area Network，广域网）连接的ISP网络。路由器的ip是ISP的DHCP服务器给的。</p></blockquote><p><strong>如果ISP可能被劫持，DHCP（路由器）也可能被劫持，后台修改DNS为8.8.8.8或者换路由器或者重启路由器</strong></p><p>因为是根已经坏了，要么上层ISP被劫持，要么DHCP服务器被安装木马。</p><h2 id="问题刨析"><a href="#问题刨析" class="headerlink" title="问题刨析"></a>问题刨析</h2><h3 id="为什么DNS自动分配后面会有一个DHCP？"><a href="#为什么DNS自动分配后面会有一个DHCP？" class="headerlink" title="为什么DNS自动分配后面会有一个DHCP？"></a>为什么DNS自动分配后面会有一个DHCP？</h3><p><img src="/2026/08/13/%E9%82%A3%E4%BA%9B%E5%B9%B4%E9%82%A3%E4%BA%9B%E4%BA%8B%E9%82%A3%E4%BA%9Bbug/image-20260813170506886.png" alt="image-20260813170506886"></p><p> DHCP 那行显示 (DHCP) 的意思是DNS 服务器地址也是由 DHCP 自动分配的，不是你手动的。当你设备连接 WiFi 时，路由器上的 DHCP 服务器会一次性和你说好：</p><table><thead><tr><th>设置项</th><th>作用</th></tr></thead><tbody><tr><td>IP 地址</td><td>你设备在局域网里的门牌号</td></tr><tr><td>子网掩码</td><td>判断局域网范围的</td></tr><tr><td>网关</td><td>路由器局域网IP，出入口</td></tr><tr><td>DNS 服务器</td><td>你要用的 DNS 服务器地址</td></tr></tbody></table><h3 id="被劫持的流程"><a href="#被劫持的流程" class="headerlink" title="被劫持的流程"></a><strong>被劫持的流程</strong></h3><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">情况 1：DHCP 被改了（路由器 DHCP 服务器被黑）</span><br><span class="line"></span><br><span class="line">  路由器被入侵后，它自己的 DHCP 功能被篡改，本来应该告诉你 DNS 是 8.8.8.8，结果告诉你是 194.169.55.201。</span><br><span class="line">  </span><br><span class="line">  你电脑插上网线/WiFi</span><br><span class="line"><span class="code">          ↓</span></span><br><span class="line"><span class="code">  路由器（DHCP服务器）回复：</span></span><br><span class="line"><span class="code">    &quot;你的IP是 xxx，你的DNS用 194.169.55.201&quot;</span></span><br><span class="line"><span class="code">          ↓</span></span><br><span class="line"><span class="code">  你的电脑乖乖听话，去用这个恶意DNS</span></span><br><span class="line"><span class="code">  </span></span><br><span class="line"><span class="code">  </span></span><br><span class="line"><span class="code">  情况 2：路由器的上游 DNS 被改了</span></span><br><span class="line"><span class="code">  </span></span><br><span class="line"><span class="code">  路由器 DHCP 功能没问题，但路由器自己的 DNS 设置被改成了 194.169.55.201。</span></span><br><span class="line"><span class="code"></span></span><br><span class="line">  你电脑问路由器DNS: opencode.ai 是谁？</span><br><span class="line"><span class="code">          ↓</span></span><br><span class="line"><span class="code">  路由器去问上游DNS: 194.169.55.201</span></span><br><span class="line"><span class="code">          ↓</span></span><br><span class="line"><span class="code">  194.169.55.201 返回成人网站IP</span></span><br></pre></td></tr></table></figure><p>DNS被劫持常见原因：</p><pre><code>1. 路由器默认密码没改 — 被人登录进去改了 DNS 设置2. 路由器漏洞 — 老旧路由器被远程入侵3. 蹭网的人搞的 — 如果有人知道密码，可能故意劫持 DNS 赚钱（劫持流量到成人网站可以拿佣金）4. 蹭网软件 — 有些蹭网/WiFi钥匙软件会偷偷改 DNS</code></pre><p>DNS 劫持的常见危害</p><ol><li>密码&#x2F;账户被盗：你以为自己登录的是银行官网，其实是被劫持到的钓鱼网站，你输入的密码直接发给攻击者。</li><li>电商欺诈：你想访问淘宝&#x2F;京东，被劫持到假冒的购物网站，付款直接进骗子口袋。</li><li>网银盗刷：登录网银时跳转到钓鱼页面，输入卡号密码就被盗。</li><li>恶意软件：有些 DNS 劫持会诱导你下载”杀毒软件”或”插件”，实际上是木马。</li><li>广告轰炸：劫持者把正常网站的广告替换成自己的，靠流量赚钱。你访问每个网站都被强行塞广告。</li><li>SSL 证书失效（部分情况）：如果劫持者用了自签名证书，浏览器可能会报安全警告，但也可能直接放行（取决于用户是否忽略警告）。</li><li>隐私泄露：你访问什么网站都被 DNS 劫持者知道得一清二楚。</li></ol>]]>
    </content>
    <id>https://tysweb.pages.dev/2026/08/13/%E9%82%A3%E4%BA%9B%E5%B9%B4%E9%82%A3%E4%BA%9B%E4%BA%8B%E9%82%A3%E4%BA%9Bbug/</id>
    <link href="https://tysweb.pages.dev/2026/08/13/%E9%82%A3%E4%BA%9B%E5%B9%B4%E9%82%A3%E4%BA%9B%E4%BA%8B%E9%82%A3%E4%BA%9Bbug/"/>
    <published>2026-08-13T08:44:25.000Z</published>
    <summary>
      <![CDATA[<h1 id="朋友家网DNS给我网址解析到成人网站"><a href="#朋友家网DNS给我网址解析到成人网站" class="headerlink" title="朋友家网DNS给我网址解析到成人网站"></a>朋友家网DNS给我网址解析到成人网站</h1><h2 id="问]]>
    </summary>
    <title>那些年那些事那些bug</title>
    <updated>2026-09-07T01:31:21.938Z</updated>
  </entry>
  <entry>
    <author>
      <name>ctyyy</name>
    </author>
    <category term="Multi-agent system for MDT" scheme="https://tysweb.pages.dev/categories/Multi-agent-system-for-MDT/"/>
    <category term="多智能体" scheme="https://tysweb.pages.dev/tags/%E5%A4%9A%E6%99%BA%E8%83%BD%E4%BD%93/"/>
    <category term="论文" scheme="https://tysweb.pages.dev/tags/%E8%AE%BA%E6%96%87/"/>
    <content>
      <![CDATA[<p><a href="%E5%A6%87%E7%A7%91%E5%A4%9A%E6%99%BA%E8%83%BD%E4%BD%93.pdf">Download PDF</a></p><h1 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h1><h2 id="现实医学背景"><a href="#现实医学背景" class="headerlink" title="现实医学背景"></a>现实医学背景</h2><blockquote><p><strong>MDT</strong>：MDT 的全称是 Multidisciplinary Team，可理解为多学科团队协作。团队通常包含外科、肿瘤内科、放疗科、影像科、病理科等医生，有时护士、营养师、心理医生也会加入。大家围坐讨论，避免单一科室决策的局限。</p></blockquote><p>卵巢肿瘤的管理越来越依赖于多学科肿瘤委员会MDT的讨论，以应对需要手术、肿瘤内科、影像、病理、分子检测多学科协同治疗。并且此病症有三个特别棘手的特征：晚期诊断、显著的肿瘤异质性、频繁复发。这些特征意味着患者在整个病程里需要反复面对高风险决策。然而全球大多数患者缺乏及时的专家共识,尤其在资源受限的中心。MDT 资源稀缺甚至完全不可用。</p><p>于是，本文提出了OMGs（卵巢肿瘤多学科智能体系统），多智能体AI框架，通过协调多学科的证据，用于给出透明依据的MDT式的建议</p><h2 id="AI决策支持的四个挑战"><a href="#AI决策支持的四个挑战" class="headerlink" title="AI决策支持的四个挑战"></a>AI决策支持的四个挑战</h2><blockquote><p>In this context, single-agent large language model (LLM) assistants may be insufficient to ensure that recommendations remain consistently verifiable and traceable across incomplete and evolving longitudinal records.</p><p>单agent大语言模型助手在零散且不断演变的纵向记录中，可能无法保证建议始终可验证和可追溯。因此需要多agent设计来应对这些挑战。</p></blockquote><p>开发卵巢肿瘤AI决策支持系统面临几个固有挑战，这四个挑战也直接决定了OMGs的设计方向：</p><ol><li>用agent进行仿照MDTs的讨论得出对病人的具体分析，这项任务具有多学科性，需要跨专业进行针对特定角色的推理，并在解释出现分歧时进行协调。</li><li>在整个护理过程中，决策空间会随着临床场景的变化而变化，包括初步管理、组织学驱动的路径、铂类耐药复发、铂类敏感复发以及事件驱动的重新评估。</li><li>输入agent数据具有纵向性，且可能不完整，分布在时间顺序的报告中，存在数据缺失、不确定性和评估不一致的情况。</li><li>临床部署需要透明度和可追溯性，将建议与可验证的患者特异性证据联系起来，并明确指出不确定性和重新评估，以支持问责和审计。</li></ol><h1 id="为什么选择多智能体"><a href="#为什么选择多智能体" class="headerlink" title="为什么选择多智能体"></a>为什么选择多智能体</h1><p>上述四个挑战中，多学科性需要角色分工（挑战1），纵向不完整数据需要显式标注缺口和矛盾（挑战3），透明度需求需要可追溯的证据链（挑战4）。多智能体架构恰好能逐一对应这些需求。</p><h3 id="LLM天然适配MDTs"><a href="#LLM天然适配MDTs" class="headerlink" title="LLM天然适配MDTs"></a>LLM天然适配MDTs</h3><blockquote><p>Such systems naturally fit the MDTs and enable seamless integration of multimodal clinical data, external knowledge bases, and case repositories through coordinated tool use, while reconciling conflicting perspectives via structured reasoning and evidence attribution.</p><p>此类系统自然契合多学科团队（MDTs）的需求，通过协同使用工具，实现多模态临床数据、外部知识库和病例库的无缝集成，同时通过结构化推理和证据归因来调和相互冲突的观点。</p></blockquote><h3 id="比单智能体更有效率"><a href="#比单智能体更有效率" class="headerlink" title="比单智能体更有效率"></a>比单智能体更有效率</h3><blockquote><p>Compared with single-agent approaches, a multi-agent design may better structure role-specific reasoning and facilitate evidence-grounded reporting, which is hypothesized to improve auditability under fragmented records.</p><p>与单agent相比，多agent设计可能更有利于构建特定角色的推理结构，并促进基于证据的报告，这被认为可以提高零散记录下的可审计性。</p><p><strong>可审计性</strong>：当病历又碎又缺时,多 agent 把推理拆成几个角色各自负责的部分,缺口和矛盾被不同 agent 显式挑出来,而不是埋在一个黑箱里–这样事后追溯”建议怎么来的、哪里可能出错”就更容易。</p></blockquote><h1 id="OMGs系统的实现"><a href="#OMGs系统的实现" class="headerlink" title="OMGs系统的实现"></a>OMGs系统的实现</h1><h2 id="系统概述"><a href="#系统概述" class="headerlink" title="系统概述"></a>系统概述</h2><p><img src="/2026/08/02/OMGs%E8%AE%BA%E6%96%87%E8%A7%A3%E8%AF%BB/image-20260805001554263.png" alt="image-20260805001554263"></p><p>OMGs采用两层架构：</p><ul><li><strong>Agent编排层（Orchestrator）</strong>：协调五个专科agent进行结构化MDT审议。五个角色分别是主席（Chair）、肿瘤内科（Medical Oncology）、影像科（Radiology）、病理科（Pathology）和核医学科（Nuclear Medicine），每个agent配备特定领域的专业知识和精选临床数据。</li><li><strong>Agent服务层（Agent Servers）</strong>：支持临床数据提取、上下文组装、证据检索、报告选择和来源追踪。</li></ul><p>收到患者病例和纵向临床记录后，编排层协调五个专科agent各自从自己的领域分析病例。每个agent从临床实践指南、生物医学文献和试验注册库中检索与其专科相关的证据。<u>随后agent进行多轮、有证据支撑的审议</u>，每个专家可以质疑、澄清和修正其他人的解读，以达成共识，模拟真实MDT会议的动态。</p><p>系统最终输出结构化决策摘要，包含三部分：最终评估（Final Assessment）**、**核心治疗策略（Core Treatment Strategy）和变更触发条件（Change Triggers），均与可追溯的证据来源关联。</p><h2 id="临床输入处理"><a href="#临床输入处理" class="headerlink" title="临床输入处理"></a>临床输入处理</h2><blockquote><p><strong>文档级来源元数据</strong>：系统从病历里提取每一条信息时，都会给它贴一个”标签”，记录这条信息是从哪份文档、什么日期的文档里提取出来的。</p><ul><li><code>value</code>: 高级别浆液性癌</li><li><code>document_type</code>: 病理报告</li><li><code>document_date</code>: 2025-03-01</li></ul><p>这个 <code>(document_type, document_date)</code> 就是文档级来源元数据，即这条数据从哪来的。 因为卵巢癌患者的病历是纵向的，同一个指标在不同时间可能有不同结果（比如化疗前后肿瘤标志物变化、影像评估变化）。有了这个标签，系统输出的建议里如果引用了某个发现，可以追溯到具体是哪一天哪份报告说的</p><p><strong>结构化病例</strong>：把一堆格式各异、散落在各处的文档，整理成一份字段固定的、机器能直接读懂的标准格式。</p></blockquote><p><img src="/2026/08/02/OMGs%E8%AE%BA%E6%96%87%E8%A7%A3%E8%AF%BB/image-20260805214320537.png" alt="image-20260805214320537"></p><p>对于每个病例，OMGs将纵向EHR文档转换为以<u>索引MDT日期</u>（即记录的MDT讨论日期）为基准的结构化病例摘要。系统对原始病历（包含异质临床文档和元数据）应用EHR结构化函数，生成规范化的病例表示。</p><p>使用预定义的病例模板，LLM从每份文档中提取显性事实，输出符合schema的JSON，缺失或不支持的值记录为”Unknown”。提取的条目保留<u>文档级来源元数据</u>（如文档类型和文档日期），以支持结构化字段到原始材料的可追溯性。条目按模态和时间规则进行标准化和合并，<u>不补全不可用的信息</u>。</p><h2 id="角色范围信息访问与证据检索"><a href="#角色范围信息访问与证据检索" class="headerlink" title="角色范围信息访问与证据检索"></a>角色范围信息访问与证据检索</h2><p><img src="/2026/08/02/OMGs%E8%AE%BA%E6%96%87%E8%A7%A3%E8%AF%BB/image-20260805214715724.png" alt="image-20260805214715724"></p><p>为反映真实MDT的边界，系统强制执行<u>角色范围访问</u>：从结构化病例表示和预定义源文档中打包专科特定的输入。专科agent仅限于访问与其角色相关的输入，而主席agent可以访问自己的角色范围包，并在审议期间整合跨专科的贡献，最终进行仲裁和综合。</p><p>外部医学知识通过<u>受控证据检索模块</u>纳入，由结构化病例schema生成的查询驱动，查询锚定于疾病背景、临床场景和既往治疗暴露。检索到的证据组织为两个互补的流，从两个预分块、语义嵌入的语料库中使用嵌入相似性搜索检索：</p><ul><li><strong>临床实践指南</strong>：精选并协调主要国际和国家框架，增强专科特定建议</li><li><strong>医学文献</strong>：来自MEDLINE基线数据集，优先考虑高级别临床证据（Cochrane综述、荟萃分析、III期随机对照试验、设计良好的队列研究）</li></ul><p>检索到的条目经过去重、过滤和规范化，存入<u>证据库</u>，分配稳定标识符和PMID（如有）。为避免评估期间的时间漂移，每个评估阶段使用的指南语料库和证据库索引都是固定的。</p><h2 id="多智能体受约束审议"><a href="#多智能体受约束审议" class="headerlink" title="多智能体受约束审议"></a>多智能体受约束审议</h2><p><img src="/2026/08/02/OMGs%E8%AE%BA%E6%96%87%E8%A7%A3%E8%AF%BB/image-20260805215439590.png" alt="image-20260805215439590"></p><p>基于结构化病例表示、角色范围输入和集中证据库，系统进行<u>受控多角色审议</u>，模拟MDT治理而非自由形式的agent交互。</p><p>每个角色agent首先独立产出角色特定的评估和建议，明确说明安全考虑、关键不确定性和可追溯的支撑文献。随后进入<u>受约束审议阶段</u>：agent默认保持沉默，仅在满足预定义条件时才被允许发言，包括：</p><ul><li>角色间冲突</li><li>安全问题</li><li>关键信息缺失</li><li>新发现的决策相关证据</li></ul><p>所有干预都是角色定向的，并明确标注理由，确保交流聚焦且可审计。</p><p>主席agent随后调和跨专科分歧，综合出统一的MDT式建议，以schema约束的形式表达：</p><p>$$<br>Y &#x3D; (\text{Final Assessment},; \text{Core Treatment Strategy},; \text{Change Triggers})<br>$$</p><p>OMGs最终吐出来的建议，固定由三块内容组成。</p><ul><li><p><strong>最终评估</strong>（Final Assessment）：回答”这个病人现在什么情况”。</p><p>比如：IIIC期高级别浆液性卵巢癌，BRCA1突变阳性，HRD阳性，首次诊断，未接受过治疗。</p></li><li><p><strong>核心治疗策略</strong>（Core Treatment Strategy）：回答”接下来怎么治、为什么这么治”。</p><p>比如：先行新辅助化疗（卡铂+紫杉醇）3-4周期，随后行中间性肿瘤减灭术（IDS），术后继续化疗并以奥拉帕利维持治疗。理由：肿瘤广泛腹腔播散，不适合直接手术（PDS）；BRCA突变阳性，PARP抑制剂维持治疗有生存获益。</p></li><li><p><strong>变更触发条件</strong>（Change Triggers）：回答”什么情况下要重新评估或改变方案”。</p><p>比如：若2周期化疗后CA-125未下降，需重新评估化疗敏感性；若影像提示疾病进展，考虑更换为非铂方案；若出现严重骨髓抑制，需调整剂量。</p></li></ul><p>最终评估总结调和后的疾病状态和风险分层，核心治疗策略指定选定的管理路径及其临床理由，变更触发条件定义需要重新评估或升级的明确临床或安全条件。Y的每个元素都必须附带可追溯的证据引用。</p><h2 id="伦理审查与学习监督"><a href="#伦理审查与学习监督" class="headerlink" title="伦理审查与学习监督"></a>伦理审查与学习监督</h2><blockquote><p><strong>去标识化</strong>：去标识化(de-identification)就是把病历里能认出”这是哪个病人”的信息删掉或替换掉,只留下临床内容,这样数据可以拿来做研究而不侵犯病人隐私。</p></blockquote><p>本研究在所有参与中心的机构审查委员会获得了伦理批准。</p><ul><li><strong>回顾性分析</strong>：因研究仅使用完全去标识化的数据且风险极低，获得了知情同意豁免（FUSCC伦理批件 2601-Exp365）。</li><li><strong>前瞻性队列</strong>：入组前获得书面知情同意（FUSCC 2508-Exp538、SFMIH KS25394、FOGH 2025-152）。</li></ul><p>OMGs系统以严格的<u>非干预性和观察性</u>方式评估，其输出离线生成，不向临床医生披露，也不用于临床决策。所有OMGs运行均使用为研究评估准备的去标识化病例包，系统不接收任何直接的患者标识符。</p><h1 id="评估设计"><a href="#评估设计" class="headerlink" title="评估设计"></a>评估设计</h1><h2 id="五个临床场景"><a href="#五个临床场景" class="headerlink" title="五个临床场景"></a>五个临床场景</h2><blockquote><p><strong>初步管理</strong>：病人刚确诊卵巢肿瘤,要决定怎么治。最核心的决策通常是:</p><ul><li>直接手术(PDS):先开刀尽量切干净肿瘤,再化疗;</li><li>先化疗再手术(NACT+IDS):肿瘤太大或扩散太广,先用化疗缩小,再做手术。</li></ul><p><strong>组织学驱动的路径</strong>：手术或活检拿到病理组织学类型后,不同类型的卵巢肿瘤走完全不同的治疗路线:</p><ul><li>高级别浆液性癌：化疗+维持治疗(PARP 抑制剂&#x2F;贝伐珠单抗),看 BRCA&#x2F;HRD;</li><li>透明细胞癌：化疗效果差,处理更激进;</li><li>生殖细胞肿瘤：用 BEP 方案,要考虑保生育;</li><li>性索间质肿瘤：可能不需要化疗;</li><li>交界性肿瘤：通常手术就够了,不化疗。</li></ul><p><strong>铂类耐药复发</strong>：病人治疗后癌症复发了,而且对铂类化疗药已经耐药(定义:完成铂类化疗后 6 个月内复发)。铂类是卵巢癌的基石药物,一旦耐药,可选择的方案很少,是临床最棘手的情况。</p><p><strong>铂类敏感复发</strong>：病人复发了,但对铂类仍然敏感(定义:完成铂类化疗后 超过 6 个月才复发)。这种情况可以再用铂类化疗,选择更多、预后更好。</p><p><strong>先验分配</strong>：的意思是分配规则在评估开始前就定死了，防止研究者事后看到结果再调整分类来美化数据。这是评估严谨性的要求，和训练&#x2F;测试划分无关。</p></blockquote><p>所有合格患者被先验分配到五个预定义MDT临床场景之一，场景分配规则在评估前定稿，并在所有中心和阶段统一应用：</p><ol><li><strong>初步管理（Primary management）</strong>：初次诊断后的治疗路径决策</li><li><strong>组织学驱动路径（Histology-driven pathways）</strong>：基于病理类型分流不同治疗路线</li><li><strong>铂类耐药复发（Platinum-resistant relapse）</strong>：铂类化疗后6个月内复发</li><li><strong>铂类敏感复发（Platinum-sensitive relapse）</strong>：铂类化疗后超过6个月复发</li><li><strong>事件驱动重新评估（Event-driven reassessment）</strong>：复杂事件需要重新评估</li></ol><p>这个系统能支持卵巢肿瘤MDT决策，那到底测了哪些类型的决策？如果只测了”刚确诊的病人怎么治，那不知道系统在复发场景下行不行。<u>五个场景就是五个不同类型的临床决策难题，铺满了患者整个病程。</u></p><h2 id="队列与数据来源"><a href="#队列与数据来源" class="headerlink" title="队列与数据来源"></a>队列与数据来源</h2><blockquote><p><strong>回顾性队列</strong>：这些是已经<u>治完的病人的历史病历</u>。系统拿这些旧病历跑一遍,生成建议,然后和已有结论比</p><p><strong>前瞻性队列</strong>：这些是<u>正在入组、正在做 MDT 讨论的病人</u>。系统在病人真实诊疗过程中同步生成建议</p><p>其中队列就是给OMGs的病例库。304例回顾性 + 59例前瞻性，这些患者的真实病历就是OMGs要处理的”考题”。</p></blockquote><p><strong>回顾性队列</strong></p><p>来自FUSCC（复旦大学附属肿瘤医院）253，NJPH（苏北人民医院）30，TFPH（台州市第一人民医院）21。筛选了去标识化的真实世界临床记录。共<u>304</u>例，中位年龄55.0岁（IQR 47.0-62.0），上皮性卵巢癌占82.2%，其余包括交界性肿瘤、生殖细胞肿瘤、性索间质肿瘤等。</p><p><strong>前瞻性队列</strong></p><p>FUSCC（复旦大学附属肿瘤医院）39，FOGH（复旦大学附属妇产科医院）10，SFMIH（上海市第一妇婴保健院）10纳入接受常规MDT讨论的患者。共纳入<u>59</u>例，中位年龄56.0岁（IQR 50.0-65.0），组织学分布与回顾性队列相似。</p><h2 id="四阶段评估框架"><a href="#四阶段评估框架" class="headerlink" title="四阶段评估框架"></a>四阶段评估框架</h2><blockquote><p><strong>单中心</strong>：只用了一家医院（FUSCC）的数据</p><p><strong>多中心</strong>：扩到了三家医院（FUSCC、NJPH、TFPH）</p><p><strong>回顾性</strong>：病人已经治完了，拿历史病历回头测</p><p><strong>基准测试</strong>：和几个”参照物”对比，建立性能基准。这里的参照物是三个单agent基线（CHAIR-R&#x2F;E&#x2F;D），目的是隔离出”多智能体审议”本身带来了多少增益</p><p><strong>re-MDT</strong>：重新组建一个MDT小组，用同样的病例资料重新讨论一遍。这批医生没参与过当时的原始MDT，相当于”盲考”</p><p><strong>前瞻性</strong>：和回顾性相反。病人正在治疗、正在做MDT讨论，系统同步跑，不是回头拿旧病历</p><p><strong>人机协作</strong>：医生先用OMGs辅助写一份建议，再和不借助OMGs时自己写的比</p></blockquote><p>评估分为四个顺序阶段，逐步提高外部有效性和工作流真实性：</p><table><thead><tr><th>阶段</th><th>设计</th><th>目的</th></tr></thead><tbody><tr><td>Phase I</td><td>单中心回顾性基准测试</td><td>量化多智能体审议和信息逐步丰富各自的贡献</td></tr><tr><td>Phase II</td><td>多中心回顾性re-MDT评估</td><td>跨场景、跨机构、跨基座模型的稳定性与人类一致性</td></tr><tr><td>Phase III</td><td>前瞻性多中心评估</td><td>与常规MDT决策的前瞻性一致性比较</td></tr><tr><td>Phase IV</td><td>人机协作评估</td><td>OMGs辅助对医生建议质量的增量提升</td></tr></tbody></table><h1 id="评估结果"><a href="#评估结果" class="headerlink" title="评估结果"></a>评估结果</h1><h2 id="SPEAR评估系统"><a href="#SPEAR评估系统" class="headerlink" title="SPEAR评估系统"></a>SPEAR评估系统</h2><p>本系统开发了一个<span style="color:#FF00FF"><strong>SPEAR评估框架</strong></span>用于系统性评估OMGs的建议质量。并通过这个框架用于展示OMGs和真实MDT的性能比较结果。本框架使用五个维度评分标准进行评估</p><table><thead><tr><th>维度</th><th>含义</th><th>备注</th></tr></thead><tbody><tr><td>Safety(安全)</td><td>建议有没有高危错误</td><td></td></tr><tr><td>Personalization(个性化)</td><td>有没有结合这个病人的具体特征</td><td></td></tr><tr><td>Evidence(证据)</td><td>证据强不强、能不能追溯到来源</td><td></td></tr><tr><td>Actionability(可操作性)</td><td>建议能不能直接落地执行</td><td></td></tr><tr><td>Robustness(稳健性)</td><td>对缺失&#x2F;矛盾信息有没有识别和兜底</td><td></td></tr></tbody></table><p>总体的决策质量计算为五个维度的平均值<br>$$<br>\text{Overall_raw} &#x3D; \frac{S + P + E + A + R}{5}<br>$$</p><p>为将安全性作为硬约束，防止高分数掩盖不安全的建议，采用<u>安全门控总分</u>：<br>$$<br>\text{Overall}&#x3D;<br>\begin{cases}<br>\min(\text{Overall_raw},,S), &amp; S &lt; 3 \<br>\text{Overall_raw}, &amp; S \ge 3<br>\end{cases}<br>$$</p><p>即当安全分低于3时，总分被安全分封顶。</p><h2 id="Phase-I：单中心回顾性基准测试"><a href="#Phase-I：单中心回顾性基准测试" class="headerlink" title="Phase I：单中心回顾性基准测试"></a>Phase I：单中心回顾性基准测试</h2><p><strong>数据来源</strong></p><p>复旦大学附属肿瘤医院的253例连续卵巢肿瘤病例</p><p><strong>测试过程</strong></p><p>与三个仅在信息输入上有所不同的单agent主席基线（仅有主席功能）进行了比较：</p><ul><li><strong>CHAIR-R</strong>：仅使用模式标准化的病例</li><li><strong>CHAIR-E</strong>：在保持相同结构化病例输入的基础上，增加了外部证据检索</li><li><strong>CHAIR-D</strong>：进一步增加了包含完整基础临床报告（包括病理、影像、实验室和基因组报告）的病例特异性证据档案以及检索到的证据和可选的候选临床试验列表</li></ul><p><u>三位具有常规MDT实践的妇科肿瘤专家独立对每个病例进行评分</u>，每个维度使用中位数评分。CHAIR-D和完整OMGs框架在索引决策时间点进行输入匹配，包括相同的病例表示、相同的RAG管道、相同的档案来源和标识符以及相同的试验资格输入，因为两边输入完全一样，所以OMGs比CHAIR-D高的那0.29分，只能归因于”多agent审议+主席综合”这个设计本身，不可能是别的原因造成的。</p><p><strong>关键结果</strong></p><p>OMGs在所有五个SPEAR维度上均取得最高平均分。与最强单agent基线CHAIR-D相比，<u>Evidence和Robustness的差距最大</u>：</p><table><thead><tr><th>维度</th><th>OMGs</th><th>CHAIR-D</th></tr></thead><tbody><tr><td>Safety</td><td>4.36</td><td>4.12</td></tr><tr><td>Personalization</td><td>4.26</td><td>4.11</td></tr><tr><td>Evidence</td><td>4.19</td><td>4.04</td></tr><tr><td>Actionability</td><td>4.18</td><td>3.92</td></tr><tr><td>Robustness</td><td>4.37</td><td>3.72</td></tr></tbody></table><p>高分（&gt;&#x3D;4）比例方面，OMGs达到Safety 92%、Personalization 89%、Evidence 87%、Actionability 86%、Robustness 97%，而CHAIR-R仅为30%&#x2F;42%&#x2F;23%&#x2F;32%&#x2F;20%。</p><p>安全门控总分：<strong>OMGs 4.27 +&#x2F;- 0.31</strong>，CHAIR-D 3.98 +&#x2F;- 0.29，CHAIR-E 3.31 +&#x2F;- 0.46，CHAIR-R 2.84 +&#x2F;- 0.58。</p><p>场景分层分析显示OMGs在每个场景中均保持总体SPEAR分在4.24以上，而CHAIR-R始终低于3.00。OMGs在所有临床场景中Safety均不低于3，其Safety&#x3D;3的实例一致对应预定义的记录约束失败模式：系统没安全分低的时候都是被烂病历拖累的，不是OMGs的锅。</p><blockquote><p>These findings indicate that OMG safety is largely contingent on, rather than independent of, underlying clinical record quality.</p><p>这些发现表明，OMGs的安全性在很大程度上取决于（而非独立于）基础临床记录的质量</p></blockquote><h2 id="Phase-II：多中心回顾性re-MDT评估"><a href="#Phase-II：多中心回顾性re-MDT评估" class="headerlink" title="Phase II：多中心回顾性re-MDT评估"></a>Phase II：多中心回顾性re-MDT评估</h2><blockquote><p><strong>re-MDT</strong>：一批没参与过当时MDT的资深医生,用同样的病例资料重新讨论一遍。相比较于MDT病人真正治疗决策时的讨论，re-MDT聚焦于研究阶段,回顾性地重新讨论。</p><p><strong>避免self-scoring</strong>：参加 MDT 讨论的人,不能又来给 MDT 和 OMGs 的对比打分。可能参与MDT讨论的人会偏向自己的团队，从而给OMGs打低分。或者他可能”刻意公平”反而给 OMGs 打太高来满足补偿心理。</p></blockquote><p>从Phase II起，为避免self-scoring，SPEAR评分由未参与MDT或re-MDT讨论的独立资深专家共识小组执行。</p><p>从FUSCC选取场景均衡的<u>100例子集</u>（每个场景20例）进行跨多个大语言模型的详细基准测试，并在NJPH和TFPH队列上使用相同协议进行外部中心验证。re-MDT评估由专门为重评估目的召集的多学科小组进行，遵循相同的五角色MDT结构，参与的都是具有常规跨机构实践的资深临床医生，且未参与纳入病例的原始MDT讨论。<u>re-MDT结论被视为一个用来对比的标尺，它本身不保证绝对正确。</u></p><p><strong>核心结果</strong></p><p>在FUSCC re-MDT队列中，基于GPT-5.1的OMGs在所有评估的基座模型中总体决策质量最高。在场景均衡队列（n&#x3D;100）中，安全门控总体SPEAR分为<u>OMGs 4.45 +&#x2F;- 0.30</u>，re-MDT 4.53 +&#x2F;- 0.23。五个场景的配对比较在Bonferroni校正后均无统计学显著差异。</p><p>维度层面呈现<u>互补性能谱</u>：OMGs在Evidence和Robustness上得分更高，而re-MDT在Actionability和Personalization上得分更高：</p><table><thead><tr><th>维度</th><th>OMGs (GPT-5.1)</th><th>re-MDT</th></tr></thead><tbody><tr><td>Safety</td><td>4.56</td><td>4.74</td></tr><tr><td>Personalization</td><td>4.26</td><td>4.76</td></tr><tr><td>Evidence</td><td>4.57</td><td>3.92</td></tr><tr><td>Actionability</td><td>4.18</td><td>4.88</td></tr><tr><td>Robustness</td><td>4.70</td><td>4.37</td></tr></tbody></table><blockquote><p>Higher Evidence scores for OMGs reflect both enhanced traceability and more consistent evidence alignment: the system systematically retrieves guideline- and trial-level evidence and matches it to treatment line, biomarker status, and disease stage, which is difficult to perform exhaustively and document explicitly under routine, time-constrained MDT workflows.</p><p>OMG的证据评分更高，这既反映了其可追溯性的增强，也反映了证据一致性更高：该系统能够系统地检索指南和试验层面的证据，并将其与治疗线、生物标志物状态和疾病分期相匹配，而在常规、时间紧迫的多学科诊疗（MDT）工作流程中，很难做到全面检索和明确记录。</p></blockquote><p>其他LLM基座模型的总体SPEAR分范围为2.61到4.14，表现明显更低且变异性更大。跨中心分析（FUSCC、NJPH、TFPH）进一步证实了总体一致性。</p><p><strong>成本与效率</strong></p><p>在相同推理设置下，完整OMGs框架每例中位<u>总token数为134,656</u>（IQR 19,130），中位端到端延迟为155.3秒（IQR 33.1），保持在预定的多学科肿瘤板审议时间范围内。在100例场景均衡的审计病例中，98%未触发Evidence封顶，2%因部分支持的引用被保守封顶为3，无病例被封顶至2或更低。</p><h2 id="Phase-III：前瞻性多中心评估"><a href="#Phase-III：前瞻性多中心评估" class="headerlink" title="Phase III：前瞻性多中心评估"></a>Phase III：前瞻性多中心评估</h2><p>在前瞻性多中心评估中，OMGs的表现接近常规MDT结论。各中心的平均SPEAR差异（OMGs减去MDT）都很小，95%置信区间保持在预定义的等效界值正负0.5分以内。</p><p><strong>59例前瞻性患者</strong>来自三个中心：FUSCC（n&#x3D;39）、FOGH（n&#x3D;10）、SFMIH（n&#x3D;10）。</p><p>按场景拆开看，OMGs和真实MDT的差距不大，但差距的方向因维度而异–某些维度OMGs高，某些维度MDT高：</p><ul><li><strong>Evidence</strong>：OMGs更高，原因是显式来源引用和系统性地检索相关指南、试验和患者级证据</li><li><strong>Actionability和Safety</strong>：在输入模糊或冲突的复杂病例中略有下降</li><li>大多数偏差保持在等效界值内，跨复杂度水平没有渐进性负面偏移</li></ul><p>以FUSCC前瞻性队列（最大队列，n&#x3D;39）为例，OMGs和真实MDT呈现互补格局：OMGs在Evidence上更高（4.72 vs 4.49），而MDT在Actionability和Safety上更高（4.79 vs 4.31，4.87 vs 4.51），但所有差距都在等效界值内。而在SFMIH（n&#x3D;10），OMGs在Safety和Evidence上均达到5.00满分，甚至超过真实MDT–说明在某些中心，系统不仅能追平人类，还能超越。</p><h2 id="Phase-IV：人机协作MDT决策"><a href="#Phase-IV：人机协作MDT决策" class="headerlink" title="Phase IV：人机协作MDT决策"></a>Phase IV：人机协作MDT决策</h2><blockquote><p><strong>亚专科投入</strong>：医院里有没有细分的专科医生。大医院有专门的妇科肿瘤科、影像科亚专科、病理科亚专科，各看各的领域。小医院可能只有一个普外科医生、一个通识影像医生，什么病都看，没有细分。</p><p><strong>正式MDT基础设施</strong>：医院有没有一套常规的多学科讨论机制。大医院有固定的MDT会议时间、固定参与的多科医生、标准化的病例汇报流程。小医院可能根本没有MDT，或者偶尔拉几个人随便聊聊，没有规范流程。</p></blockquote><p>Phase IV评估了OMGs在人机协作工作流中的效果。<u>12名医生参与，包括三甲医院的6名住院医和6名非三甲医院医生。</u>每位医生对相同病例在两种条件下完成建议：仅人工决策 vs OMGs辅助决策。</p><p><strong>核心发现</strong></p><p>在所有组别中，OMGs辅助提高了安全门控总体分，表明患者级端到端决策质量的持续净改善。</p><p>以FUSCC前瞻性队列的住院医为例：</p><ul><li>Scenes 1-3中，所有五个SPEAR领域均有改善（校正后P &lt;&#x3D; 4.8x10^-4），<u>Evidence提升最大</u></li><li>Scene 4中，除Robustness外其余维度均保持显著</li><li>Scene 5中，除Actionability外其余维度均保持显著</li></ul><p>非三甲医院医生呈现类似模式。FOGH和SFMIH的外部队列同样支持该结论。最大的增益出现在<u>Evidence和Robustness</u>，因为这两个维度在亚专科投入或正式MDT基础设施有限时往往最薄弱。</p><blockquote><p>In this context, OMGs appears to function as a <strong>structured cognitive scaffold</strong>, reducing omission risk and promoting explicit reasoning rather than replacing clinical judgment. The ability to externalize MDT-style deliberation into auditable, evidence-linked text may therefore help narrow practice variability and improve the defensibility of longitudinal decisions in resource-constrained settings.</p><p>OMGs在这里起到的是<strong>结构化认知脚手架</strong>的作用：减少遗漏风险、促进显式推理，而非替代临床判断。将MDT式审议外化为可审计的、与证据关联的文本，有助于缩小实践变异性，提高资源受限环境下纵向决策的可辩护性。</p></blockquote><h1 id="讨论与启示"><a href="#讨论与启示" class="headerlink" title="讨论与启示"></a>讨论与启示</h1><h2 id="核心发现"><a href="#核心发现" class="headerlink" title="核心发现"></a>核心发现</h2><p>本研究的两个主要发现：</p><ol><li><p><strong>跨场景的决策质量</strong>：在单中心回顾性基准中，OMGs在所有SPEAR维度上优于最强单agent基线，最大增益在Evidence和Robustness。这反映了一个临床现实：在复杂卵巢肿瘤场景中，限制因素很少是命名一个方案，而是<u>论证策略、识别缺失或冲突变量、定义管理应变更条件的能力</u>。在多中心场景均衡队列中，性能保持稳定，前瞻性比较显示尽管临床复杂度增加，与常规MDT结论的偏差仍然适度。</p></li><li><p><strong>近期临床实用性</strong>：配对人机评估中，医生在OMGs辅助下产出了更高质量的MDT式建议，最显著的改善出现在住院医和非三甲医院医生中。增益在Evidence、Actionability和Robustness维度尤为明显–这些领域在亚专科投入或MDT基础设施有限时往往发展不足。</p></li></ol><h2 id="定位：决策支持而非替代"><a href="#定位：决策支持而非替代" class="headerlink" title="定位：决策支持而非替代"></a>定位：决策支持而非替代</h2><p>OMGs不定位为自主决策者，而是<u>决策支持脚手架</u>。它在综合最关键的节点上让临床假设、不确定性和证据依赖变得显式。每例155秒的处理时间使OMGs能够在预定的MDT会议前预先生成分析，无缝融入常规临床工作流。</p><p>对于MDT资源有限的机构，OMGs提供基于指南的决策支持，保持机构监督的同时实现协作决策。这对缺乏专门MDT基础设施的小型医院尤其有益。此外，系统还发挥着教育作用，记录临床推理、证据来源和重新评估标准，是住院医和初级医生的学习工具。</p><h2 id="局限性"><a href="#局限性" class="headerlink" title="局限性"></a>局限性</h2><blockquote><p>In summary, OMGs demonstrates that a multi-agent system with role-specific constraints and traceable evidence can effectively replicate MDT-level decision-making for ovarian malignancies across both retrospective and prospective multicentre evaluations. The system consistently improves clinicians’ recommendations in collaborative workflows. Instead of positioning LLMs as autonomous decision-makers, this work presents a model in which these systems enhance MDT deliberation by strengthening evidence integration, managing uncertainty, and improving documentation, while clinicians retain final decision-making responsibility.</p><p>总之，OMGs表明具有角色特定约束和可追溯证据的多智能体系统可以在回顾性和前瞻性多中心评估中有效复制卵巢恶性肿瘤的MDT级决策。系统在人机协作工作流中持续改善医生的建议。这项工作提出的模型不是将LLM定位为自主决策者，而是通过加强证据整合、管理不确定性和改善文档来增强MDT审议，同时由医生保留最终决策责任。</p></blockquote><ul><li>所有评估均在中国医疗体系内进行，对不同语言、指南生态系统、处方约束和MDT组织方式的普适性需进一步研究</li><li>评估为离线非干预性，关注决策质量和一致性，而非对患者预后的因果效应</li><li>Phase IV中，改善主要反映增强的结构化文档、证据表达和失败模式暴露，需要未来随机或交叉设计来分离辅助效应与锚定效应</li><li>真实世界EHR的碎片化和缺失仍是残余风险的主要来源，系统性能和安全性与输入质量紧密耦合</li></ul>]]>
    </content>
    <id>https://tysweb.pages.dev/2026/08/02/OMGs%E8%AE%BA%E6%96%87%E8%A7%A3%E8%AF%BB/</id>
    <link href="https://tysweb.pages.dev/2026/08/02/OMGs%E8%AE%BA%E6%96%87%E8%A7%A3%E8%AF%BB/"/>
    <published>2026-08-02T06:58:59.000Z</published>
    <summary>
      <![CDATA[<p><a href="%E5%A6%87%E7%A7%91%E5%A4%9A%E6%99%BA%E8%83%BD%E4%BD%93.pdf">Download PDF</a></p>
<h1 id="背景"><a href="#背景" class="headerlink" ti]]>
    </summary>
    <title>OMGs论文解读</title>
    <updated>2026-09-07T01:31:21.836Z</updated>
  </entry>
  <entry>
    <author>
      <name>ctyyy</name>
    </author>
    <category term="算法题" scheme="https://tysweb.pages.dev/categories/%E7%AE%97%E6%B3%95%E9%A2%98/"/>
    <category term="算法" scheme="https://tysweb.pages.dev/tags/%E7%AE%97%E6%B3%95/"/>
    <category term="Codeforces" scheme="https://tysweb.pages.dev/tags/Codeforces/"/>
    <content>
      <![CDATA[<h1 id="A-Iskander-and-Drawings"><a href="#A-Iskander-and-Drawings" class="headerlink" title="A. Iskander and Drawings"></a>A. Iskander and Drawings</h1><p>贪心，找最长连续子序列</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;bits/stdc++.h&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">solve</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> t;</span><br><span class="line">cin &gt;&gt; t;</span><br><span class="line"><span class="keyword">while</span> (t--) &#123;</span><br><span class="line"><span class="type">int</span> n;</span><br><span class="line">string s;</span><br><span class="line">cin &gt;&gt; n;</span><br><span class="line">cin &gt;&gt; s;</span><br><span class="line"><span class="type">int</span> xian = <span class="number">0</span>;</span><br><span class="line"><span class="type">int</span> maxx = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line"><span class="keyword">if</span> (s[i] == <span class="string">&#x27;*&#x27;</span>) &#123;</span><br><span class="line">maxx = <span class="built_in">max</span>(maxx, (xian + <span class="number">1</span>) / <span class="number">2</span>);</span><br><span class="line">xian = <span class="number">0</span>;</span><br><span class="line">&#125; <span class="keyword">else</span></span><br><span class="line">xian++;</span><br><span class="line">&#125;</span><br><span class="line">maxx = <span class="built_in">max</span>(maxx, (xian + <span class="number">1</span>) / <span class="number">2</span>);</span><br><span class="line">cout &lt;&lt; maxx;</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">signed</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line">cin.<span class="built_in">tie</span>(<span class="literal">nullptr</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">solve</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="B-Nikita-and-Books"><a href="#B-Nikita-and-Books" class="headerlink" title="B. Nikita and Books"></a>B. Nikita and Books</h1><p>贪心</p><p>因为最终只要求是连续递增的，所以我们让序列：<code>1,2,3,4,5……</code>这样递增就好了。存一个storage代表总容量，然后一点一点往外拿。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;bits/stdc++.h&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="keyword">define</span> int long long</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">solve</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> t;</span><br><span class="line">cin &gt;&gt; t;</span><br><span class="line"><span class="keyword">while</span> (t--) &#123;</span><br><span class="line"><span class="type">int</span> n;</span><br><span class="line">cin &gt;&gt; n;</span><br><span class="line"><span class="type">int</span> shu[n];</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line">cin &gt;&gt; shu[i];</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">int</span> ku = <span class="number">0</span>;</span><br><span class="line"><span class="type">int</span> flag = <span class="number">0</span>;</span><br><span class="line">ku += (shu[<span class="number">0</span>] - <span class="number">1</span>);</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt; n; i++) &#123;</span><br><span class="line"><span class="keyword">if</span>(shu[i]&gt;=i<span class="number">+1</span>)&#123;</span><br><span class="line">ku+=(shu[i]-(i<span class="number">+1</span>));</span><br><span class="line">&#125;<span class="keyword">else</span>&#123;</span><br><span class="line"><span class="type">int</span> take=((i<span class="number">+1</span>)-shu[i]);</span><br><span class="line">ku-=take;</span><br><span class="line"><span class="keyword">if</span>(ku&lt;<span class="number">0</span>)&#123;</span><br><span class="line">flag=<span class="number">1</span>;</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">cout&lt;&lt;(flag==<span class="number">1</span>?<span class="string">&quot;NO&quot;</span>:<span class="string">&quot;YES&quot;</span>);</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">signed</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line">cin.<span class="built_in">tie</span>(<span class="literal">nullptr</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">solve</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="C-Stepan-and-Permutation"><a href="#C-Stepan-and-Permutation" class="headerlink" title="C. Stepan and Permutation"></a>C. Stepan and Permutation</h1><p>并查集</p><p>题目给了一个<code>a</code>和一个<code>b</code>，这两个字母代表每个数字可以移动的步长step，我们由测试样例1可以看出来，当<code>ab</code>为23的时候，他们步长是相差1的，也就是可以通过<code>ab</code>互相配合来达到遍历所有区间的目的。</p><p>然后可以感觉出来其实这个区间被分成了关于a的一个集合和关于b的一个集合。如果数组本身是乱序的，那么我们可以通过这两个集合的相互配合来修改顺序吗？</p><p>那么当遍历到某个下标<code>i</code>的时候，如果这个下标<code>i</code>表示的数和这个排序后这个下标<code>i</code>应该表示的数如果在一个集合内，我们就可以通过<code>ab</code>互相配合来修改顺序。</p><p>这些<strong>集合</strong>我们用并查集来维护。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;bits/stdc++.h&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="keyword">define</span> int long long</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> N 200005</span></span><br><span class="line"><span class="type">int</span> p[N];<span class="comment">//p[x]为x的父节点</span></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">find</span><span class="params">(<span class="type">int</span> x)</span> </span>&#123; <span class="comment">//查找结点x的祖宗结点</span></span><br><span class="line"><span class="keyword">if</span> (p[x] != x) p[x] = <span class="built_in">find</span>(p[x]);</span><br><span class="line"><span class="keyword">return</span> p[x];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">solve</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> t;</span><br><span class="line">cin &gt;&gt; t;</span><br><span class="line"><span class="keyword">while</span> (t--) &#123;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> n, a, b;</span><br><span class="line">cin &gt;&gt; n &gt;&gt; a &gt;&gt; b;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt;= n; i ++ ) &#123; <span class="comment">//并查集的初始化</span></span><br><span class="line">p[i] = i;</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">int</span> shu[n], shuc[n];</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line">cin &gt;&gt; shu[i];</span><br><span class="line">shuc[i] = shu[i];</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line"><span class="keyword">if</span> (i + a &lt; n) p[<span class="built_in">find</span>(shu[i])] = <span class="built_in">find</span>(shu[i + a]);</span><br><span class="line"><span class="keyword">if</span> (i + b &lt; n)  p[<span class="built_in">find</span>(shu[i])] = <span class="built_in">find</span>(shu[i + b]);</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">sort</span>(shuc, shuc + n);</span><br><span class="line"><span class="type">int</span> ok = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line"><span class="keyword">if</span> (shu[i] != shuc[i]) &#123;</span><br><span class="line"><span class="keyword">if</span> (<span class="built_in">find</span>(shu[i]) != <span class="built_in">find</span>(shuc[i])) &#123;</span><br><span class="line">ok = <span class="number">0</span>;</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;NO&quot;</span>;</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> (ok) cout &lt;&lt; <span class="string">&quot;YES&quot;</span>;</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">signed</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line">cin.<span class="built_in">tie</span>(<span class="literal">nullptr</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">solve</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="D-Yaroslav-and-Productivity"><a href="#D-Yaroslav-and-Productivity" class="headerlink" title="D. Yaroslav and Productivity"></a>D. Yaroslav and Productivity</h1><p> **第一步：从最简单的情况开始想 **</p><p> 先不考虑帖子，总生产力就是 sum(a)。</p><p> <strong>第二步：加一个帖子，看看发生了什么</strong></p><p> 有一个帖子 <code>b_1</code> &#x3D; 3。它翻转 <code>[1, 3]</code>，那总生产力变成：<br> <code> (-a1 - a2 - a3) + a4 + a5 + ... + an = (-sum[1,3]) + sum[4,n]</code></p><p><strong>第三步：加第二个帖子，观察变化</strong></p><p>再加 b<del>2</del> &#x3D; 5。现在两个帖子，选或不选，有 4 种组合。这时候开始注意到：</p><p>选帖子3: 位置1<del>3翻。选帖子5: 位置1</del>5翻</p><p>位置1<del>3的翻转次数 &#x3D; x</del>3~ + x<del>5</del>，位置4<del>5的翻转次数 &#x3D; x</del>5<del>，位置6</del>n的翻转次数 &#x3D; 0。</p><p>决定翻转次数的是”有多少帖子覆盖了这个位置”，而覆盖规则是：帖子 b<del>j</del> 覆盖所有 ≤ b<del>j</del> 的位置。</p><p><strong>第四步：画一根数轴，标出所有 b<del>j</del></strong></p><p>位置:      1   2   3         4   5          6   7   8            9</p><p>帖子:        b<del>1</del>&#x3D;3            b<del>2</del>&#x3D;5            b<del>3</del>&#x3D;8</p><p>这时你自然会发现：</p><ul><li>位置 1~3：被帖子 1,2,3 覆盖</li><li>位置 4~5：被帖子 2,3 覆盖</li><li>位置 6~8：被帖子 3 覆盖</li><li>位置 9~n：不被任何帖子覆盖</li></ul><p>“覆盖集合”只在 b<del>j</del> 位置发生变化。在 [1,3] 内部，每个位置被覆盖的帖子集合一样。</p><p><strong>第五步：压缩，分段</strong></p><p>既然在一个区间内所有位置改变相同，我们把它打包。</p><p>将帖子排序为 b<del>1</del> &lt; b<del>2</del> &lt; … &lt;b<del>3</del>，数组被分成 m+1 段：</p><p>段1: [1, b<del>1</del>]</p><p>段2: (p<del>1</del>, b<del>2</del>]</p><p>段m: (b<del>m-1</del>, b<del>m</del>]</p><p>段m+1: (b<del>m</del>, n]</p><p>记 <code>seg[i] </code>为第 i 段的和，接下来只需要操作这些段就可以了。（原数组值转变为这些段就是因为激励帖子本身就把问题转换成了对段的求解）</p><p><strong>第六步：设状态方程</strong></p><p><code>dp[i][0]</code>&#x3D; 从段 i 到末尾的最大贡献</p><p><code>dp[i][1]</code> &#x3D; 从段 i 到末尾的最大贡献</p><p><strong>第七步：初始状态及遍历方向</strong></p><p>遍历方向从后往前遍历，因为我们的初始状态是<code>dp[0][0]=seg.back();</code>（因为最后一段的翻转状态只取决于b<del>m</del>，比较好判断）</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;bits/stdc++.h&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="keyword">define</span> int long long</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> N 200005</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">solve</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> t;</span><br><span class="line">cin &gt;&gt; t;</span><br><span class="line"><span class="keyword">while</span> (t--) &#123;</span><br><span class="line"><span class="type">int</span> n, m;</span><br><span class="line">cin &gt;&gt; n &gt;&gt; m;</span><br><span class="line"></span><br><span class="line"><span class="function">vector&lt;<span class="type">int</span>&gt; <span class="title">a</span><span class="params">(n)</span></span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; i++) cin &gt;&gt; a[i];</span><br><span class="line"></span><br><span class="line"><span class="function">vector&lt;<span class="type">int</span>&gt; <span class="title">b</span><span class="params">(m)</span></span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; m; i++) cin &gt;&gt; b[i];</span><br><span class="line"><span class="built_in">sort</span>(b.<span class="built_in">begin</span>(), b.<span class="built_in">end</span>());</span><br><span class="line"></span><br><span class="line"><span class="function">vector&lt;<span class="type">long</span> <span class="type">long</span>&gt; <span class="title">pref</span><span class="params">(n + <span class="number">1</span>, <span class="number">0</span>)</span></span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; i++) pref[i + <span class="number">1</span>] = pref[i] + a[i];</span><br><span class="line"></span><br><span class="line"><span class="comment">// 计算每个段的和，共 m+1 段</span></span><br><span class="line">vector&lt;<span class="type">int</span>&gt; seg;</span><br><span class="line"><span class="type">int</span> prev = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; m; i++) &#123;</span><br><span class="line">seg.<span class="built_in">push_back</span>(pref[b[i]] - pref[prev]);  </span><br><span class="line">prev = b[i];</span><br><span class="line">&#125;</span><br><span class="line">seg.<span class="built_in">push_back</span>(pref[n] - pref[prev]);  </span><br><span class="line"></span><br><span class="line"><span class="comment">// 从右向左 DP</span></span><br><span class="line"><span class="type">int</span> dp[<span class="number">1</span>][<span class="number">2</span>];</span><br><span class="line">dp[<span class="number">0</span>][<span class="number">0</span>]=seg.<span class="built_in">back</span>(); <span class="comment">//不翻转的话就是最后一段的长度</span></span><br><span class="line">dp[<span class="number">0</span>][<span class="number">1</span>]=LLONG_MIN / <span class="number">2</span>;        </span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = (<span class="type">int</span>)seg.<span class="built_in">size</span>() - <span class="number">2</span>; i &gt;= <span class="number">0</span>; i--) &#123;</span><br><span class="line"><span class="type">int</span> ndp0 =  seg[i] + <span class="built_in">max</span>(dp[<span class="number">0</span>][<span class="number">0</span>], dp[<span class="number">0</span>][<span class="number">1</span>]);</span><br><span class="line"><span class="type">int</span> ndp1 = -seg[i] + <span class="built_in">max</span>(dp[<span class="number">0</span>][<span class="number">0</span>], dp[<span class="number">0</span>][<span class="number">1</span>]);</span><br><span class="line">dp[<span class="number">0</span>][<span class="number">0</span>] = ndp0;</span><br><span class="line">dp[<span class="number">0</span>][<span class="number">1</span>] = ndp1;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">cout &lt;&lt; <span class="built_in">max</span>(dp[<span class="number">0</span>][<span class="number">0</span>], dp[<span class="number">0</span>][<span class="number">1</span>]) &lt;&lt; <span class="string">&#x27;\n&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">signed</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line">cin.<span class="built_in">tie</span>(<span class="literal">nullptr</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">solve</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="E-Masha-and-the-Garland"><a href="#E-Masha-and-the-Garland" class="headerlink" title="E. Masha and the Garland"></a>E. Masha and the Garland</h1><p>假设我们翻转子段 [a, b]（把里面的 0 变 1，1 变 0）：</p><pre><code> 位置:  ...  a-1  [a  a+1  ...  b-1  b]  b+1  ... 原值:  ...   x    y   y&#39;   ...  z&#39;   z    w    ... 翻转后: ...   x   !y  !y&#39;   ... !z&#39;  !z   w    ...                ↑                            ↑            边界对(a-1,a)翻转了          边界对(b,b+1)翻转了</code></pre><ul><li>内部对 (a,a+1)…(b-1,b)：两个都翻转，相等关系不变</li><li>边界对 (a-1,a) 和 (b,b+1)：一个翻转一个不翻转，相等关系翻转<ul><li>原来相等 → 变不相等（修复了问题）</li><li>原来不相等 → 变相等（产生了新问题，但我们可以选择不这么干）</li></ul></li></ul><p>  即：<strong>一次操作至多修复 2 个相邻相同对。</strong></p><p>设区间内有 bad 个相邻相同对。</p><ul><li>每次操作修 0 个、1 个或 2 个</li><li>最优策略：每次选两个相邻相同对，翻转它们之间的子段，一次修两个</li><li>最少操作次数 &#x3D; <code>ceil(bad / 2)</code></li></ul><p>用前缀和数组 <code>P[i]</code> 统计从开头到位置 i 有多少个相邻相同对：  <code>P[i] = s[0..i] </code>中相邻相同对的数量</p><p><strong>对于区间<code> [l, r]</code>：</strong></p><p>  区间内 bad 数 &#x3D;<code>P[r-1] - P[l-1]</code>&#x3D; (前r个字符的bad数) - (前l-1个字符的bad数)。  然后判断 <code>bad ≤ 2k。</code></p><p>例1: s &#x3D; “0011”, 查询 [1, 4] 即整个串 0011</p><ul><li>相邻相同对：(0,0) 相等，(0,1) 不等，(1,1) 相等 → bad &#x3D; 2</li><li>最少操作：<code>ceil(2/2)</code> &#x3D; 1 次</li><li>实际：翻转 [2,3] 即 01 → 0011 变成 0101，美丽了</li><li>判定：2 ≤ 2k，k ≥ 1 即可</li></ul><p>  例2: s &#x3D; “0000”, 查询 [1, 4]</p><ul><li>翻转位置 2（即 [1,1]）：0000 → 0100</li><li>翻转位置 4（即 [3,3]）：0100 → 0101</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;bits/stdc++.h&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="keyword">define</span> int long long</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> N 200005</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">solve</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> t;</span><br><span class="line">cin &gt;&gt; t;</span><br><span class="line"><span class="keyword">while</span> (t--) &#123;</span><br><span class="line"><span class="type">int</span> m, n;</span><br><span class="line">cin &gt;&gt; m &gt;&gt; n;</span><br><span class="line">string s;</span><br><span class="line">cin &gt;&gt; s;</span><br><span class="line">vector&lt;<span class="type">int</span>&gt;<span class="built_in">P</span>(m,<span class="number">0</span>);</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt; m; ++i)</span><br><span class="line">P[i] = P[i - <span class="number">1</span>] + (s[i] == s[i - <span class="number">1</span>]);</span><br><span class="line"><span class="keyword">while</span> (n--) &#123;</span><br><span class="line"><span class="type">int</span> l, r, k;</span><br><span class="line">cin &gt;&gt; l &gt;&gt; r &gt;&gt; k;</span><br><span class="line">cout &lt;&lt; (P[r - <span class="number">1</span>] - P[l - <span class="number">1</span>] &lt;= (k *<span class="number">2</span> ) ? <span class="string">&quot;YES\n&quot;</span> : <span class="string">&quot;NO\n&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">signed</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">ios::<span class="built_in">sync_with_stdio</span>(<span class="literal">false</span>);</span><br><span class="line">cin.<span class="built_in">tie</span>(<span class="literal">nullptr</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">solve</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://tysweb.pages.dev/2026/07/22/Codeforces%20Round%201109%20(Div.%203)/</id>
    <link href="https://tysweb.pages.dev/2026/07/22/Codeforces%20Round%201109%20(Div.%203)/"/>
    <published>2026-07-22T10:43:22.000Z</published>
    <summary>
      <![CDATA[<h1 id="A-Iskander-and-Drawings"><a href="#A-Iskander-and-Drawings" class="headerlink" title="A. Iskander and Drawings"></a>A. Iskander and]]>
    </summary>
    <title>Codeforces Round 1109 (Div. 3)</title>
    <updated>2026-09-07T01:31:21.823Z</updated>
  </entry>
  <entry>
    <author>
      <name>ctyyy</name>
    </author>
    <category term="Cooking" scheme="https://tysweb.pages.dev/categories/Cooking/"/>
    <category term="菜谱" scheme="https://tysweb.pages.dev/tags/%E8%8F%9C%E8%B0%B1/"/>
    <content>
      <![CDATA[<h1 id="食材准备"><a href="#食材准备" class="headerlink" title="食材准备"></a>食材准备</h1><p>尖椒 ×2</p><p>火腿</p><p>蒜片</p><h1 id="过程"><a href="#过程" class="headerlink" title="过程"></a>过程</h1><ol><li>热锅凉油下蒜片爆香。然后放切好的尖椒。注意不要炒的太久，稍微有个味道就可以</li><li>放生抽。不要放太多，大约铲子的1&#x2F;3。放太多会让尖椒失去绿色，看着很没有食欲。</li><li>放盐，一勺</li><li>炒一小会，炒出味道后放火腿</li><li>最后放一点点点点点点点的耗油。<strong>刚出锅前十秒放，不然耗油的味道会被炒老</strong></li></ol><p><img src="/2026/07/20/%E5%B0%96%E6%A4%92%E7%82%92%E7%81%AB%E8%85%BF/83f096e7733863e2963713feb44d6fb9.jpg" alt="83f096e7733863e2963713feb44d6fb9"></p>]]>
    </content>
    <id>https://tysweb.pages.dev/2026/07/20/%E5%B0%96%E6%A4%92%E7%82%92%E7%81%AB%E8%85%BF/</id>
    <link href="https://tysweb.pages.dev/2026/07/20/%E5%B0%96%E6%A4%92%E7%82%92%E7%81%AB%E8%85%BF/"/>
    <published>2026-07-20T07:19:16.000Z</published>
    <summary>
      <![CDATA[<h1 id="食材准备"><a href="#食材准备" class="headerlink" title="食材准备"></a>食材准备</h1><p>尖椒 ×2</p>
<p>火腿</p>
<p>蒜片</p>
<h1 id="过程"><a href="#过程" class=]]>
    </summary>
    <title>尖椒炒火腿</title>
    <updated>2026-09-07T01:31:21.929Z</updated>
  </entry>
  <entry>
    <author>
      <name>ctyyy</name>
    </author>
    <category term="Cooking" scheme="https://tysweb.pages.dev/categories/Cooking/"/>
    <category term="菜谱" scheme="https://tysweb.pages.dev/tags/%E8%8F%9C%E8%B0%B1/"/>
    <content>
      <![CDATA[<p>材料准备：</p><ol><li>食材：土豆丝，青椒丝</li><li>爆香：蒜片，小米辣</li><li>调味：生抽，盐，耗油，醋（米醋，陈醋）</li></ol><p>步骤：</p><ol><li>土豆丝切片，然后再切丝。将用<strong>水洗到没有淀粉的颜色</strong>的土豆加醋泡水。</li><li>土豆丝焯水后立马过凉水，凉水倒出后土豆丝备用，焯水是因为土豆直接炒可能炒不熟。</li><li><span style="color:red">热锅凉油</span>放入小米辣，蒜片爆香</li><li>放入土豆丝，放盐一勺（家里的小勺），生抽一勺（家里的铁勺大约 1&#x2F;3），再等上个十几秒就可以放青椒丝了。土豆不宜炒的太过。</li><li>翻炒几下后加入一点点的耗油（一个大拇指盖那么大），然后淋上锅边醋后出锅</li></ol><p><img src="/2026/07/15/%E9%85%B8%E8%BE%A3%E5%9C%9F%E8%B1%86%E4%B8%9D/afc1688419075e76bed087ad9cd1c060.jpg" alt="afc1688419075e76bed087ad9cd1c060"></p>]]>
    </content>
    <id>https://tysweb.pages.dev/2026/07/15/%E9%85%B8%E8%BE%A3%E5%9C%9F%E8%B1%86%E4%B8%9D/</id>
    <link href="https://tysweb.pages.dev/2026/07/15/%E9%85%B8%E8%BE%A3%E5%9C%9F%E8%B1%86%E4%B8%9D/"/>
    <published>2026-07-15T14:17:03.000Z</published>
    <summary>
      <![CDATA[<p>材料准备：</p>
<ol>
<li>食材：土豆丝，青椒丝</li>
<li>爆香：蒜片，小米辣</li>
<li>调味：生抽，盐，耗油，醋（米醋，陈醋）</li>
</ol>
<p>步骤：</p>
<ol>
<li>土豆丝切片，然后再切丝。将用<strong>水洗到没有淀]]>
    </summary>
    <title>酸辣土豆丝</title>
    <updated>2026-09-07T01:31:21.957Z</updated>
  </entry>
  <entry>
    <author>
      <name>ctyyy</name>
    </author>
    <category term="Cooking" scheme="https://tysweb.pages.dev/categories/Cooking/"/>
    <category term="菜谱" scheme="https://tysweb.pages.dev/tags/%E8%8F%9C%E8%B0%B1/"/>
    <content>
      <![CDATA[<p>将以下材料混合至碗 &#x2F; 盆中</p><ul><li>高筋面粉 240g</li><li>耐糖酵母 2g</li><li>白糖 10g</li><li>食用盐 1g</li></ul><h1 id="发面"><a href="#发面" class="headerlink" title="发面"></a>发面</h1><p>用接近<strong>35°的常温水（差不多是手放进去不烫手的温度）<strong>来和面，一边</strong>加水（水要占到整个面重的约60％，否则面会烤干巴）<strong>一边搅拌。搅拌成絮状且碗中无干面粉后放入<span style="color:#00FFFF"><strong>10g的食用油</strong></span>。用手把面揉成团。密醒发酵至原始面团的</strong>1.5~2倍</strong>大小。其中絮状样子如下图所示：</p><p><img src="/2026/07/15/pizza/6f8cd7ee6cfe2a364c2f82dba6cc6b89-1784123831012-2.jpg" alt="6f8cd7ee6cfe2a364c2f82dba6cc6b89"></p><p>注意事项：</p><ol><li><p>发酵时间不可以太长，否则面会过度发酵导致面很酸很软</p></li><li><p>判断醒发好的另一个标志为用手指在中间戳一个洞，面不会回缩</p><p><img src="/2026/07/15/pizza/5d6dabfe338fbbd4344bc22e22e1f07f.jpg" alt="5d6dabfe338fbbd4344bc22e22e1f07f"></p></li></ol><h1 id="做饼胚"><a href="#做饼胚" class="headerlink" title="做饼胚"></a>做饼胚</h1><p>发酵过后的面团拿出来<strong>揉捏拍打</strong>（此步骤目的是为了把面里的气泡挤出去），然后把面团摊平，捏成饼胚形状。<span style="color:#00FFFF"><strong>用叉子扎一些眼</strong></span>。放入模具或者硅油纸中。</p><p><img src="/2026/07/15/pizza/1bf44146f212573fe35f4da9db68e9af.jpg" alt="1bf44146f212573fe35f4da9db68e9af"></p><h1 id="放配料"><a href="#放配料" class="headerlink" title="放配料"></a>放配料</h1><p>首先在饼胚上涂抹一层<strong>番茄酱</strong>，之后撒上一层<strong>芝士碎</strong>（目的是锁住水分）</p><p><img src="/2026/07/15/pizza/image-20260715220332967.png" alt="image-20260715220332967"></p><p>然后放入<strong>青椒丁，玉米粒</strong>等喜爱的蔬菜后，铺上<strong>火腿片</strong>。最后撒上一层<strong>芝士碎</strong>&lt;（目的是拉丝）</p><h1 id="烤"><a href="#烤" class="headerlink" title="烤"></a>烤</h1><p>放入烤箱，<strong>上下管，220℃ ~ 250℃，烤15 ~ 18分钟</strong> 。</p><p><img src="/2026/07/15/pizza/09142f392fba1581c9f8eeb74c618743.jpg" alt="09142f392fba1581c9f8eeb74c618743"></p><h1 id="改进措施"><a href="#改进措施" class="headerlink" title="改进措施"></a>改进措施</h1><h2 id="边上硬，中间软"><a href="#边上硬，中间软" class="headerlink" title="边上硬，中间软"></a>边上硬，中间软</h2><p>在铺的时候，边上铺薄一点。这样卷起来就不会变硬。</p>]]>
    </content>
    <id>https://tysweb.pages.dev/2026/07/15/pizza/</id>
    <link href="https://tysweb.pages.dev/2026/07/15/pizza/"/>
    <published>2026-07-15T13:44:58.000Z</published>
    <summary>
      <![CDATA[<p>将以下材料混合至碗 &#x2F; 盆中</p>
<ul>
<li>高筋面粉 240g</li>
<li>耐糖酵母 2g</li>
<li>白糖 10g</li>
<li>食用盐 1g</li>
</ul>
<h1 id="发面"><a href="#发面" class="h]]>
    </summary>
    <title>pizza</title>
    <updated>2026-09-07T01:31:21.909Z</updated>
  </entry>
  <entry>
    <author>
      <name>ctyyy</name>
    </author>
    <category term="大模型" scheme="https://tysweb.pages.dev/categories/%E5%A4%A7%E6%A8%A1%E5%9E%8B/"/>
    <category term="AI" scheme="https://tysweb.pages.dev/tags/AI/"/>
    <category term="PyTorch" scheme="https://tysweb.pages.dev/tags/PyTorch/"/>
    <content>
      <![CDATA[<h1 id="神经网络初识"><a href="#神经网络初识" class="headerlink" title="神经网络初识"></a>神经网络初识</h1><h2 id="特点"><a href="#特点" class="headerlink" title="特点"></a>特点</h2><p>一、优点</p><ol><li>精度高，性能优于其他的机器学习方法，甚至在某些领域超过了人类</li><li>可以近似任意的非线性函数</li><li>近年来在学界和业界受到了热捧，有大量的框架和库可供调用</li></ol><p>二、缺点</p><ol><li>属于黑箱模型，很难解释模型内部的工作逻辑</li><li>训练耗时久，对算力要求高</li><li>网络结构复杂，需要手动调试大量超参数</li><li>在小规模数据集上效果差，容易出现过拟合问题</li></ol><h2 id="大致演示"><a href="#大致演示" class="headerlink" title="大致演示"></a>大致演示</h2><p>同层不同神经元之间拿不到彼此的数据</p><p><img src="/2026/07/06/PyTorch%20%E8%BF%9B%E9%98%B6%E2%80%94%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/image-20260708213628849.png" alt="image-20260708213628849"></p><p><img src="/2026/07/06/PyTorch%20%E8%BF%9B%E9%98%B6%E2%80%94%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/image-20260708215423816.png" alt="image-20260708215423816"></p><p><a href="https://playground.tensorflow.org/#activation=tanh&batchSize=10&dataset=circle&regDataset=reg-plane&learningRate=0.03&regularizationRate=0&noise=0&networkShape=4,2&seed=0.76260&showTestData=false&discretize=false&percTrainData=50&x=true&y=true&xTimesY=false&xSquared=false&ySquared=false&cosX=false&sinX=false&cosY=false&sinY=false&collectStats=false&problem=classification&initZero=false&hideText=false">神经网络的演示地址</a></p><h1 id="激活函数"><a href="#激活函数" class="headerlink" title="激活函数"></a>激活函数</h1><p>激活函数用于对每层的输出数据进行变换，进而为整个网络注入了非线性因素。此时，神经网络就可以拟合各种曲线。如果没有激活函数,不管你堆多少层全连接,整个网络在数学上仍然只是一个线性变换——因为线性变换的复合还是线性变换,<code>W2(W1x + b1) + b2</code> 永远可以化简成 <code>W&#39;x + b&#39;</code>。所以多层和单层没区别,都只能画直线(或超平面)。</p><p>激活函数的作用就是在每一层输出后做一次非线性”扭折”,把那个可化简的线性链打断。一旦打断,网络就有了表达弯曲、拐折、复杂边界的能力,这就是万能逼近定理说的 ——足够宽的单隐层网络能逼近任意连续函数。</p><h2 id="Sigmoid函数"><a href="#Sigmoid函数" class="headerlink" title="Sigmoid函数"></a>Sigmoid函数</h2><p><img src="/2026/07/06/PyTorch%20%E8%BF%9B%E9%98%B6%E2%80%94%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/image-20260708221936864.png" alt="image-20260708221936864"></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">x = torch.linspace(-<span class="number">10</span>, <span class="number">10</span>, <span class="number">1000</span>, requires_grad=<span class="literal">True</span>)  <span class="comment"># requires_grad=True 需梯度以便求导</span></span><br><span class="line">   fig, ax = plt.subplots(<span class="number">1</span>, <span class="number">2</span>)  <span class="comment"># 1 行 2 列子图</span></span><br><span class="line">   fig.set_size_inches(<span class="number">12</span>, <span class="number">4</span>)</span><br><span class="line">   ax[<span class="number">0</span>].plot(x.data, torch.sigmoid(x).data, <span class="string">&quot;purple&quot;</span>)  <span class="comment"># 左图：sigmoid 函数值</span></span><br><span class="line">   ax[<span class="number">0</span>].set_title(<span class="string">&quot;sigmoid(x)&quot;</span>)</span><br><span class="line">   ax[<span class="number">0</span>].spines[<span class="string">&quot;top&quot;</span>].set_visible(<span class="literal">False</span>)</span><br><span class="line">   ax[<span class="number">0</span>].spines[<span class="string">&quot;right&quot;</span>].set_visible(<span class="literal">False</span>)</span><br><span class="line">   ax[<span class="number">0</span>].spines[<span class="string">&quot;left&quot;</span>].set_position(<span class="string">&quot;zero&quot;</span>)</span><br><span class="line">   ax[<span class="number">0</span>].spines[<span class="string">&quot;bottom&quot;</span>].set_position(<span class="string">&quot;zero&quot;</span>)</span><br><span class="line">   ax[<span class="number">0</span>].axhline(<span class="number">0.5</span>, color=<span class="string">&quot;gray&quot;</span>, alpha=<span class="number">0.7</span>, linewidth=<span class="number">1</span>)</span><br><span class="line">   ax[<span class="number">0</span>].axhline(<span class="number">1</span>, color=<span class="string">&quot;gray&quot;</span>, alpha=<span class="number">0.7</span>, linewidth=<span class="number">1</span>)</span><br><span class="line">   torch.sigmoid(x).<span class="built_in">sum</span>().backward()  <span class="comment"># 反向传播，使 x.grad 为 sigmoid 的导数</span></span><br><span class="line">   ax[<span class="number">1</span>].plot(x.data, x.grad, <span class="string">&quot;purple&quot;</span>)  <span class="comment"># 右图：导数</span></span><br><span class="line">   ax[<span class="number">1</span>].set_title(<span class="string">&quot;sigmoid\&#x27;(x)&quot;</span>)</span><br><span class="line">   ax[<span class="number">1</span>].spines[<span class="string">&quot;top&quot;</span>].set_visible(<span class="literal">False</span>)</span><br><span class="line">   ax[<span class="number">1</span>].spines[<span class="string">&quot;right&quot;</span>].set_visible(<span class="literal">False</span>)</span><br><span class="line">   ax[<span class="number">1</span>].spines[<span class="string">&quot;left&quot;</span>].set_position(<span class="string">&quot;zero&quot;</span>)</span><br><span class="line">   ax[<span class="number">1</span>].spines[<span class="string">&quot;bottom&quot;</span>].set_position(<span class="string">&quot;zero&quot;</span>)</span><br><span class="line">   ax[<span class="number">1</span>].set_ylim(<span class="number">0</span>, <span class="number">0.3</span>)</span><br><span class="line">   plt.show()</span><br></pre></td></tr></table></figure><ol><li><p><code>torch.linspace(start, end, steps)</code> 的作用是在指定区间内<strong>均匀地取若干个点</strong>。</p><p><code>plt.subplots(1, 2)</code>  为创建一张画布和一组子图,两个数字是”行数、列数”:<code>1, 2</code> 就是 1 行 2 列,并排放两个子图。它返回两个东西:</p><ul><li><code>fig</code> – 整张画布(容器)</li><li><code>ax</code> – 子图数组,这里是长度 2 的+数组,<code>ax[0]</code> 是左图,<code>ax[1]</code> 是右图</li></ul><p>所以代码里能写 <code>ax[0].plot(...)</code> 画左边 sigmoid,<code>ax[1].plot(...)</code> 画右边导数。如果写 <code>plt.subplots(2, 2)</code> 就是 2 行 2 列四个子图,<code>ax</code> 变成二维数组,用 <code>ax[0][1]</code> 这种方式访问。</p><ul><li><code>ax[i][j]</code> 就是”第 i 行第 j 列”那个子图,跟二维数组的习惯完全一致:<code>ax[0][0]</code> 左上、<code>ax[0][1]</code> 右上、<code>ax[1][0]</code> 左下、<code>ax[1][1]</code> 右下。</li><li>不过注意 <code>matplotlib</code> 会自动”压扁”只有一行或一列的情况。 <code>subplots(1, 2)</code> 返回的 <code>ax</code> 是<strong>一维</strong>的(长度 2),所以用 <code>ax[0]</code>、<code>ax[1]</code>,写 <code>ax[0][0]</code> 会报错。只有行列都大于 1(比如 <code>subplots(2, 2)</code>)时,<code>ax</code> 才是真正的二维数组,才能用 <code>ax[0][1]</code> 两个下标访问</li></ul></li><li><p><code>fig.set_size_inches(12, 4)</code></p><p>设置整张画布的物理尺寸,宽 12 英寸、高 4 英寸。因为两个子图是并排的,宽给足、高压低,这样左右两个图各自看起来扁长,适合画函数曲线(横轴跨度大、纵轴变化小)。不设的话 <code>matplotlib</code> 用默认尺寸(约 6.4×4.8),两个子图挤在一起会很小。</p><p> <code>ax[0].axhline(0.5, color=&quot;gray&quot;, alpha=0.7, linewidth=1)</code></p><ul><li><code>0.5</code> — 在 y&#x3D;0.5 处画这条线</li><li><code>color=&quot;gray&quot;</code> — 灰色</li><li><code>alpha=0.7</code> — 透明度,0 全透明、1 不透明,0.7 是淡淡的灰</li><li><code>linewidth=1</code> — 线宽 1 磅</li></ul><p>放在 sigmoid 的场景里,这条线是有意义的:sigmoid 在 x&#x3D;0 时正好等于 0.5,而且它是个 S 形从 0 涨到 1 的函数。所以画 y&#x3D;0.5 这条参考线,能帮你一眼看清”曲线在哪儿穿过中点”;代码里紧接着的 <code>axhline(1)</code> 则标出 sigmoid 的上限。</p><p>对应的还有 <code>axvline</code>(vertical),画竖直参考线,用法一样。</p></li></ol><h2 id="Tanh函数"><a href="#Tanh函数" class="headerlink" title="Tanh函数"></a>Tanh函数</h2><p>.<img src="/2026/07/06/PyTorch%20%E8%BF%9B%E9%98%B6%E2%80%94%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/image-20260710213809369.png" alt="image-20260710213809369"></p><h2 id="RULU函数"><a href="#RULU函数" class="headerlink" title="RULU函数"></a>RULU函数</h2><p><img src="/2026/07/06/PyTorch%20%E8%BF%9B%E9%98%B6%E2%80%94%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/image-20260709212520505.png" alt="image-20260709212520505"></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">fig, ax = plt.subplots(<span class="number">1</span>, <span class="number">2</span>)</span><br><span class="line">fig.set_size_inches(<span class="number">12</span>, <span class="number">4</span>)</span><br><span class="line">ax[<span class="number">0</span>].plot(x.data, torch.relu(x).data, <span class="string">&quot;purple&quot;</span>)</span><br><span class="line">ax[<span class="number">0</span>].set_title(<span class="string">&quot;relu(x)&quot;</span>)</span><br><span class="line">ax[<span class="number">0</span>].spines[<span class="string">&quot;top&quot;</span>].set_visible(<span class="literal">False</span>)</span><br><span class="line">ax[<span class="number">0</span>].spines[<span class="string">&quot;right&quot;</span>].set_visible(<span class="literal">False</span>)</span><br><span class="line">ax[<span class="number">0</span>].spines[<span class="string">&quot;left&quot;</span>].set_position(<span class="string">&quot;zero&quot;</span>)</span><br><span class="line">ax[<span class="number">0</span>].spines[<span class="string">&quot;bottom&quot;</span>].set_position(<span class="string">&quot;zero&quot;</span>)</span><br><span class="line">torch.relu(x).<span class="built_in">sum</span>().backward()  <span class="comment"># 反向传播求 ReLU 梯度</span></span><br><span class="line">ax[<span class="number">1</span>].plot(x.data, x.grad, <span class="string">&quot;purple&quot;</span>)</span><br><span class="line">ax[<span class="number">1</span>].set_title(<span class="string">&quot;relu\&#x27;(x)&quot;</span>)</span><br><span class="line">ax[<span class="number">1</span>].spines[<span class="string">&quot;top&quot;</span>].set_visible(<span class="literal">False</span>)</span><br><span class="line">ax[<span class="number">1</span>].spines[<span class="string">&quot;right&quot;</span>].set_visible(<span class="literal">False</span>)</span><br><span class="line">ax[<span class="number">1</span>].spines[<span class="string">&quot;left&quot;</span>].set_position(<span class="string">&quot;zero&quot;</span>)</span><br><span class="line">ax[<span class="number">1</span>].spines[<span class="string">&quot;bottom&quot;</span>].set_position(<span class="string">&quot;zero&quot;</span>)</span><br><span class="line">plt.show()</span><br></pre></td></tr></table></figure><h2 id="Softmax"><a href="#Softmax" class="headerlink" title="Softmax"></a>Softmax</h2><p><img src="/2026/07/06/PyTorch%20%E8%BF%9B%E9%98%B6%E2%80%94%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/image-20260710213432249.png" alt="image-20260710213432249"></p><p>可以直接调用</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#自定义环境 library/python3-be38bd9cb461ab775f44082e06df14e1</span></span><br><span class="line"><span class="comment"># 整体流程：构造一维输入 → softmax 将原始值转为概率分布（和为 1）→ 打印对比</span></span><br><span class="line">x = torch.tensor([<span class="number">2.0</span>, <span class="number">1.0</span>, <span class="number">0.1</span>])</span><br><span class="line">output = torch.softmax(x, dim=<span class="number">0</span>)  <span class="comment"># dim=0：沿第 0 维（唯一维）做 softmax</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;输入：&quot;</span>, x)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;Softmax输出：&quot;</span>, output)  <span class="comment"># 各元素 ∈ (0,1)，总和 = 1</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;输出之和：&quot;</span>, output.<span class="built_in">sum</span>())</span><br><span class="line"><span class="comment"># 二维示例：按行做 softmax（每行和为 1）</span></span><br><span class="line">x2 = torch.tensor([[<span class="number">1.0</span>, <span class="number">2.0</span>, <span class="number">3.0</span>],</span><br><span class="line">                    [<span class="number">1.0</span>, <span class="number">1.0</span>, <span class="number">1.0</span>]])</span><br><span class="line">output2 = torch.softmax(x2, dim=<span class="number">1</span>)  <span class="comment"># dim=1：沿列方向（每行内部）做 softmax</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;二维Softmax输出：\n&quot;</span>, output2)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;每行之和：&quot;</span>, output2.<span class="built_in">sum</span>(dim=<span class="number">1</span>))  <span class="comment"># 均为 1</span></span><br></pre></td></tr></table></figure><ol><li><p>softmax 的公式是对每个元素先取指数、再除以指数之和： <code>output[i] = exp(x[i]) / Σ exp(x[j])</code>。比如 <code>[2.0, 1.0, 0.1]</code> </p><table><thead><tr><th>x</th><th>exp(x)</th><th>除以总和(11.21)</th><th>output</th></tr></thead><tbody><tr><td>2.0</td><td>7.389</td><td>7.389&#x2F;11.21</td><td><strong>0.659</strong></td></tr><tr><td>1.0</td><td>2.718</td><td>2.718&#x2F;11.21</td><td><strong>0.242</strong></td></tr><tr><td>0.1</td><td>1.105</td><td>1.105&#x2F;11.21</td><td><strong>0.099</strong></td></tr></tbody></table><p>可获得以下信息：</p><ul><li>每个输出都落在 (0, 1),可以当”概率”看</li><li>三个加起来 &#x3D; 1,这就是 <code>output.sum()</code> 打印的东西</li></ul><p>还值得注意一点:原始值 <code>2.0</code> 是 <code>1.0</code> 的两倍,但 <code>softmax</code> 之后 <code>0.659</code> 是 <code>0.242</code> 的约 2.7 倍 – 指数运算<strong>放大了差距</strong>,大的值优势更明显。这就是 <code>softmax</code> 用来挑”最可能的类别”的原因。</p></li><li><p>二维<code>dim</code> 的含义</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">x2 = torch.tensor([[<span class="number">1.0</span>, <span class="number">2.0</span>, <span class="number">3.0</span>],</span><br><span class="line">                   [<span class="number">1.0</span>, <span class="number">1.0</span>, <span class="number">1.0</span>]])</span><br><span class="line">output2 = torch.softmax(x2, dim=<span class="number">1</span>)</span><br></pre></td></tr></table></figure><p><code>dim</code> 决定沿哪个轴做归一化,也就是让那个轴方向上的元素之和为 1</p><ul><li><code>dim=1</code> – 沿列方向,在每一行内部做 <code>softmax</code>,所以每行和为 1</li><li><code>dim=0</code> – 沿行方向,在每一列内部做,每列和为 1</li></ul><p><code>dim=1</code>,所以分别看每一行。第一行 <code>[1.0, 2.0, 3.0]</code></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">exp = [<span class="number">2.72</span>, <span class="number">7.39</span>, <span class="number">20.09</span>],总和 <span class="number">30.19</span></span><br><span class="line">output = [<span class="number">0.090</span>, <span class="number">0.245</span>, <span class="number">0.665</span>]   <span class="comment"># 3 最大,拿到 0.665</span></span><br></pre></td></tr></table></figure><p>第二行 <code>[1.0, 1.0, 1.0]</code> 三个相等</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">output = [<span class="number">0.333</span>, <span class="number">0.333</span>, <span class="number">0.333</span>]   <span class="comment"># 完全均分</span></span><br></pre></td></tr></table></figure><p><code>output2.sum(dim=1)</code> 打印的就是每行之和,两个都是 1。这个例子展示了 softmax 的两种行为:值有差距时”放大优势”,值相等时”平均分配”。</p></li></ol><h1 id="参数初始化"><a href="#参数初始化" class="headerlink" title="参数初始化"></a>参数初始化</h1><p>在训练开始前,给 W 和 b 设一个初始值。我们选择哪个激活函数以及如何初始化参数，可以决定优化算法收敛的速度有多快；糟糕的选择可能会导致我们在训练时遇到梯度爆炸或梯度消失</p><h2 id="常数初始化"><a href="#常数初始化" class="headerlink" title="常数初始化"></a>常数初始化</h2><p>所有权重参数初始化为一个常数，即</p><p><img src="/2026/07/06/PyTorch%20%E8%BF%9B%E9%98%B6%E2%80%94%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/image-20260712102632372.png" alt="image-20260712102632372"></p><p>这里 <code>J</code> 为全1矩阵，*<code>k</code> 为初始化的常数。</p><p>注意：将权重初始值设为 0 将无法正确进行学习。严格地说，不能将权重初始值设成一样的值。因为这意味着反向传播时权重全部都会进行相同的更新，被更新为相同的值（对称的值）。这使得神经网络拥有许多不同的权重的意义丧失了。为了防止”权重均一化”（瓦解权重的对称结构），必须随机生成初始值。</p><h2 id="秩初始化"><a href="#秩初始化" class="headerlink" title="秩初始化"></a>秩初始化</h2><p>权重参数初始化为单位矩阵，即</p><p><img src="/2026/07/06/PyTorch%20%E8%BF%9B%E9%98%B6%E2%80%94%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/image-20260712102903862.png" alt="image-20260712102903862"></p><p>这里 <em>I</em> 为单位矩阵，即主对角线上元素为 1，其它元素为 0。秩初始化多用于 <code>RNN</code> 等需要保持恒等映射的场景，全连接层中较少使用。</p><h2 id="正态分布初始化"><a href="#正态分布初始化" class="headerlink" title="正态分布初始化"></a>正态分布初始化</h2><p>权重参数按指定均值<em>μ</em>与标准差<em>σ</em>正态分布初始化。因为不能直接将权重初始化为相同的常数，所以需要对参数进行随机初始化。最常见的随机分布就是<br><strong>正态分布</strong>（也叫 <strong>高斯分布</strong>），记作 <em>X</em> ~ <em>N</em>(<em>μ</em>, <em>σ</em>2)。</p><p>其概率密度函数为：</p><p><img src="/2026/07/06/PyTorch%20%E8%BF%9B%E9%98%B6%E2%80%94%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/image-20260712103447941.png" alt="image-20260712103447941"></p><h2 id="均匀分布初始化"><a href="#均匀分布初始化" class="headerlink" title="均匀分布初始化"></a>均匀分布初始化</h2><p>权重参数在指定区间内均匀分布初始化。均匀分布一般记作 <em>X</em> ~ <em>U</em>(<em>a</em>,<em>b</em>)。</p><p>其概率密度函数为：</p><p><img src="/2026/07/06/PyTorch%20%E8%BF%9B%E9%98%B6%E2%80%94%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/image-20260712103513348.png" alt="image-20260712103513348"></p><h2 id="Xavier-初始化（Glorot-初始化）"><a href="#Xavier-初始化（Glorot-初始化）" class="headerlink" title="Xavier 初始化（Glorot 初始化）"></a>Xavier 初始化（Glorot 初始化）</h2><p>Xavier初始化根据输入和输出的神经元数量调整权重的初始范围，确保每一层的输出方差与输入方差相近。</p><p><img src="/2026/07/06/PyTorch%20%E8%BF%9B%E9%98%B6%E2%80%94%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/image-20260712103604198.png" alt="image-20260712103604198"></p><p>Xavier 初始化参数适用于 Sigmoid 和 Tanh 等激活函数，能有效缓解梯度消失或爆炸问题。其推导假设激活函数在 0 附近近似线性且对称，因此不适用于 ReLU（输出恒非负，破坏了对称性）。</p><h2 id="He-初始化（Kaiming-初始化）"><a href="#He-初始化（Kaiming-初始化）" class="headerlink" title="He 初始化（Kaiming 初始化）"></a>He 初始化（Kaiming 初始化）</h2><p>He初始化根据输入的神经元数量调整权重的初始范围。其方差为 Xavier 的 2 倍，以补偿 ReLU 将一半神经元置零导致的方差减半。</p><p><img src="/2026/07/06/PyTorch%20%E8%BF%9B%E9%98%B6%E2%80%94%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/image-20260712103953768.png" alt="image-20260712103953768"></p><p>He 初始化参数主要适用于 ReLU 及其变体（如 Leaky ReLU）激活函数。</p><h1 id="搭建神经网络"><a href="#搭建神经网络" class="headerlink" title="搭建神经网络"></a>搭建神经网络</h1><p><img src="/2026/07/06/PyTorch%20%E8%BF%9B%E9%98%B6%E2%80%94%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/image-20260712113502295.png" alt="image-20260712113502295"></p><h2 id="自定义模型"><a href="#自定义模型" class="headerlink" title="自定义模型"></a>自定义模型</h2><p>接口：继承 <code>nn.Module</code>，实现 <code>__init__</code> 与 <code>forward(input)</code>。</p><p>功能：所有神经网络模块的基类；自定义模型需继承此类并实现前向传播。</p><p>参数：在 <code>__init__</code> 中定义子模块与参数，在 <code>forward</code> 中接收输入并返回输出。</p><p>在神经网络框架中，由多个层组成的组件称之为 <strong>模块（Module）</strong>。在 PyTorch 中模型和各网络层都是 Module。在定义时需主要实现两个方法：</p><ul><li><code>__init__</code>：定义网络各层的结构，并初始化参数。</li><li><code>forward</code>：根据输入进行前向传播，并返回输出。计算其输出关于输入的梯度，可通过其反向传播函数进行访问（通常自动发生）。forward方法是每次调用的具体实现。</li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">ModelDemo</span>(nn.Module):</span><br><span class="line">    <span class="comment"># todo: 1. 在init魔法方法中，完成初始化：父类成员及神经网络搭建。</span></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="comment"># 1.1初始化父类成员</span></span><br><span class="line">        <span class="built_in">super</span>().__init__()</span><br><span class="line">        <span class="comment"># 1.2 搭建神经网络 → 隐藏层 + 输出层</span></span><br><span class="line">        <span class="comment"># 隐藏层1: 输入特征数 3, 输出特征数 3</span></span><br><span class="line">        <span class="variable language_">self</span>.linear1 = nn.Linear(<span class="number">3</span>, <span class="number">3</span>)</span><br><span class="line">        <span class="comment"># 隐藏层2: 输入特征数 3, 输出特征数 2</span></span><br><span class="line">        <span class="variable language_">self</span>.linear2 = nn.Linear(<span class="number">3</span>, <span class="number">2</span>)</span><br><span class="line">        <span class="comment"># 输出层: 输入特征数 2, 输出特征数 2</span></span><br><span class="line">        <span class="variable language_">self</span>.output = nn.Linear(<span class="number">2</span>, <span class="number">2</span>)</span><br><span class="line">        <span class="comment"># 1.3 对隐藏层进行参数初始化．</span></span><br><span class="line">        <span class="comment"># 隐藏层1</span></span><br><span class="line">        nn.init.xavier_normal_(<span class="variable language_">self</span>.linear1.weight)</span><br><span class="line">        nn.init.zeros_(<span class="variable language_">self</span>.linear1.bias)</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 隐藏层2</span></span><br><span class="line">        nn.init.kaiming_normal_(<span class="variable language_">self</span>.linear2.weight)</span><br><span class="line">        nn.init.zeros_(<span class="variable language_">self</span>.linear2.bias)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># todo: 1.2 前向传播：输入层 -&gt; 隐藏层 -&gt; 输出层 （forward名字不可更改）</span></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">forward</span>(<span class="params">self, x</span>):</span><br><span class="line">        <span class="comment"># 1.1 第一层 隐藏层计算：加权求和 + 激活函数．</span></span><br><span class="line">        <span class="comment"># 分解版写法．</span></span><br><span class="line">        <span class="comment"># x = self.linear1(x)        # 加权求和</span></span><br><span class="line">        <span class="comment"># x = torch.sigmoid(x)       # 激活函数</span></span><br><span class="line">        <span class="comment"># 合并版写法．</span></span><br><span class="line">        x = torch.sigmoid(<span class="variable language_">self</span>.linear1(x))</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 1.2 第2层 隐藏层计算：加权求和 + 激活函数(ReLU)</span></span><br><span class="line">        x = torch.relu(<span class="variable language_">self</span>.linear2(x))</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 1.3 第3层 输出层计算：加权求和 + 激活函数(Softmax)</span></span><br><span class="line">        <span class="comment"># dim=-1, 表示按行计算，一条样本一条样本的处理。</span></span><br><span class="line">        x = torch.softmax(<span class="variable language_">self</span>.output(x), dim=-<span class="number">1</span>)</span><br><span class="line">        <span class="keyword">return</span> x</span><br></pre></td></tr></table></figure><h2 id="模型训练"><a href="#模型训练" class="headerlink" title="模型训练"></a>模型训练</h2><h4 id="查看模型结构和参数数量"><a href="#查看模型结构和参数数量" class="headerlink" title="查看模型结构和参数数量"></a>查看模型结构和参数数量</h4><p>接口：<code>torchsummary.summary(model, input_size, batch_size=None, device=&#39;cuda&#39;)</code></p><p>功能：打印模型结构和各层参数数量。</p><p>参数：</p><ul><li><code>model</code>：待查看的模型</li><li><code>input_size</code>：输入形状（如 <code>(3,)</code> 表示 3 个特征）</li><li><code>batch_size</code>：可选，批大小</li><li><code>device</code>：运行设备</li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">train</span>():</span><br><span class="line">    <span class="comment"># 1. 创建模型对象.</span></span><br><span class="line">    my_model = ModelDemo()</span><br><span class="line">    <span class="comment"># print(f&#x27;my_model: &#123;my_model&#125;&#x27;)</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 2. 创建数据集样本, 随机生成.</span></span><br><span class="line">    data = torch.randn(size=(<span class="number">5</span>, <span class="number">3</span>))</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;data: <span class="subst">&#123;data&#125;</span>&#x27;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;data.shape: <span class="subst">&#123;data.shape&#125;</span>&#x27;</span>)  <span class="comment"># (5行, 3列)</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;data.requires_grad: <span class="subst">&#123;data.requires_grad&#125;</span>&#x27;</span>)  <span class="comment"># False</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 3. 调用神经网络模型 → 进行模型训练.</span></span><br><span class="line">    output = my_model(data)  <span class="comment"># 底层自动调用了 forward()方法, 进行 前向传播.</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;output: <span class="subst">&#123;output&#125;</span>&#x27;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;output.shape: <span class="subst">&#123;output.shape&#125;</span>&#x27;</span>)  <span class="comment"># (5行, 2列)</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;output.requires_grad: <span class="subst">&#123;output.requires_grad&#125;</span>&#x27;</span>)  <span class="comment"># True</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;-&#x27;</span> * <span class="number">30</span>)</span><br><span class="line">    <span class="comment"># 4. 计算 和 查看模型参数.</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;==================== 计算模型参数 ====================&#x27;</span>)</span><br><span class="line">    <span class="comment"># 参1: (神经网络)模型对象, 参2: 输入数据维度(5行3列)</span></span><br><span class="line">    summary(my_model, input_size=(<span class="number">3</span>,))</span><br></pre></td></tr></table></figure><p>对于这里的<code>summary</code>输出值为：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">               (<span class="built_in">type</span>)                Output Shape          Param <span class="comment">#</span></span><br><span class="line">================================================================</span><br><span class="line">            Linear-<span class="number">1</span>                    [-<span class="number">1</span>, <span class="number">3</span>]              <span class="number">12</span></span><br><span class="line">            Linear-<span class="number">2</span>                    [-<span class="number">1</span>, <span class="number">2</span>]               <span class="number">8</span></span><br><span class="line">            Linear-<span class="number">3</span>                    [-<span class="number">1</span>, <span class="number">2</span>]               <span class="number">6</span></span><br><span class="line">================================================================</span><br><span class="line">Total params: <span class="number">26</span></span><br><span class="line">Trainable params: <span class="number">26</span></span><br><span class="line">Non-trainable params: <span class="number">0</span></span><br><span class="line">----------------------------------------------------------------</span><br><span class="line">Input size (MB): <span class="number">0.00</span></span><br><span class="line">Forward/backward <span class="keyword">pass</span> size (MB): <span class="number">0.00</span></span><br><span class="line">Params size (MB): <span class="number">0.00</span></span><br><span class="line">Estimated Total Size (MB): <span class="number">0.00</span></span><br><span class="line">----------------------------------------------------------------</span><br><span class="line"></span><br><span class="line">进程已结束，退出代码为 <span class="number">0</span></span><br></pre></td></tr></table></figure><p>其中：</p><ul><li><code>Layer (type)</code> – 层的类型和序号。模型有三个 <code>nn.Linear</code>(全连接层),按前向传播顺序编号 Linear-1&#x2F;2&#x2F;3,对应代码里的 <code>linear1</code>、<code>linear2</code>、<code>output</code>。</li><li><code>Output Shape</code> – 这一层的输出张量形状。<code>[-1, 2]</code> 里 <code>-1</code> 是 batch 维(动态,不固定),,<code>2</code> 是特征数。</li><li>⭐<code>Param #</code> – 这一层的可训练参数数量(权重 + 偏置)。</li></ul><p>可训练的参数如何计算出来的：<code>nn.Linear(in, out)</code> 的参数 &#x3D; <code>in × out</code>(权重矩阵) + <code>out</code>(偏置)。</p><h5 id="nn-Linear-in-out-的参数运算逻辑"><a href="#nn-Linear-in-out-的参数运算逻辑" class="headerlink" title="nn.Linear(in, out) 的参数运算逻辑"></a><code>nn.Linear(in, out)</code> 的参数运算逻辑</h5><p>拿 <code>Linear-2</code> 举例,它是 <code>nn.Linear(3, 2)</code>,意思是输入 3 个特征,输出 2 个特征。</p><p><strong>权重矩阵:in × out 个</strong></p><p>把输入想象成 3 个数 <code>[x1, x2, x3]</code>,输出是 2 个数 <code>[y1, y2]</code>。<span style="color:#FF00FF">每个输出都是所有输入加权求和算出来的:</span></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">y1 = w11·x1 + w12·x2 + w13·x3 + b1</span><br><span class="line">y2 = w21·x1 + w22·x2 + w23·x3 + b2</span><br></pre></td></tr></table></figure><p>看那些 <code>w</code>,一共需要 <code>2 × 3 = 6</code> 个权重(每个输出 3 个,共 2 个输出)。排成矩阵就是 2 行 3 列,形状 <code>(out, in)</code> &#x3D; <code>(2, 3)</code>,所以权重数量 &#x3D; <code>out × in</code> &#x3D; <code>in × out</code>。</p><p><strong>偏置:out 个</strong></p><p>再看 <code>b1</code>、<code>b2</code>,每个输出配一个偏置,共 2 个 &#x3D; <code>out</code> 个。偏置不乘输入,直接加上去,作用是让直线能上下平移(不固定过原点)。</p><p><strong>加起来</strong></p><p><code>in × out</code>(权重)+ <code>out</code>(偏置)&#x3D; <code>3 × 2 + 2</code> &#x3D; <code>6 + 2</code> &#x3D; <code>8</code> 个参数,正好是表格里 Linear-2 那行的 <code>Param #</code>。</p><p><img src="/2026/07/06/PyTorch%20%E8%BF%9B%E9%98%B6%E2%80%94%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/image-20260715231158202.png" alt="image-20260715231158202"></p><p><strong>总结</strong></p><ol><li><p>5行3列，代表5个数据，每个数据有三个特征。此为输入层</p></li><li><p>隐藏层1<strong>接收</strong>上一层所有输出（第一个数据的三个特征），然后把这三个数据整合起来，整合的方法就是用本层的权重（反向传播可不断更新这个权重）和一个偏置值进行训练整合。<span style="color:#FF00FF">单层可训练参数 &#x3D; 神经元个数 × 上一层的输出数(&#x3D;每个神经元的权重数) + 神经元个数(&#x3D;每个神经元1个偏置)</span></p><ol><li><pre><code class="language-python">样本1: [x1, x2, x3]  ──┐样本2: [x1, x2, x3]  ──┤样本3: [x1, x2, x3]  ──┼──&gt; 同一个神经元(3个权重+1偏置),每条各算一次样本4: [x1, x2, x3]  ──┤样本5: [x1, x2, x3]  ──┘<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">      神经元看到&quot;3 个特征&quot; , 这个 &quot;3 个特征的加权求和&quot; 操作根据 &lt;span style=&quot;color:#FF00FF&quot;&gt;GPU/向量化计算（不是写个 for 循环逐条算,而是把 5 条样本摞成一个矩阵,一次矩阵乘法全算完。）&lt;/span&gt;被**同时重复执行了 5 次**,每次喂一条样本。</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">3. 隐藏层2重复隐藏层1</span><br><span class="line"></span><br><span class="line">4. 输出层重复隐藏层2</span><br><span class="line"></span><br><span class="line">5. 取下一个 batch,重复前向传播、算损失、反向传播、更新参数的过程 , 直到所有数据过了一遍(一个 epoch),再开始下一轮 epoch。</span><br><span class="line"></span><br><span class="line"># 损失函数</span><br><span class="line"></span><br><span class="line">神经网络中，需要以某个指标为线索来寻找最优权重参数；这个指标就是**损失函数（loss function）**。</span><br><span class="line"></span><br><span class="line">## 分类任务</span><br><span class="line"></span><br><span class="line">### 二分类任务损失函数</span><br><span class="line"></span><br><span class="line">![image-20260720193339409](&lt;PyTorch 进阶—人工神经网络/image-20260720193339409.png&gt;)</span><br><span class="line"></span><br><span class="line">### 多分类损失函数自带`Softmax`,其具体公式如下</span><br><span class="line"></span><br><span class="line">![image-20260718210801468](&lt;PyTorch 进阶—人工神经网络/image-20260718210801468.png&gt;)</span><br><span class="line"></span><br><span class="line">**具体执行流程如下**</span><br><span class="line"></span><br><span class="line">![image-20260718211404551](&lt;PyTorch 进阶—人工神经网络/image-20260718211404551.png&gt;)</span><br><span class="line"></span><br><span class="line">## 回归任务</span><br><span class="line"></span><br><span class="line">### MAE</span><br><span class="line"></span><br><span class="line">描述预测值与真实值之间差值绝对值的平均</span><br><span class="line"></span><br><span class="line">![image-20260720194155017](&lt;PyTorch 进阶—人工神经网络/image-20260720194155017.png&gt;)</span><br><span class="line"></span><br><span class="line">### MSE</span><br><span class="line"></span><br><span class="line">![image-20260720203508451](&lt;PyTorch 进阶—人工神经网络/image-20260720203508451.png&gt;)</span><br><span class="line"></span><br><span class="line">### Smooth L1</span><br><span class="line"></span><br><span class="line">可以理解为平滑L1函数：</span><br><span class="line"></span><br><span class="line">![image-20260720204206276](&lt;PyTorch 进阶—人工神经网络/image-20260720204206276.png&gt;)</span><br><span class="line"></span><br><span class="line">当误差较小时（预测值与真实值之差的绝对值小于1），使用L2 Loss，使得损失函数平滑可导。</span><br><span class="line"></span><br><span class="line">当误差较大时时（预测值与真实值之差的绝对值大于1），用L1 Loss降低异常值的影响。</span><br><span class="line"></span><br><span class="line"># 神经网络优化方法</span><br><span class="line"></span><br><span class="line">## 梯度下降算法回顾</span><br><span class="line"></span><br><span class="line">### 基本概念</span><br><span class="line"></span><br><span class="line">梯度下降法（Gradient Descent）是一种用于最小化目标函数的迭代优化算法。核心是沿着目标函数（如损失函数）的负梯度方向逐步调整参数，从而逼近函数的最小值。梯度方向指示了函数增长最快的方向，因此负梯度方向是函数下降最快的方向。所以有：</span><br><span class="line"></span><br><span class="line">![image-20260720211512214](&lt;PyTorch 进阶—人工神经网络/image-20260720211512214.png&gt;)</span><br><span class="line"></span><br><span class="line">其中，`η`是学习率，如果学习率太小，那么每次训练之后得到的效果都太小，增大训练的时间成本。如果，学习率太大，那就有可能直接跳过最优解，进入无限的训练中。解决的方法就是，学习率也需要随着训练的进行而变化。</span><br><span class="line"></span><br><span class="line">**举个具体例子：**</span><br><span class="line"></span><br><span class="line">- 模型只有一个参数 `w`</span><br><span class="line">- 预测公式是 `y_pred = w * x`</span><br><span class="line">- 真实值是 `y = 3`。</span><br><span class="line">- 数据就一个样本：`x = 1, y = 3`。</span><br><span class="line">- 损失用平方误差：`L = (y_pred − y)² = (w − 3)²`</span><br><span class="line"></span><br><span class="line">这个损失函数在 `w = 3` 时最小（损失为 0）。现在从 `w = 0.5` 开始，学习率 `η = 0.1`，看看每一步怎么更新。</span><br><span class="line"></span><br><span class="line">1. 第0步：</span><br><span class="line"></span><br><span class="line">   - 当前 `w = 0.5`，预测 `y_pred = 0.5`</span><br><span class="line">   - 损失 `L = (0.5 − 3)² = 6.25`</span><br><span class="line">   - 对 `w` 求导：`∂L/∂w = 2(w − 3) = 2(0.5 − 3) = −5`</span><br><span class="line"></span><br><span class="line">   梯度是 `−5`，说明“往 w 增大的方向走，损失会下降”。负梯度方向就是 `+5`，所以我们要把 w 往大调。</span><br><span class="line"></span><br><span class="line">   &lt;span style=&quot;color:#DEB887&quot;&gt;Q：既然往`w`增大的方向走，损失会下降。直接不就能得出把`w`增大吗，为什么还要专门说负梯度方向就是 `+5`?&lt;/span&gt;</span><br><span class="line"></span><br><span class="line">   &lt;span style=&quot;color:#DEB887&quot;&gt;A：两者完全等价。但“负梯度方向”这个说法，本质是在描述一条不变的规则：&lt;/span&gt;</span><br><span class="line"></span><br><span class="line">   &gt; &lt;span style=&quot;color:#DEB887&quot;&gt;不管梯度是什么，永远朝着梯度的反方向更新参数。&lt;/span&gt;</span><br><span class="line"></span><br><span class="line">   &lt;span style=&quot;color:#DEB887&quot;&gt;当梯度是 `−5` 时：w ← w − η × (−5) = w + η×5   ← 这就是把 w 往大调&lt;/span&gt;</span><br><span class="line"></span><br><span class="line">   &lt;span style=&quot;color:#DEB887&quot;&gt;当梯度是 `+5` 时：w ← w − η × (+5) = w − η×5   ← 把 w 往小调 &lt;/span&gt;</span><br><span class="line"></span><br><span class="line">   &lt;span style=&quot;color:#DEB887&quot;&gt;公式不需要你每轮手动判断“这次该增大还是减小”，减号会自动处理。“沿负梯度方向更新”可以不用思考地套用到所有情况。&lt;/span&gt;</span><br><span class="line"></span><br><span class="line">   &lt;span style=&quot;color:#DEB887&quot;&gt;更重要的是，真实网络有成千上万个参数，梯度是一个向量，每个参数分量可能有正有负,不可能每个都说“把参数增大”——到底增大哪个、增大多少？但统一用 `参数 ← 参数 − η × 梯度` 这条规则，每个参数会自动按自己梯度的反方向调整。&lt;/span&gt;</span><br><span class="line"></span><br><span class="line">   更新新的值</span><br><span class="line"></span><br></pre></td></tr></table></figure>新 w = 旧 w − 学习率 × 梯度  = 0.5 − 0.1 × (−5)  = 0.5 + 0.5  = 1.0  //现在w更接近真实值w=3了</code></pre></li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">2. 第1步</span><br><span class="line"></span><br><span class="line">   `w = 1.0`，梯度变成 `2(1.0 − 3) = −4`</span><br><span class="line"></span><br><span class="line">   更新：`w = 1.0 − 0.1 × (−4) = 1.4`</span><br><span class="line"></span><br><span class="line">3. 继续下去：</span><br><span class="line"></span><br><span class="line">   | 轮次 | 当前 w       | 梯度 2(w−3)  | 新 w = w − 0.1×梯度 | 损失 |</span><br><span class="line">   | ---- | ------------ | ------------ | ------------------- | ---- |</span><br><span class="line">   | 0    | 0.5          | −5           | 1.0                 | 6.25 |</span><br><span class="line">   | 1    | 1.0          | −4           | 1.4                 | 4.00 |</span><br><span class="line">   | 2    | 1.4          | −3.2         | 1.72                | 2.56 |</span><br><span class="line">   | 3    | 1.72         | −2.56        | 1.976               | 1.64 |</span><br><span class="line">   | ...  | 越来越接近 3 | 越来越接近 0 | 3                   | 0    |</span><br><span class="line"></span><br><span class="line">**在深度学习中，梯度下降的几种方式的根本区别就在于 Batch Size 不同，如下表所示：**</span><br><span class="line"></span><br><span class="line">| 梯度下降方式 | Training Set Size | Batch Size | Number of Batches |</span><br><span class="line">| ------------ | ----------------- | ---------- | ----------------- |</span><br><span class="line">| BGD          | N                 | N          | 1                 |</span><br><span class="line">| SGD          | N                 | 1          | N                 |</span><br><span class="line">| Mini‑Batch   | N                 | B          | \(N/B+1\)         |</span><br><span class="line"></span><br><span class="line">### 训练过程</span><br><span class="line"></span><br><span class="line">在进行模型训练时，有三个基础的概念，从大到小是 Epoch → Iteration → Batch。</span><br><span class="line"></span><br><span class="line">1. Batch size：一次喂多少样本</span><br><span class="line"></span><br><span class="line">   如果把50000 张图一次性塞进模型算梯度则会显存爆掉、太慢。所以每次只取一小批，比如 256 张，算一次损失、做一次反向传播、更新一次权重。这个 256 就是 batch size。</span><br><span class="line"></span><br><span class="line">2. *teration：更新一次权重叫一次迭代</span><br><span class="line"></span><br><span class="line">   拿一个 batch（256 张）跑完前向 + 反向 + 权重更新，就是一次 iteration。所以一次 iteration 处理 256 个样本。</span><br><span class="line"></span><br><span class="line">3. Epoch：把全部数据看一遍叫一轮</span><br><span class="line"></span><br><span class="line">   如果有50000张图片，50000 张图全部过一遍模型，就是一个 epoch。因为每次只处理 256 张，所以要分多批才能看完一遍。</span><br><span class="line"></span><br><span class="line">假设数据集有50000个训练样本，现在选择Batch Size=256对模型进行训练。</span><br><span class="line"></span><br><span class="line">- 每个Epoch要训练的图片数量:50000</span><br><span class="line">- 训练集具有的Batch个数:50000/256+1=196</span><br><span class="line">- 每个Epoch具有的Iteration 个数:196</span><br><span class="line">- 10个Epoch具有的Iteration个数:1960</span><br><span class="line"></span><br><span class="line">## 反向传播算法</span><br><span class="line"></span><br><span class="line">**知识回顾**：`backward()`</span><br><span class="line"></span><br><span class="line">比如损失函数为`loss = ((w ** 2) / 2.0).sum()`，`loss.backward()`</span><br><span class="line"></span><br><span class="line">正向计算时，数值是这么流动的（假设`w`初始值为1.0）：</span><br><span class="line"></span><br><span class="line">```python</span><br><span class="line">w  →  w²  →  w²/2  →  loss</span><br></pre></td></tr></table></figure></li></ol><ul><li>拿 <code>w = 1.0</code> 算 <code>w² = 1.0</code>；</li><li>再算 <code>w²/2 = 0.5</code>；</li><li>最后这个 <code>0.5</code> 就是 loss。</li></ul><p><code>backward()</code> 要做的事情正好反过来：梯度从 loss 往回流，所以图写成：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">loss ← w²/<span class="number">2</span> ← w</span><br></pre></td></tr></table></figure><p>箭头往左表示梯度传播的方向。它把每一步的导数相乘（链式法则），最后得到 loss 对 w 的梯度：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">loss 对 w²/<span class="number">2</span> 的导数 = <span class="number">1</span></span><br><span class="line">w²/<span class="number">2</span> 对 w 的导数   = w</span><br><span class="line">两者相乘           = <span class="number">1</span> × w = w</span><br></pre></td></tr></table></figure><p><span style="color:#DEB887">Q:为什么不直接正向求导，还非要加一个反向传播？</span></p><p><span style="color:#DEB887">A：正向模式求导的话，如果想得到 loss 对每个参数的导数，就得把整个计算图“带导数”完整走一遍，如果每个参数都走一遍，那么100 万参数 &#x3D; 100 万遍，时间复杂度很高。反向的话，从 loss 出发往回走，每过一个节点就把梯度传给它下面的所有参数，走一遍就能同时拿到全部参数的梯度。成本大约是一遍前向 + 一遍反向，和参数个数基本无关。</p><p>所以 <code>w = 1.0</code> 时梯度就是 <code>1.0</code>，这个结果自动存进 <code>w.grad</code>。</p><p><code>w.grad</code>中存的值会在<code>w</code>&#x3D;<code>w</code>-学习率 * 梯度中拿出来。</p><p>更新完，格子里的 1.0 还在（step 不清空）。到下一轮。就要进行梯度清空：<code>.zero_grad()</code>。</p><h2 id="梯度下降优化方法"><a href="#梯度下降优化方法" class="headerlink" title="梯度下降优化方法"></a>梯度下降优化方法</h2><ol><li>碰到平缓区域，梯度值较小，参数优化变慢</li><li>碰到 “鞍点”，梯度为0，参数无法优化</li><li>碰到局部最小值，参数不是最优</li></ol><p>对于这些问题，出现了一些对梯度下降算法的优化方法，例如:Momentum、AdaGrad、RMSprop、Adam等</p><p>![image-20260823193941796](PyTorch 进阶—人工神经网络&#x2F;image-20260823193941796.png)</p><h3 id="优化前置方法：指数加权平均"><a href="#优化前置方法：指数加权平均" class="headerlink" title="优化前置方法：指数加权平均"></a>优化前置方法：指数加权平均</h3><p>我们最常见的算数平均指的是将所有数加起来除以数的个数，每个数的权重是相同的。指数加权平均指的是给每个数赋<br>予不同的权重求得平均数。移动平均数，指的是计算最近邻的N个数来获得平均数。</p><p>指数移动加权平均则是参考各数值，并且各数值的权重都不同，距离越远的数字对平均数计算的贡献就越小(权重较<br>小)，距离越近则对平均数的计算贡献就越大(权重越大)。</p><p>![image-20260823195623158](PyTorch 进阶—人工神经网络&#x2F;image-20260823195623158.png)</p><p>β越小，1-β越大，也就越参考本次的值（Y<del>t</del>）。所以浮动越大。</p><h3 id="梯度下降优化方法—动量算法Momenttum"><a href="#梯度下降优化方法—动量算法Momenttum" class="headerlink" title="梯度下降优化方法—动量算法Momenttum"></a>梯度下降优化方法—动量算法Momenttum</h3><h5 id="算法流程"><a href="#算法流程" class="headerlink" title="算法流程"></a>算法流程</h5><p>（指数加权）梯度计算公式:s<del>t</del>&#x3D;β * s<del>t-1</del> + (1-β) * g<del>t</del></p><p>参数更新公式：w<del>t</del>&#x3D;w<del>t-1</del> - n * s<del>t</del></p><ul><li>s<del>t</del>是当前时刻指数加权平均梯度值。S<del>t-1</del>是历史指数加权平均梯度值</li><li>g<del>t</del>是当前时刻的梯度值</li><li>β是调节权重系数，通常取0.9或0.99</li><li>n是学习率</li><li>w<del>t</del>是当前时刻模型权重参数</li></ul><p><strong><u>举个例子，假设:权重β为0.9</u></strong></p><ol><li>第一次梯度值:s<del>1</del>&#x3D;g<del>1</del>&#x3D;w<del>1</del></li><li>第二次梯度值:s<del>2</del>&#x3D; 0.9 * s<del>1</del> + g<del>2</del> * 0.1</li><li>第三次梯度值:s<del>3</del>&#x3D; 0.9 * s<del>2</del> + g<del>3</del> * 0.1</li><li>第四次梯度值:s<del>4</del>&#x3D;0.9 * s<del>3</del> + g<del>4</del> * 0.1</li></ol><ul><li>w表示初始梯度</li><li>g表示当前轮数计算出的梯度值</li><li>s表示历史梯度移动加权平均值</li></ul><p>梯度下降公式中梯度的计算，就不再是当前时刻 t 的梯度值，而是历史梯度值的指数移动加权平均值。公式修改为</p><ul><li>W<del>t</del> &#x3D; W<del>t-1</del> - η  * S<del>t</del></li><li>W<del>t</del>：当前时刻模型权重参数</li><li>S<del>t</del>:当前时刻指数加权平均梯度值</li><li>η：学习率</li></ul><h5 id="作用"><a href="#作用" class="headerlink" title="作用"></a>作用</h5><ul><li>当处于鞍点位置时，由于当前的梯度为0，参数无法更新。但是Momentum动量梯度下降算法已经在先前积累了一些梯度值，很有可能使得跨过鞍点。</li><li>由于mini-batch普通的梯度下降算法，每次选取少数的样本梯度确定前进方向，可能会出现震荡，使得训练时间变长。Momentum使用移动加权平均，平滑了梯度的变化，使得前进方向更加平缓，有利于加快训练过程。</li></ul><h5 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h5><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">Momenttum</span>():</span><br><span class="line">    <span class="comment"># 1 初始化权重参数</span></span><br><span class="line">    w = torch.tensor([<span class="number">1.0</span>], requires_grad=<span class="literal">True</span>, dtype=torch.float32)</span><br><span class="line">    loss = ((w ** <span class="number">2</span>) / <span class="number">2.0</span>).<span class="built_in">sum</span>()</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 2 实例化优化方法：SGD 指定参数beta=0.9</span></span><br><span class="line">    optimizer = torch.optim.SGD([w], lr=<span class="number">0.01</span>, momentum=<span class="number">0.9</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 3 第1次更新 计算梯度，并对参数进行更新</span></span><br><span class="line">    optimizer.zero_grad()</span><br><span class="line">    loss.backward()</span><br><span class="line">    optimizer.step()</span><br><span class="line"></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;第1次:梯度w.grad: %f, 更新后的权重:%f&#x27;</span> % (w.grad.numpy(), w.detach().numpy()))</span><br><span class="line">    <span class="comment"># 4 第2次更新 计算梯度，并对参数进行更新</span></span><br><span class="line">    <span class="comment"># 使用更新后的参数机选输出结果</span></span><br><span class="line">    loss = ((w ** <span class="number">2</span>) / <span class="number">2.0</span>).<span class="built_in">sum</span>()</span><br><span class="line">    optimizer.zero_grad()</span><br><span class="line">    loss.backward()</span><br><span class="line">    optimizer.step()</span><br><span class="line"></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&#x27;第2次:梯度w.grad: %f, 更新后的权重:%f&#x27;</span> % (w.grad.numpy(), w.detach().numpy()))</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://tysweb.pages.dev/2026/07/06/PyTorch%20%E8%BF%9B%E9%98%B6%E2%80%94%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/</id>
    <link href="https://tysweb.pages.dev/2026/07/06/PyTorch%20%E8%BF%9B%E9%98%B6%E2%80%94%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/"/>
    <published>2026-07-06T14:32:38.000Z</published>
    <summary>
      <![CDATA[<h1 id="神经网络初识"><a href="#神经网络初识" class="headerlink" title="神经网络初识"></a>神经网络初识</h1><h2 id="特点"><a href="#特点" class="headerlink" title="特点"><]]>
    </summary>
    <title>PyTorch 进阶—人工神经网络</title>
    <updated>2026-09-07T01:31:21.877Z</updated>
  </entry>
  <entry>
    <author>
      <name>ctyyy</name>
    </author>
    <category term="算法题" scheme="https://tysweb.pages.dev/categories/%E7%AE%97%E6%B3%95%E9%A2%98/"/>
    <category term="算法" scheme="https://tysweb.pages.dev/tags/%E7%AE%97%E6%B3%95/"/>
    <category term="LeetCode" scheme="https://tysweb.pages.dev/tags/LeetCode/"/>
    <content>
      <![CDATA[<h1 id="基础算法"><a href="#基础算法" class="headerlink" title="基础算法"></a>基础算法</h1><h2 id="位运算"><a href="#位运算" class="headerlink" title="位运算"></a>位运算</h2><h3 id="XOR-性质"><a href="#XOR-性质" class="headerlink" title="XOR 性质"></a>XOR 性质</h3><h4 id="3513-不同-XOR-三元组的数目-I（1663）"><a href="#3513-不同-XOR-三元组的数目-I（1663）" class="headerlink" title="3513. 不同 XOR 三元组的数目 I（1663）"></a><a href="https://leetcode.cn/problems/number-of-unique-xor-triplets-i">3513. 不同 XOR 三元组的数目 I（1663）</a></h4><p>最终答案肯定包含n，因为三个相同的数XOR出来是这个数本身且两个下标相同 时 a XOR a XOR b &#x3D; b，仍然包括在n里面</p><p><strong>那么能XOR出来n外面的值只能通过三个下标不同的数XOR。</strong></p><p>n&#x3D;4时</p><p>XOR出来0 ：1 XOR 2 XOR 3</p><p>XOR出来n+1 ：  2 XOR 3 XOR 4</p><p>XOR出来n+2 ：  1 XOR 3 XOR 4</p><p>XOR出来n+3 ：  1 XOR 2 XOR 4</p><p>n&#x3D;5时，n&#x3D;6时，n&#x3D;6时.最多到7就没了</p><p>n&#x3D;8，9，10，11，12，13，14，15时，最高到15就没了</p><p><img src="/2026/06/24/LeetCode%E5%88%B7%E9%A2%98%E7%AC%94%E8%AE%B0/image-20260727142026967.png" alt="image-20260727142026967"></p><p>这么说…..</p><p><img src="/2026/06/24/LeetCode%E5%88%B7%E9%A2%98%E7%AC%94%E8%AE%B0/image-20260727142134553.png" alt="image-20260727142134553"></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">uniqueXorTriplets</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line"><span class="keyword">if</span>(nums.<span class="built_in">size</span>()==<span class="number">2</span>) <span class="keyword">return</span> <span class="number">2</span>;</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(nums.<span class="built_in">size</span>()==<span class="number">1</span>) <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"><span class="keyword">else</span> &#123;</span><br><span class="line"><span class="type">int</span> a=nums.<span class="built_in">size</span>();</span><br><span class="line"><span class="type">int</span> b=<span class="number">1</span>;</span><br><span class="line"><span class="keyword">while</span>(b&lt;=a) b*=<span class="number">2</span>;</span><br><span class="line"><span class="keyword">return</span> b;</span><br><span class="line">&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/2026/06/24/LeetCode%E5%88%B7%E9%A2%98%E7%AC%94%E8%AE%B0/image-20260727142640488.png" alt="image-20260727142640488"></p><p><img src="/2026/06/24/LeetCode%E5%88%B7%E9%A2%98%E7%AC%94%E8%AE%B0/image-20260727142717545.png" alt="image-20260727142717545"></p><p>后来发现….</p><blockquote><p>对于 n ≥ 3，所有可能的 XOR 值恰好覆盖 [0, 2^k - 1]，其中 2^k 是大于 n 的最小 2 的幂。</p></blockquote><h4 id="3514-不同-XOR-三元组的数目-II（1884）"><a href="#3514-不同-XOR-三元组的数目-II（1884）" class="headerlink" title="3514. 不同 XOR 三元组的数目 II（1884）"></a><a href="https://leetcode.cn/problems/number-of-unique-xor-triplets-ii">3514. 不同 XOR 三元组的数目 II（1884）</a></h4><p>一开始想的dp，后来发现用不到，只需要开个set然后枚举就能过了。这是1884的题？</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">uniqueXorTriplets</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line"> unordered_set&lt;<span class="type">int</span>&gt; nums2;</span><br><span class="line"> unordered_set&lt;<span class="type">int</span>&gt; nums3;</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i&lt;nums.<span class="built_in">size</span>();i++)&#123;</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> j=<span class="number">0</span>;j&lt;nums.<span class="built_in">size</span>();j++)&#123;</span><br><span class="line"> nums<span class="number">2.</span><span class="built_in">insert</span>(nums[i]^nums[j]);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">auto</span> v:nums2)&#123;</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i&lt;nums.<span class="built_in">size</span>();i++)&#123;</span><br><span class="line"> nums<span class="number">3.</span><span class="built_in">insert</span>(nums[i]^v);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">return</span> nums<span class="number">3.</span><span class="built_in">size</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/2026/06/24/LeetCode%E5%88%B7%E9%A2%98%E7%AC%94%E8%AE%B0/image-20260729183615933.png" alt="image-20260729183615933"></p><p>emmmm，能过就是好方法[doge]</p><h4 id="3702-按位异或非零的最长子序列"><a href="#3702-按位异或非零的最长子序列" class="headerlink" title="3702. 按位异或非零的最长子序列"></a><a href="https://leetcode.cn/problems/longest-subsequence-with-non-zero-bitwise-xor/">3702. 按位异或非零的最长子序列</a></h4><p>脑筋急转弯，事实上所有数的XOR值只有三种情况。因为只有<code>A XOR B</code>等于0的时候当且仅当<code>A==B</code></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">longestSubsequence</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//[1,……x,x+1] 1^……^x=x+1 -&gt;0</span></span><br><span class="line">        <span class="comment">//[1,……x,x+1] 1^……^x!=x+1 -&gt;！0</span></span><br><span class="line">        <span class="type">int</span> t = nums.<span class="built_in">size</span>();</span><br><span class="line">        <span class="type">int</span> ans = nums[<span class="number">0</span>];</span><br><span class="line">        <span class="type">int</span> flag = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">if</span> (ans != <span class="number">0</span>)</span><br><span class="line">            flag = <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt; t - <span class="number">1</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (nums[i] != <span class="number">0</span>)</span><br><span class="line">                flag = <span class="number">1</span>;</span><br><span class="line">            ans ^= nums[i];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (t == <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (nums[t - <span class="number">1</span>] == <span class="number">0</span>)</span><br><span class="line">                <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">                <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (ans == nums[t - <span class="number">1</span>])&#123;</span><br><span class="line">                <span class="keyword">if</span>(ans==<span class="number">0</span>&amp;&amp;flag==<span class="number">0</span>) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">                <span class="keyword">return</span> t - <span class="number">1</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">                <span class="keyword">return</span> t;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h2 id="区间合并"><a href="#区间合并" class="headerlink" title="区间合并"></a>区间合并</h2><h3 id="删除被覆盖区间"><a href="#删除被覆盖区间" class="headerlink" title="删除被覆盖区间"></a>删除被覆盖区间</h3><p>我们只要确定了左端点从小到大排序，那么就确保了<strong>接下来的区间的左端点一定位于前面已经遍历过区间左端点的后面</strong>。那么只要本轮的右端点小于前面区间右端点的最大值，就可以把本轮区间消除掉。</p><p>如果左端点相等，我们尽量让右端点值大的排在前面。因为⬆的假设就是由大区间逐渐包裹小区间的算法过程。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">removeCoveredIntervals</span><span class="params">(vector&lt;vector&lt;<span class="type">int</span>&gt;&gt;&amp; intervals)</span> </span>&#123;</span><br><span class="line"><span class="built_in">sort</span>(intervals.<span class="built_in">begin</span>(), intervals.<span class="built_in">end</span>(), [](<span class="type">const</span> vector&lt;<span class="type">int</span>&gt;&amp; a, <span class="type">const</span> vector&lt;<span class="type">int</span>&gt;&amp; b) &#123;</span><br><span class="line"><span class="keyword">if</span> (a[<span class="number">0</span>] != b[<span class="number">0</span>])</span><br><span class="line"><span class="keyword">return</span> a[<span class="number">0</span>] &lt; b[<span class="number">0</span>];</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">return</span> a[<span class="number">1</span>] &gt; b[<span class="number">1</span>];</span><br><span class="line">&#125;);</span><br><span class="line"><span class="type">int</span> maxx = <span class="number">0</span>;</span><br><span class="line"><span class="type">int</span> ans = intervals.<span class="built_in">size</span>();</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">auto</span>&amp; v : intervals) &#123;</span><br><span class="line"><span class="keyword">if</span> (v[<span class="number">1</span>] &lt;= maxx) ans--;</span><br><span class="line">maxx = <span class="built_in">max</span>(v[<span class="number">1</span>], maxx);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> ans;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="字符串"><a href="#字符串" class="headerlink" title="字符串"></a>字符串</h2><h3 id="3517-最小回文排列-I（1357）"><a href="#3517-最小回文排列-I（1357）" class="headerlink" title="3517. 最小回文排列 I（1357）"></a><a href="https://leetcode.cn/problems/smallest-palindromic-rearrangement-i">3517. 最小回文排列 I（1357）</a></h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">string <span class="title">smallestPalindrome</span><span class="params">(string s)</span> </span>&#123;</span><br><span class="line">string beginn = <span class="string">&quot;&quot;</span>;</span><br><span class="line">string endd = <span class="string">&quot;&quot;</span>;</span><br><span class="line"><span class="type">int</span> ant[<span class="number">27</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; s.<span class="built_in">size</span>(); i++) &#123;</span><br><span class="line">ant[s[i] - <span class="string">&#x27;a&#x27;</span>]++;</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">char</span> pre;</span><br><span class="line"><span class="type">int</span> flag = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">26</span>; i &gt;= <span class="number">0</span>; i--) &#123;</span><br><span class="line"><span class="keyword">if</span> (ant[i] % <span class="number">2</span> != <span class="number">0</span>) &#123;</span><br><span class="line">pre = <span class="string">&#x27;a&#x27;</span> + i;</span><br><span class="line">ant[i]--;</span><br><span class="line">flag = <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">while</span> (ant[i] &gt; <span class="number">0</span>) &#123;</span><br><span class="line">ant[i] -= <span class="number">2</span>;</span><br><span class="line"><span class="type">char</span> temp = <span class="string">&#x27;a&#x27;</span> + i;</span><br><span class="line"><span class="comment">//cout&lt;&lt;ant[i]&lt;&lt;endl;</span></span><br><span class="line">beginn += temp;</span><br><span class="line">endd += temp;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">reverse</span>(beginn.<span class="built_in">begin</span>(), beginn.<span class="built_in">end</span>());</span><br><span class="line"><span class="keyword">if</span> (flag)</span><br><span class="line">beginn = beginn + pre + endd;</span><br><span class="line"><span class="keyword">else</span> beginn += endd;</span><br><span class="line"><span class="keyword">return</span> beginn;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>这段代码内存会超限</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ans = temp + ans + temp;</span><br></pre></td></tr></table></figure><p>它在循环里每次都在构造一个新字符串，并且把当前 <code>ans</code> 完整地复制一遍。假设字符串长度是 n，这个循环大概执行 n&#x2F;2 次，每次平均复制 O(n) 个字符，总时间和临时内存开销都是 <strong>O(n²)</strong>。当 n 很大时（比如 10⁵），中间产生的大量临时字符串对象会把内存顶爆，LeetCode 就报 MLE 了。</p><h3 id="3016-输入单词需要的最少按键次数-II（1534）"><a href="#3016-输入单词需要的最少按键次数-II（1534）" class="headerlink" title=" 3016. 输入单词需要的最少按键次数 II（1534）"></a><a href="https://leetcode.cn/problems/minimum-number-of-pushes-to-type-word-ii"> 3016. 输入单词需要的最少按键次数 II（1534）</a></h3><p>能过就是好方法</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">minimumPushes</span><span class="params">(string word)</span> </span>&#123;</span><br><span class="line"><span class="built_in">sort</span>(word.<span class="built_in">begin</span>(), word.<span class="built_in">end</span>());</span><br><span class="line">cout&lt;&lt;word&lt;&lt;endl;</span><br><span class="line"><span class="type">int</span> out[<span class="number">27</span>];</span><br><span class="line"><span class="type">int</span> ant=<span class="number">0</span>;</span><br><span class="line"><span class="type">int</span> ans = <span class="number">1</span>;</span><br><span class="line"><span class="type">int</span> step = <span class="number">1</span>;</span><br><span class="line"><span class="type">int</span> button = <span class="number">2</span>;</span><br><span class="line"><span class="type">char</span> pre = word[<span class="number">0</span>];</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt; word.<span class="built_in">size</span>(); i++,ans++) &#123;</span><br><span class="line"><span class="keyword">if</span> (word[i] != pre) &#123;</span><br><span class="line">pre=word[i];</span><br><span class="line">out[ant++]=ans;</span><br><span class="line">            ans=<span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">    out[ant++]=ans;</span><br><span class="line">ans=<span class="number">0</span>;</span><br><span class="line"><span class="built_in">sort</span>(out,out+ant);</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i=ant<span class="number">-1</span>;i&gt;=<span class="number">0</span>;i--,button++)&#123;</span><br><span class="line"><span class="keyword">if</span>(button==<span class="number">10</span>)&#123;</span><br><span class="line">button=<span class="number">2</span>;</span><br><span class="line">step++;</span><br><span class="line">&#125;</span><br><span class="line">ans+=out[i]*step;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> ans;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="滑动窗口"><a href="#滑动窗口" class="headerlink" title="滑动窗口"></a>滑动窗口</h2><h2 id="模拟"><a href="#模拟" class="headerlink" title="模拟"></a>模拟</h2><h3 id="2958-最多-K-个重复元素的最长子数组（）"><a href="#2958-最多-K-个重复元素的最长子数组（）" class="headerlink" title="2958. 最多 K 个重复元素的最长子数组（）"></a><a href="https://leetcode.cn/problems/length-of-longest-subarray-with-at-most-k-frequency/">2958. 最多 K 个重复元素的最长子数组（）</a></h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">maxSubarrayLength</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums, <span class="type">int</span> k)</span> </span>&#123;</span><br><span class="line">        map&lt;<span class="type">int</span>, <span class="type">int</span>&gt; mp;</span><br><span class="line">        <span class="type">int</span> ans = <span class="number">1</span>;</span><br><span class="line">        <span class="type">int</span> temp = <span class="number">0</span>;</span><br><span class="line">        <span class="type">int</span> j = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; nums.<span class="built_in">size</span>(); i++) &#123;</span><br><span class="line">            mp[nums[i]]++;</span><br><span class="line">            temp++;</span><br><span class="line">            <span class="keyword">while</span> (mp[nums[i]] &gt; k &amp;&amp; j &lt; i) &#123;</span><br><span class="line">                temp--;</span><br><span class="line">                mp[nums[j]]--;</span><br><span class="line">                j++;</span><br><span class="line">            &#125;</span><br><span class="line">            ans = <span class="built_in">max</span>(ans, temp);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> ans;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="3867-数对的最大公约数之和"><a href="#3867-数对的最大公约数之和" class="headerlink" title="3867.数对的最大公约数之和"></a><a href="https://leetcode.cn/problems/sum-of-gcd-of-formed-pairs/description/?envType=daily-question&envId=2026-07-16">3867.数对的最大公约数之和</a></h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">gcd</span><span class="params">(<span class="type">int</span> x,<span class="type">int</span> y)</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> y==<span class="number">0</span>?x:<span class="built_in">gcd</span>(y,x%y);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="type">long</span> <span class="type">long</span> <span class="title">gcdSum</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line">        <span class="function">vector&lt;<span class="type">int</span>&gt; <span class="title">prefixGcd</span><span class="params">(nums.size())</span></span>;</span><br><span class="line">        <span class="type">int</span> mx=<span class="number">0</span>;</span><br><span class="line">        <span class="type">long</span> <span class="type">long</span> sum=<span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i&lt;nums.<span class="built_in">size</span>();i++)&#123;</span><br><span class="line">        mx=<span class="built_in">max</span>(mx,nums[i]);</span><br><span class="line">            prefixGcd[i]=<span class="built_in">gcd</span>(nums[i],mx);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">sort</span>(prefixGcd.<span class="built_in">begin</span>(),prefixGcd.<span class="built_in">end</span>(),[](<span class="type">const</span> <span class="type">int</span> &amp;a,<span class="type">const</span> <span class="type">int</span> &amp;b)&#123;</span><br><span class="line">            <span class="keyword">return</span> a&lt;b;</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>,j=nums.<span class="built_in">size</span>()<span class="number">-1</span>;i&lt;nums.<span class="built_in">size</span>()/<span class="number">2</span>;i++,j--)&#123;</span><br><span class="line">            <span class="keyword">if</span>(i==j) <span class="keyword">break</span>;</span><br><span class="line">            sum+=<span class="built_in">gcd</span>(prefixGcd[i],prefixGcd[j]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> sum;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="1260-二维网格迁移（1337）"><a href="#1260-二维网格迁移（1337）" class="headerlink" title="1260. 二维网格迁移（1337）"></a><a href="https://leetcode.cn/problems/shift-2d-grid">1260. 二维网格迁移（1337）</a></h3><p>把二维网格展开成一串，比如样例一我们可以展开成：</p><p><code>1 2 3 4 5 6 7 8 9</code>，然后每个数的实际位置为<code>i*n+j</code>，移动后的实际位置为<code>(i*n+j+k)%(m*n)</code>。然后再复原回矩阵形式就行了。</p><p>**AC代码  **</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">vector&lt;vector&lt;<span class="type">int</span>&gt;&gt; <span class="built_in">shiftGrid</span>(vector&lt;vector&lt;<span class="type">int</span>&gt;&gt;&amp; grid, <span class="type">int</span> k) &#123;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> m=grid.<span class="built_in">size</span>();</span><br><span class="line"><span class="type">int</span> n=grid[<span class="number">0</span>].<span class="built_in">size</span>();</span><br><span class="line">vector&lt;vector&lt;<span class="type">int</span>&gt;&gt; <span class="built_in">grid2</span>(m,<span class="built_in">vector</span>&lt;<span class="type">int</span>&gt;(n));</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i&lt;m;i++)&#123;</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> j=<span class="number">0</span>;j&lt;n;j++)&#123;</span><br><span class="line"><span class="type">int</span> fact=(i*n+j+k)%(m*n);</span><br><span class="line"><span class="type">int</span> i1=fact/n;</span><br><span class="line"><span class="type">int</span> j1=fact-i1*n;</span><br><span class="line">grid2[i1][j1]=grid[i][j];</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> grid2;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3499-操作后最大活跃区段数-I（1729）"><a href="#3499-操作后最大活跃区段数-I（1729）" class="headerlink" title="3499. 操作后最大活跃区段数 I（1729）"></a><a href="https://leetcode.cn/problems/maximize-active-section-with-trade-i/">3499. 操作后最大活跃区段数 I（1729）</a></h3><p>操作的本质是：</p><ul><li>损失：选中那个 1 块的长度（它变成 0 了）</li><li>收获：选中那个 1 块左右两侧的 0 块长度之和（它们变成 1 了）</li></ul><p><strong>其实选中那个 1 块是不会变化的</strong>，因为首先它变成0，然后又变成1.相当于不加不减。我们收获的得到的就是这个1块周围0的长度之和.<strong>注意题目没有说<code>1</code>的区间必须连续，也就是比如<code>111111101111100</code>的最大活跃区间有12个<code>1</code></strong></p><p>那么我们的算法目的就出现了：原始 1 的个数 + max(左右 0 块长度之和)</p><p><strong>AC代码</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">maxActiveSectionsAfterTrade</span><span class="params">(string s)</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> ones = <span class="built_in">count</span>(s.<span class="built_in">begin</span>(), s.<span class="built_in">end</span>(), <span class="string">&#x27;1&#x27;</span>);</span><br><span class="line">vector&lt;pair&lt;<span class="type">int</span>, <span class="type">int</span>&gt;&gt; blocks;</span><br><span class="line"><span class="type">char</span> com = s[<span class="number">0</span>];</span><br><span class="line"><span class="type">int</span> tem = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt; s.<span class="built_in">size</span>(); i++) &#123;</span><br><span class="line"><span class="keyword">if</span> (com == s[i]) &#123;</span><br><span class="line">tem++;</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            blocks.<span class="built_in">push_back</span>(&#123;com-<span class="string">&#x27;0&#x27;</span>,tem&#125;);</span><br><span class="line">com=s[i];</span><br><span class="line">tem=<span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">  blocks.<span class="built_in">push_back</span>(&#123;s[s.<span class="built_in">size</span>()<span class="number">-1</span>]-<span class="string">&#x27;0&#x27;</span>,tem&#125;);</span><br><span class="line"><span class="type">int</span> maxx=<span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> idx = <span class="number">1</span>; idx + <span class="number">1</span> &lt; blocks.<span class="built_in">size</span>(); idx++) &#123;</span><br><span class="line"><span class="keyword">if</span> (blocks[idx].first == <span class="number">1</span>) &#123;</span><br><span class="line"><span class="type">int</span> gain = blocks[idx - <span class="number">1</span>].second + blocks[idx + <span class="number">1</span>].second;</span><br><span class="line">maxx = <span class="built_in">max</span>(maxx, gain);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> ones+maxx;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/2026/06/24/LeetCode%E5%88%B7%E9%A2%98%E7%AC%94%E8%AE%B0/image-20260721191419331.png" alt="image-20260721191419331"></p><p>emmmmm优化一下</p><ul><li><strong><code>vector&lt;pair&lt;int,int&gt;&gt; blocks</code></strong> — 原来要先建块数组再二次遍历，n&#x3D;10^5 时 push_back 有多次扩容和堆分配。改成单遍扫描，只维护 <code>prev0</code>&#x2F;<code>cur0</code> 两个滑动变量，零动态分配</li><li><strong>合并 <code>count</code> 遍历</strong> — 原来 <code>count(s.begin(), s.end(), &#39;1&#39;)</code> 单独扫一遍，现在在主循环里顺便累加 <code>ones</code></li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">maxActiveSectionsAfterTrade</span><span class="params">(<span class="type">const</span> string&amp; s)</span> </span>&#123;</span><br><span class="line">        <span class="type">int</span> n = s.<span class="built_in">size</span>();</span><br><span class="line">        <span class="type">int</span> ones = <span class="number">0</span>;</span><br><span class="line">        <span class="type">int</span> prev0 = <span class="number">0</span>, cur0 = <span class="number">0</span>;</span><br><span class="line">        <span class="type">int</span> max2 = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (s[i] == <span class="string">&#x27;1&#x27;</span>) &#123;</span><br><span class="line">                ones++;</span><br><span class="line">                <span class="keyword">if</span> (cur0 &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (prev0 &gt; <span class="number">0</span>) max2 = <span class="built_in">max</span>(max2, prev0 + cur0);</span><br><span class="line">                    prev0 = cur0;</span><br><span class="line">                    cur0 = <span class="number">0</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                cur0++;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (cur0 &gt; <span class="number">0</span> &amp;&amp; prev0 &gt; <span class="number">0</span>) max2 = <span class="built_in">max</span>(max2, prev0 + cur0);</span><br><span class="line">        <span class="keyword">return</span> ones + max2;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="3536-两个数字的最大乘积（1199）"><a href="#3536-两个数字的最大乘积（1199）" class="headerlink" title="3536. 两个数字的最大乘积（1199）"></a><a href="https://leetcode.cn/problems/maximum-product-of-two-digits">3536. 两个数字的最大乘积（1199）</a></h3><p>简单模拟</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">maxProduct</span><span class="params">(<span class="type">int</span> n)</span> </span>&#123;</span><br><span class="line">       <span class="type">int</span> ans[<span class="number">10</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">       <span class="keyword">while</span> (n != <span class="number">0</span>) &#123;</span><br><span class="line">           ans[n % <span class="number">10</span>]++;</span><br><span class="line">           n /= <span class="number">10</span>;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="type">int</span> anss = <span class="number">0</span>;</span><br><span class="line">       <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">9</span>; i &gt;= <span class="number">0</span>; i--) &#123;</span><br><span class="line">           <span class="keyword">if</span> (ans[i] &gt;= <span class="number">1</span>) &#123;</span><br><span class="line">               <span class="keyword">if</span> (anss == <span class="number">0</span> &amp;&amp; ans[i] &gt;= <span class="number">2</span>)</span><br><span class="line">                   <span class="keyword">return</span> i * i;</span><br><span class="line">               <span class="keyword">if</span> (anss != <span class="number">0</span>)</span><br><span class="line">                   <span class="keyword">return</span> anss * i;</span><br><span class="line">               <span class="keyword">else</span> &#123;</span><br><span class="line">                   anss = i;</span><br><span class="line">                   ans[i]--;</span><br><span class="line">               &#125;</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> anss;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure><h3 id="628-三个数的最大乘积（1199）"><a href="#628-三个数的最大乘积（1199）" class="headerlink" title="628. 三个数的最大乘积（1199）"></a><a href="https://leetcode.cn/problems/maximum-product-of-three-numbers/description/?envType=daily-question&envId=2026-07-27">628. 三个数的最大乘积（1199）</a></h3><p>简单模拟</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">maximumProduct</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line">        <span class="built_in">sort</span>(nums.<span class="built_in">begin</span>(), nums.<span class="built_in">end</span>());</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">max</span>(nums[nums.<span class="built_in">size</span>() - <span class="number">1</span>] * nums[nums.<span class="built_in">size</span>() - <span class="number">2</span>] *</span><br><span class="line">                       nums[nums.<span class="built_in">size</span>() - <span class="number">3</span>],</span><br><span class="line">                   nums[nums.<span class="built_in">size</span>() - <span class="number">1</span>] * nums[<span class="number">0</span>] * nums[<span class="number">1</span>]);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h3 id="1464-数组中两元素的最大乘积-1121"><a href="#1464-数组中两元素的最大乘积-1121" class="headerlink" title="1464. 数组中两元素的最大乘积(1121)"></a><a href="https://leetcode.cn/problems/maximum-product-of-two-elements-in-an-array">1464. 数组中两元素的最大乘积(1121)</a></h3><p>同上</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">maxProduct</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line"><span class="built_in">sort</span>(nums.<span class="built_in">begin</span>(),nums.<span class="built_in">end</span>());</span><br><span class="line"><span class="keyword">return</span> <span class="built_in">max</span>((nums[nums.<span class="built_in">size</span>()<span class="number">-1</span>]<span class="number">-1</span>)*(nums[nums.<span class="built_in">size</span>()<span class="number">-2</span>]<span class="number">-1</span>),(nums[<span class="number">0</span>]<span class="number">-1</span>)*(nums[<span class="number">1</span>]<span class="number">-1</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3014-输入单词需要的最少按键次数-I（1324）"><a href="#3014-输入单词需要的最少按键次数-I（1324）" class="headerlink" title="3014. 输入单词需要的最少按键次数 I（1324）"></a><a href="https://leetcode.cn/problems/minimum-number-of-pushes-to-type-word-i">3014. 输入单词需要的最少按键次数 I（1324）</a></h3><p>简单模拟</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">minimumPushes</span><span class="params">(string word)</span> </span>&#123;</span><br><span class="line"><span class="built_in">sort</span>(word.<span class="built_in">begin</span>(), word.<span class="built_in">end</span>());</span><br><span class="line"><span class="type">int</span> ans = <span class="number">0</span>, step = <span class="number">1</span>, button = <span class="number">2</span>;</span><br><span class="line"><span class="type">char</span> pre = word[<span class="number">0</span>];</span><br><span class="line">ans += step;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt; word.<span class="built_in">size</span>(); i++) &#123;</span><br><span class="line">word[i] != pre ? (button + <span class="number">1</span> == <span class="number">10</span> ? (button = <span class="number">2</span>, step++) : (button += <span class="number">1</span>)) : <span class="number">1</span>;</span><br><span class="line">ans += step;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> ans;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3731-找出缺失的元素（1217）"><a href="#3731-找出缺失的元素（1217）" class="headerlink" title="3731. 找出缺失的元素（1217）"></a><a href="https://leetcode.cn/problems/find-missing-elements/">3731. 找出缺失的元素（1217）</a></h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">vector&lt;<span class="type">int</span>&gt; <span class="title">findMissingElements</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line">    vector&lt;<span class="type">int</span>&gt; ans;</span><br><span class="line">    <span class="built_in">sort</span>(nums.<span class="built_in">begin</span>(), nums.<span class="built_in">end</span>());</span><br><span class="line">    <span class="type">int</span> temp = nums[<span class="number">0</span>];</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; nums.<span class="built_in">size</span>(); i++,temp++) &#123;</span><br><span class="line">        <span class="keyword">while</span> (nums[i] != temp) &#123;</span><br><span class="line">            ans.<span class="built_in">push_back</span>(temp);</span><br><span class="line">            temp++;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> ans;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3345-最小可整除数位乘积-I（1200）"><a href="#3345-最小可整除数位乘积-I（1200）" class="headerlink" title="3345. 最小可整除数位乘积 I（1200）"></a><a href="https://leetcode.cn/problems/smallest-divisible-digit-product-i/">3345. 最小可整除数位乘积 I（1200）</a></h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">smallestNumber</span><span class="params">(<span class="type">int</span> n, <span class="type">int</span> t)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = n;; i++) &#123;</span><br><span class="line">        <span class="type">int</span> ans = <span class="number">1</span>;</span><br><span class="line">        <span class="type">int</span> temp = i;</span><br><span class="line">        <span class="keyword">while</span> (temp &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            ans *= (temp % <span class="number">10</span>);</span><br><span class="line">            temp /= <span class="number">10</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (ans % t == <span class="number">0</span>)</span><br><span class="line">            <span class="keyword">return</span> i;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="2996-大于等于顺序前缀和的最小缺失整数（1406）"><a href="#2996-大于等于顺序前缀和的最小缺失整数（1406）" class="headerlink" title="2996. 大于等于顺序前缀和的最小缺失整数（1406）"></a><a href="https://leetcode.cn/problems/smallest-missing-integer-greater-than-sequential-prefix-sum/">2996. 大于等于顺序前缀和的最小缺失整数（1406）</a></h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">missingInteger</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line">    <span class="function">unordered_set&lt;<span class="type">int</span>&gt; <span class="title">st</span><span class="params">(nums.begin(), nums.end())</span></span>;</span><br><span class="line">    <span class="type">int</span> sum = nums[<span class="number">0</span>];</span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">1</span>; i &lt; nums.<span class="built_in">size</span>(); ++i)&#123;</span><br><span class="line">        <span class="keyword">if</span>(nums[i] == nums[i<span class="number">-1</span>] + <span class="number">1</span>)&#123;</span><br><span class="line">            sum += nums[i];</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">int</span> x = sum;</span><br><span class="line">    <span class="keyword">while</span>(st.<span class="built_in">count</span>(x))&#123;</span><br><span class="line">        x++;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> x;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3090-每个字符最多出现两次的最长子字符串（1329）"><a href="#3090-每个字符最多出现两次的最长子字符串（1329）" class="headerlink" title="3090. 每个字符最多出现两次的最长子字符串（1329）"></a><a href="https://leetcode.cn/problems/maximum-length-substring-with-two-occurrences/">3090. 每个字符最多出现两次的最长子字符串（1329）</a></h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">maximumLengthSubstring</span><span class="params">(string s)</span> </span>&#123;</span><br><span class="line">      <span class="type">int</span> ans=<span class="number">0</span>;</span><br><span class="line">      <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i&lt;s.<span class="built_in">size</span>();i++)&#123;</span><br><span class="line">          <span class="type">int</span> temp=<span class="number">0</span>;</span><br><span class="line">          <span class="type">int</span> a[<span class="number">27</span>]=&#123;<span class="number">0</span>&#125;;</span><br><span class="line">          <span class="keyword">for</span>(<span class="type">int</span> j=i;j&lt;s.<span class="built_in">size</span>();j++)&#123;</span><br><span class="line">              a[s[j]-<span class="string">&#x27;a&#x27;</span>]++;</span><br><span class="line">              temp++;</span><br><span class="line">              <span class="keyword">if</span>(a[s[j]-<span class="string">&#x27;a&#x27;</span>]&gt;<span class="number">2</span>)&#123;</span><br><span class="line">                  temp--;</span><br><span class="line">                  <span class="keyword">break</span>;</span><br><span class="line">              &#125;</span><br><span class="line">          &#125;</span><br><span class="line">          ans=<span class="built_in">max</span>(ans,temp);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">return</span> ans;</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure><h3 id=""><a href="#" class="headerlink" title=""></a></h3><h3 id="3069-将元素分配到两个数组中-I-1024"><a href="#3069-将元素分配到两个数组中-I-1024" class="headerlink" title="3069. 将元素分配到两个数组中 I(1024)"></a><a href="https://leetcode.cn/problems/distribute-elements-into-two-arrays-i/">3069. 将元素分配到两个数组中 I(1024)</a></h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">vector&lt;<span class="type">int</span>&gt; <span class="title">resultArray</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line">    vector&lt;<span class="type">int</span>&gt; arr1;</span><br><span class="line">    vector&lt;<span class="type">int</span>&gt; arr2;</span><br><span class="line">    vector&lt;<span class="type">int</span>&gt; result;</span><br><span class="line">    arr<span class="number">1.</span><span class="built_in">push_back</span>(nums[<span class="number">0</span>]);</span><br><span class="line">    arr<span class="number">2.</span><span class="built_in">push_back</span>(nums[<span class="number">1</span>]);</span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">2</span>;i&lt;nums.<span class="built_in">size</span>();i++)&#123;</span><br><span class="line">        <span class="keyword">if</span>(arr1[arr<span class="number">1.</span><span class="built_in">size</span>()<span class="number">-1</span>]&gt;arr2[arr<span class="number">2.</span><span class="built_in">size</span>()<span class="number">-1</span>])</span><br><span class="line">            arr<span class="number">1.</span><span class="built_in">push_back</span>(nums[i]);</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">            arr<span class="number">2.</span><span class="built_in">push_back</span>(nums[i]);</span><br><span class="line"></span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i&lt;arr<span class="number">1.</span><span class="built_in">size</span>();i++) result.<span class="built_in">push_back</span>(arr1[i]);</span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i&lt;arr<span class="number">2.</span><span class="built_in">size</span>();i++) result.<span class="built_in">push_back</span>(arr2[i]);</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="3622-判断整除性（1149）"><a href="#3622-判断整除性（1149）" class="headerlink" title="3622. 判断整除性（1149）"></a><a href="https://leetcode.cn/problems/check-divisibility-by-digit-sum-and-product/">3622. 判断整除性（1149）</a></h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">bool</span> <span class="title">checkDivisibility</span><span class="params">(<span class="type">int</span> n)</span> </span>&#123;</span><br><span class="line">       <span class="type">int</span> ji=<span class="number">1</span>,sum=<span class="number">0</span>;</span><br><span class="line">       <span class="type">int</span> temp=n;</span><br><span class="line">       <span class="keyword">while</span>(n)&#123;</span><br><span class="line">           <span class="type">int</span> t=n%<span class="number">10</span>;</span><br><span class="line">           ji*=t;</span><br><span class="line">           sum+=t;</span><br><span class="line">           n/=<span class="number">10</span>;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> ((temp%(ji+sum))==<span class="number">0</span>?<span class="number">1</span>:<span class="number">0</span>);</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure><h3 id="3718-缺失的最小倍数（1228）"><a href="#3718-缺失的最小倍数（1228）" class="headerlink" title="3718. 缺失的最小倍数（1228）"></a><a href="https://leetcode.cn/problems/smallest-missing-multiple-of-k/">3718. 缺失的最小倍数（1228）</a></h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">missingMultiple</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums, <span class="type">int</span> k)</span> </span>&#123;</span><br><span class="line">        <span class="built_in">sort</span>(nums.<span class="built_in">begin</span>(),nums.<span class="built_in">end</span>());</span><br><span class="line">        <span class="type">int</span> max=nums[nums.<span class="built_in">size</span>()<span class="number">-1</span>];</span><br><span class="line">        set&lt;<span class="type">int</span>&gt; se;</span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i&lt;nums.<span class="built_in">size</span>();i++)&#123;</span><br><span class="line">            se.<span class="built_in">insert</span>(nums[i]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">int</span> temp=<span class="number">1</span>;</span><br><span class="line">        <span class="keyword">while</span>(temp*k&lt;=max)&#123;</span><br><span class="line">            <span class="keyword">if</span>(se.<span class="built_in">find</span>(temp*k)==se.<span class="built_in">end</span>()) <span class="keyword">return</span> temp*k;</span><br><span class="line">            temp++;a</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> temp*k;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h1 id="数据结构"><a href="#数据结构" class="headerlink" title="数据结构"></a>数据结构</h1><h2 id="栈和队列"><a href="#栈和队列" class="headerlink" title="栈和队列"></a>栈和队列</h2><h3 id="单调栈"><a href="#单调栈" class="headerlink" title="单调栈"></a>单调栈</h3><h4 id="1081-不同字符的最小子序列（2185）"><a href="#1081-不同字符的最小子序列（2185）" class="headerlink" title="1081. 不同字符的最小子序列（2185）"></a><a href="https://leetcode.cn/problems/smallest-subsequence-of-distinct-characters">1081. 不同字符的最小子序列（2185）</a></h4><p>本题当我们遍历到一个新的位置的时候，思考这个字符串是作为一个新的子串的开头，还是作为一个旧的子串的延续？</p><p><strong>一个新的字串的开头</strong></p><p>需要考虑在这个字符前面的那些字符是否还会出现？</p><ol><li>如果不会出现，则本字符只能作为旧的子串的延续</li></ol><p><strong>一个旧的子串的延续</strong></p><p>需要考虑这个字符可不可以把前面的第<code>i</code>个字符给拱掉？</p><ol><li>当第<code>i</code>个字符的字典序<code>&lt;</code>前一个字符的时候<ul><li>保证字典序最小</li></ul></li><li>当前一个字符在后面还可以出现的时候<ul><li>前面删掉的字符后面还能再加回来，保证所有字符都出现</li></ul></li></ol><p>我们用栈模拟上述流程，每次第<code>i</code>个字符比较的时候，都是与栈顶的元素比较。如果能拱掉，我们就出栈前一个元素，直到找到拱不掉的。最后，我们就把当前遍历到的字符入栈。</p><p>⭐ <strong>为什么一个一个拱就是对的，他还可能跳着拱呢？</strong></p><p>我们举一个例子：</p><p>比如现在的序列：<code>b a c y d x</code>。这里的<code>xy</code>为未知数</p><p>如果跳着替换的话，也就是让<code>x</code>替换<code>y</code>。思考一下什么时候可以替换？</p><ol><li><code>y</code>的字典序比<code>x</code>要大，即<code>y</code>&gt;<code>x</code></li><li><code>d</code>的字典序比<code>x</code>小，即<code>d</code>&lt;<code>x</code></li></ol><p>这样的话会发生跳着拱掉<code>y</code>而保留<code>d</code></p><p>我们看这三者关系：<code>d</code>&lt;<code>x</code>&lt;<code>y</code>，按理说在上轮<code>d</code>就应该把<code>y</code>替换掉了。但是没有替换，因为什么？因为<code>y</code>是剩下的主串中最后一个了。如果<code>y</code>可以拱掉<code>d</code>，那么早在上一轮<code>x</code>就把<code>d</code>拱掉了。故在已经确定栈顶元素不能拱掉之后，除栈顶外的栈里的元素一定是不可拱掉的。这也是贪心的策略</p><p><strong>在我们遍历<code>cbacdcbc</code>的时候</strong></p><table><thead><tr><th>轮数（<code>i</code>）</th><th>遍历到  (<code>s[i]</code>)</th><th>状态</th><th>字符串</th></tr></thead><tbody><tr><td>0</td><td><code>c</code></td><td>进入子串</td><td>[c]</td></tr><tr><td>1</td><td><code>b</code></td><td><code>c</code> &gt; <code>b</code>，栈顶更大，满足条件1，并且<code>c</code>在主串的后面还会出现。所以<code>b</code>可以拱掉<code>c</code>，把<code>c</code>给<code>pop</code>掉</td><td>[b]</td></tr><tr><td>2</td><td><code>a</code></td><td><code>b</code> &lt; <code>a</code>，栈顶更大，满足条件1，并且<code>b</code>在主串的后面还会出现。所以<code>a</code>可以拱掉<code>b</code>，把<code>b</code>给<code>pop</code>掉</td><td>[a]</td></tr><tr><td>3</td><td><code>c</code></td><td><code>a</code> &lt; <code>c</code> ，栈顶更小，不能拱。把<code>c</code>入栈</td><td>[a, c]</td></tr><tr><td>4</td><td><code>d</code></td><td><code>c</code> &lt; <code>d</code> ，栈顶更小，不能拱。把<code>d</code>入栈</td><td>[a, c,d]</td></tr><tr><td>5</td><td><code>c</code></td><td><code>c</code>在栈中，跳过</td><td>[a,c,d]</td></tr><tr><td>6</td><td><code>b</code></td><td><code>d </code>&lt; <code>b</code>，栈顶更大，满足条件1，但是<code>d</code>在主串的后面不会出现了。所以不能拱。把<code>b</code>入栈</td><td>[a,c,d,b]</td></tr><tr><td>7</td><td><code>c</code></td><td><code>c</code>在栈中，跳过</td><td>[a,c,d,b]</td></tr></tbody></table><p><strong>AC代码</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">string <span class="title">smallestSubsequence</span><span class="params">(string s)</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> ABC[<span class="number">200</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line"><span class="type">int</span> flag[<span class="number">200</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">stack&lt;<span class="type">char</span>&gt; st;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; s.<span class="built_in">size</span>(); i++) &#123;</span><br><span class="line">ABC[s[i]]++;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; s.<span class="built_in">size</span>(); i++) &#123;</span><br><span class="line">ABC[s[i]]--;</span><br><span class="line"><span class="keyword">if</span> (flag[s[i]]) <span class="keyword">continue</span>;</span><br><span class="line"><span class="keyword">while</span> (!st.<span class="built_in">empty</span>() &amp;&amp; st.<span class="built_in">top</span>() &gt; s[i] &amp;&amp; ABC[st.<span class="built_in">top</span>()]) &#123;</span><br><span class="line">flag[st.<span class="built_in">top</span>()] = <span class="number">0</span>;</span><br><span class="line">st.<span class="built_in">pop</span>();</span><br><span class="line">&#125;</span><br><span class="line">st.<span class="built_in">push</span>(s[i]);</span><br><span class="line">flag[s[i]] = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line">string ans;</span><br><span class="line"><span class="keyword">while</span> (!st.<span class="built_in">empty</span>()) &#123;</span><br><span class="line">ans += st.<span class="built_in">top</span>();</span><br><span class="line">st.<span class="built_in">pop</span>();</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">reverse</span>(ans.<span class="built_in">begin</span>(), ans.<span class="built_in">end</span>());</span><br><span class="line"><span class="keyword">return</span> ans;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="数学知识"><a href="#数学知识" class="headerlink" title="数学知识"></a>数学知识</h1><h2 id="约数"><a href="#约数" class="headerlink" title="约数"></a>约数</h2><h3 id="辗转相除法"><a href="#辗转相除法" class="headerlink" title="辗转相除法"></a>辗转相除法</h3><h4 id="奇数和与偶数和的最大公约数"><a href="#奇数和与偶数和的最大公约数" class="headerlink" title="奇数和与偶数和的最大公约数"></a><a href="https://leetcode.cn/problems/gcd-of-odd-and-even-sums/solutions/3993675/qi-shu-he-yu-ou-shu-he-de-zui-da-gong-yu-f3os/?envType=daily-question&envId=2026-07-15">奇数和与偶数和的最大公约数</a></h4><p>辗转相除法的核心原理是：两个整数的最大公约数等于<strong>第二个数</strong>与<strong>第一个数除以第二个数所得余数</strong>的最大公约数，其数学表达式如下：<br>$$<br>\gcd(a,b) &#x3D; \gcd(b,; a \bmod b)<br>$$<br><code>sumOdd</code>和<code>sumEven</code>用等差数列求和</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">gcd</span><span class="params">(<span class="type">int</span> x, <span class="type">int</span> y)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> y == <span class="number">0</span> ? x : <span class="built_in">gcd</span>(y, x % y);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">gcdOfOddEvenSums</span><span class="params">(<span class="type">int</span> n)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">gcd</span>(n * n, n * (n + <span class="number">1</span>));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h2 id="博弈论"><a href="#博弈论" class="headerlink" title="博弈论"></a>博弈论</h2><h3 id="1927-求和游戏（2005）"><a href="#1927-求和游戏（2005）" class="headerlink" title="1927. 求和游戏（2005）"></a><a href="https://leetcode.cn/problems/sum-game/">1927. 求和游戏（2005）</a></h3><p>来源：<a href="https://codeforces.com/contest/1215/problem/D">D. Ticket Game（1700）</a></p><p>我还以为一点之前能做出来的，哭。</p><p><img src="/2026/06/24/LeetCode%E5%88%B7%E9%A2%98%E7%AC%94%E8%AE%B0/image-20260823021305405.png" alt="image-20260823021305405"></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">bool</span> <span class="title">sumGame</span><span class="params">(string num)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (num.<span class="built_in">find</span>(<span class="string">&#x27;?&#x27;</span>) == <span class="number">-1</span>) &#123;</span><br><span class="line">            <span class="type">int</span> ans1 = <span class="number">0</span>, ans2 = <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>, j = num.<span class="built_in">size</span>() / <span class="number">2</span>; i &lt; num.<span class="built_in">size</span>() / <span class="number">2</span>; i++, j++) &#123;</span><br><span class="line">                ans1 += (num[i] - <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line">                ans2 += (num[j] - <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> ans1 != ans2;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="type">int</span> ans1 = <span class="number">0</span>, ans2 = <span class="number">0</span>;</span><br><span class="line">            <span class="type">int</span> sum1 = <span class="number">0</span>, sum2 = <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>, j = num.<span class="built_in">size</span>() / <span class="number">2</span>; i &lt; num.<span class="built_in">size</span>() / <span class="number">2</span>; i++, j++) &#123;</span><br><span class="line">                ans1 += (num[i] == <span class="string">&#x27;?&#x27;</span>);</span><br><span class="line">                ans2 += (num[j] == <span class="string">&#x27;?&#x27;</span>);</span><br><span class="line">                <span class="keyword">if</span> (num[i] != <span class="string">&#x27;?&#x27;</span>)</span><br><span class="line">                    sum1 += (num[i] - <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line">                <span class="keyword">if</span> (num[j] != <span class="string">&#x27;?&#x27;</span>)</span><br><span class="line">                    sum2 += (num[j] - <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (ans1 &lt; ans2) &#123;</span><br><span class="line">                <span class="built_in">swap</span>(ans1, ans2);</span><br><span class="line">                <span class="built_in">swap</span>(sum1, sum2);</span><br><span class="line">            &#125;</span><br><span class="line">            ans1 -= ans2;</span><br><span class="line">            <span class="keyword">if</span> (sum1 &gt; sum2) &#123;</span><br><span class="line">                <span class="comment">// 1.左边的值&gt;右边的值</span></span><br><span class="line">                <span class="comment">// 最优策略可以简化为两边都加9，右边的所有？被左边消除掉</span></span><br><span class="line">                <span class="comment">// 最后左边的?由alice先选,alice肯定选9拉大左边的值，而bob不能选负数，所以bob必输</span></span><br><span class="line">                <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (sum1 &lt; sum2) &#123;</span><br><span class="line">                <span class="comment">// 2.左边的值&lt;右边的值</span></span><br><span class="line">                <span class="comment">// 最优策略可以简化为两边都加9，右边的所有？被左边消除掉</span></span><br><span class="line">                <span class="comment">// 最后左边的?由alice先选,alice选0拉小左边的值,或者选9拉大左边的值</span></span><br><span class="line">                <span class="comment">// 而bob选9拉大，bob只要能在剩下的?/2次拉大到sum2，就可以赢</span></span><br><span class="line">                <span class="comment">// 或者alice拉大不到比右边还要大</span></span><br><span class="line">                <span class="type">int</span> bob = ans1 / <span class="number">2</span>;</span><br><span class="line">                <span class="type">int</span> alice = (ans1 + <span class="number">1</span>) / <span class="number">2</span>;</span><br><span class="line">                <span class="type">int</span> ok1 = bob * <span class="number">9</span> &gt;= (sum2 - sum1); <span class="comment">// ok1=1代表bob能补回来</span></span><br><span class="line">                <span class="type">int</span> ok2 =</span><br><span class="line">                    alice * <span class="number">9</span> + sum1 &gt;</span><br><span class="line">                    sum2; <span class="comment">// ok2=1代表alice拉大到了比sum2更大,不能加等号，因为bob可以选0</span></span><br><span class="line">                cout &lt;&lt; alice * <span class="number">9</span> &lt;&lt; <span class="string">&#x27; &#x27;</span> &lt;&lt; sum2 &lt;&lt; endl;</span><br><span class="line">                <span class="keyword">return</span> (!ok1 || ok2);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="comment">// 如果两边相等，只要有alice的回合，bob必输，因为bob不能选负数</span></span><br><span class="line">                <span class="keyword">if</span> (ans1 &gt; <span class="number">0</span>)</span><br><span class="line">                    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">                <span class="keyword">else</span></span><br><span class="line">                    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h1 id="动态规划"><a href="#动态规划" class="headerlink" title="动态规划"></a>动态规划</h1><h2 id="锯齿形状数组的总数Ⅱ"><a href="#锯齿形状数组的总数Ⅱ" class="headerlink" title="锯齿形状数组的总数Ⅱ"></a>锯齿形状数组的总数Ⅱ</h2><h3 id="定义状态"><a href="#定义状态" class="headerlink" title="定义状态"></a>定义状态</h3><p>整个数组的变化节奏只有两种。当前位置<code>i</code>的数为x时：</p><ul><li>第<code>i-1</code>个位置是<code>&lt; x</code>的，那么第<code>i+1</code>个位置就要<code>&gt; x</code>的</li><li>第<code>i-1</code>个位置是<code>&gt; x</code>的，那么第<code>i+1</code>个位置就要<code>&lt; x</code>的</li></ul><p>因为每个数都可能作为上升存在也可能作为下降存在，所以定义两个状态：</p><ul><li><code>up[x]</code>：当前数组最后一个数是 <code>x</code>，并且最后一步是上升的方案数，即<code>z &gt; y &lt; x</code></li><li><code>down[x]</code>：当前数组最后一个数是 <code>x</code>，并且最后一步是下降的方案数，即<code>z &lt; y &gt; x</code></li></ul><h3 id="分析状态转移"><a href="#分析状态转移" class="headerlink" title="分析状态转移"></a>分析状态转移</h3><p>若数列为<code>z y x</code>，对于x：</p><ol><li>最后一步是上升，即存在前一个数<code>y &lt; x</code>，那么<code>up[x]</code>要加上<code>down[y]</code>(当前数组最后一个数是 <code>y</code>，并且最后一步是下降的方案数).即加上了<code>z &gt; y</code>的情况</li><li>最后一步是下降，即存在前一个数<code>y &gt; x</code>，那么<code>down[x]</code>要加上<code>up[y]</code>(当前数组最后一个数是 <code>y</code>，并且最后一步是上升的方案数).即加上了<code>z &lt; y</code>的情况</li></ol><h3 id="分析初始状态len-2"><a href="#分析初始状态len-2" class="headerlink" title="分析初始状态len&#x3D;2"></a>分析初始状态len&#x3D;2</h3><p>若长度为2，下标为<code>i</code>的最后一步为上升方案数<code>up[i]=i</code>，下标为<code>i</code>的最后一步为下降方案数<code>up[i]=r-l</code></p><p>得到复杂度高的代码</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="type">int</span> len = <span class="number">3</span>; len &lt;= n; len++) &#123;</span><br><span class="line"><span class="comment">//此时的up,down数组为第len-1层的数据</span></span><br><span class="line"><span class="comment">//定义新newup,newdown来更新第len层的数据</span></span><br><span class="line"><span class="type">int</span> newup[r - l + <span class="number">1</span>] = &#123;<span class="number">0</span>&#125;, newdown[r - l + <span class="number">1</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> x = l; x &lt;= r; x++) &#123;</span><br><span class="line"><span class="comment">//如果y-&gt;x为上升，那么就要加上所有z-&gt;y是下降的</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> y = <span class="number">0</span>; y &lt; x; y++)</span><br><span class="line">newup[x] = (newup[x] + down[y]) % MOD;</span><br><span class="line"><span class="comment">//如果y-&gt;x为下降，那么就要加上所有z-&gt;y是上升的</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> y = x + <span class="number">1</span>; y &lt;= r; y++)</span><br><span class="line">newdown[x] = (newdown[x] + up[y]) % MOD;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = l; i &lt;= r; i++) &#123;</span><br><span class="line">up[i] = newup[i];</span><br><span class="line">down[i] = newdown[i];</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="⭐⭐⭐优化时间复杂度——矩阵快速幂"><a href="#⭐⭐⭐优化时间复杂度——矩阵快速幂" class="headerlink" title="⭐⭐⭐优化时间复杂度——矩阵快速幂"></a>⭐⭐⭐优化时间复杂度——矩阵快速幂</h3><p>比如·<code>n=3,l=0,r=2</code></p><p>当长度为2的时候</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">up   = [<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>]</span><br><span class="line">down = [<span class="number">2</span>, <span class="number">1</span>, <span class="number">0</span>]</span><br><span class="line">state2 =</span><br><span class="line">[</span><br><span class="line">  <span class="number">0</span>,</span><br><span class="line">  <span class="number">1</span>,</span><br><span class="line">  <span class="number">2</span>,</span><br><span class="line">  <span class="number">2</span>,</span><br><span class="line">  <span class="number">1</span>,</span><br><span class="line">  <span class="number">0</span></span><br><span class="line">]</span><br></pre></td></tr></table></figure><p>当进行<code>len=3</code>的更新时</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">newUp[<span class="number">0</span>] = <span class="number">0</span></span><br><span class="line">newUp[<span class="number">1</span>] = down[<span class="number">0</span>]</span><br><span class="line">newUp[<span class="number">2</span>] = down[<span class="number">0</span>] + down[<span class="number">1</span>]</span><br><span class="line"></span><br><span class="line">newDown[<span class="number">0</span>] = up[<span class="number">1</span>] + up[<span class="number">2</span>]</span><br><span class="line">newDown[<span class="number">1</span>] = up[<span class="number">2</span>]</span><br><span class="line">newDown[<span class="number">2</span>] = <span class="number">0</span></span><br><span class="line">如果写的明确一点，所有的新值都是旧状态的加法组合。</span><br><span class="line">newUp[<span class="number">0</span>]   = <span class="number">0</span></span><br><span class="line">newUp[<span class="number">1</span>]   = oldDown[<span class="number">0</span>]</span><br><span class="line">newUp[<span class="number">2</span>]   = oldDown[<span class="number">0</span>] + oldDown[<span class="number">1</span>]</span><br><span class="line">newDown[<span class="number">0</span>] = oldUp[<span class="number">1</span>] + oldUp[<span class="number">2</span>]</span><br><span class="line">newDown[<span class="number">1</span>] = oldUp[<span class="number">2</span>]</span><br><span class="line">newDown[<span class="number">2</span>] = <span class="number">0</span></span><br></pre></td></tr></table></figure><p>这就可以用一个 <code>0/1</code> 表来表示，这个表就是“转移矩阵”。含义为：这个新状态要由哪些旧状态加起来。<code>newUp2: 0 0 0 1 1 0</code>:<code>newUp[2] = oldDown[0] + oldDown[1]</code></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">             oldUp0 oldUp1 oldUp2 oldDown0 oldDown1 oldDown2</span><br><span class="line">newUp0          <span class="number">0</span>      <span class="number">0</span>      <span class="number">0</span>       <span class="number">0</span>        <span class="number">0</span>        <span class="number">0</span></span><br><span class="line">newUp1          <span class="number">0</span>      <span class="number">0</span>      <span class="number">0</span>       <span class="number">1</span>        <span class="number">0</span>        <span class="number">0</span></span><br><span class="line">newUp2          <span class="number">0</span>      <span class="number">0</span>      <span class="number">0</span>       <span class="number">1</span>        <span class="number">1</span>        <span class="number">0</span></span><br><span class="line">newDown0        <span class="number">0</span>      <span class="number">1</span>      <span class="number">1</span>       <span class="number">0</span>        <span class="number">0</span>        <span class="number">0</span></span><br><span class="line">newDown1        <span class="number">0</span>      <span class="number">0</span>      <span class="number">1</span>       <span class="number">0</span>        <span class="number">0</span>        <span class="number">0</span></span><br><span class="line">newDown2        <span class="number">0</span>      <span class="number">0</span>      <span class="number">0</span>       <span class="number">0</span>        <span class="number">0</span>        <span class="number">0</span></span><br></pre></td></tr></table></figure><p>则可以更新出<code>state3 = T * state2，state4 = T * (T * state2)= T^2 * state2…………</code></p><p>我们要计算<code>staten=T^(n-2) * state2</code></p><p>但由于计算<code>n-2</code>次矩阵相乘复杂度太高，那么我们可以用快速幂的方式</p><p>比如<code>n=10</code>，<code>state10 = T^8 * state2</code>，如果普通乘法则需要：<code>state2 -&gt; state3 -&gt; state4 -&gt; state5 -&gt; state6 -&gt; state7 -&gt; state8 -&gt; state9 -&gt; state10</code>。我们优化一下为：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">T^1</span><br><span class="line">T^2 = T^1 * T^1</span><br><span class="line">T^4 = T^2 * T^2</span><br><span class="line">T^8 = T^4 * T^4</span><br></pre></td></tr></table></figure><p>这样只需要四次</p><p>再比如<code>n=15</code>，<code>T^(15 - 2) = T^13</code>，而<code>13 = 8 + 4 + 1</code>（拆解成二进制1101），所以<code>T^13 = T^8 * T^4 * T^1</code>。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">Matrix <span class="title">mul</span><span class="params">(<span class="type">const</span> Matrix&amp; a, <span class="type">const</span> Matrix&amp; b)</span> </span>&#123; <span class="comment">//矩阵乘法</span></span><br><span class="line">    <span class="type">int</span> n = a.<span class="built_in">size</span>();</span><br><span class="line">    <span class="type">int</span> mid = b.<span class="built_in">size</span>();</span><br><span class="line">    <span class="type">int</span> m = b[<span class="number">0</span>].<span class="built_in">size</span>();</span><br><span class="line"></span><br><span class="line">    <span class="function">Matrix <span class="title">c</span><span class="params">(n, vector&lt;<span class="type">long</span> <span class="type">long</span>&gt;(m, <span class="number">0</span>))</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>; k &lt; mid; k++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (a[i][k] == <span class="number">0</span>) <span class="keyword">continue</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j &lt; m; j++) &#123;</span><br><span class="line">                <span class="keyword">if</span> (b[k][j] == <span class="number">0</span>) <span class="keyword">continue</span>;</span><br><span class="line"></span><br><span class="line">                c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % MOD;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> c;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function">Matrix <span class="title">qpow</span><span class="params">(Matrix base, <span class="type">long</span> <span class="type">long</span> exp)</span> </span>&#123; <span class="comment">//快速幂</span></span><br><span class="line">    <span class="type">int</span> n = base.<span class="built_in">size</span>();</span><br><span class="line"></span><br><span class="line">    <span class="function">Matrix <span class="title">res</span><span class="params">(n, vector&lt;<span class="type">long</span> <span class="type">long</span>&gt;(n, <span class="number">0</span>))</span></span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line">        res[i][i] = <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (exp &gt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="comment">//就是看当前二进制这一位是不是 1,如果是 1，就说明当前这个 base 要乘进答案里：</span></span><br><span class="line">        <span class="keyword">if</span> (exp &amp; <span class="number">1</span>) &#123;</span><br><span class="line">            res = <span class="built_in">mul</span>(base, res);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        base = <span class="built_in">mul</span>(base, base);</span><br><span class="line">        exp &gt;&gt;= <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> res;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>快速幂解释，例如n&#x3D;13的情况</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">exp = <span class="number">13</span>，base = T^<span class="number">1</span></span><br><span class="line">最低位是 <span class="number">1</span>，所以 res *= T^<span class="number">1</span></span><br><span class="line">base 平方 -&gt; T^<span class="number">2</span></span><br><span class="line">exp 右移 -&gt; <span class="number">6</span></span><br><span class="line"></span><br><span class="line">exp = <span class="number">6</span>，base = T^<span class="number">2</span></span><br><span class="line">最低位是 <span class="number">0</span>，所以 res 不动</span><br><span class="line">base 平方 -&gt; T^<span class="number">4</span></span><br><span class="line">exp 右移 -&gt; <span class="number">3</span></span><br><span class="line"></span><br><span class="line">exp = <span class="number">3</span>，base = T^<span class="number">4</span></span><br><span class="line">最低位是 <span class="number">1</span>，所以 res *= T^<span class="number">4</span></span><br><span class="line">base 平方 -&gt; T^<span class="number">8</span></span><br><span class="line">exp 右移 -&gt; <span class="number">1</span></span><br><span class="line"></span><br><span class="line">exp = <span class="number">1</span>，base = T^<span class="number">8</span></span><br><span class="line">最低位是 <span class="number">1</span>，所以 res *= T^<span class="number">8</span></span><br><span class="line">base 平方 -&gt; T^<span class="number">16</span></span><br><span class="line">exp 右移 -&gt; <span class="number">0</span></span><br></pre></td></tr></table></figure><h3 id="AC代码"><a href="#AC代码" class="headerlink" title="AC代码"></a>AC代码</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;bits/stdc++.h&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> int long long</span></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> MOD = <span class="number">1e9</span><span class="number">+7</span>;</span><br><span class="line"><span class="keyword">using</span> Matrix = vector&lt;vector&lt;<span class="type">int</span>&gt;&gt;;</span><br><span class="line"></span><br><span class="line"><span class="function">Matrix <span class="title">mul</span><span class="params">(<span class="type">const</span> Matrix&amp; a, <span class="type">const</span> Matrix&amp; b)</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> n = a.<span class="built_in">size</span>();</span><br><span class="line"><span class="type">int</span> mid = b.<span class="built_in">size</span>();</span><br><span class="line"><span class="type">int</span> m = b[<span class="number">0</span>].<span class="built_in">size</span>();</span><br><span class="line"></span><br><span class="line"><span class="function">Matrix <span class="title">c</span><span class="params">(n, vector&lt;<span class="type">int</span>&gt;(m, <span class="number">0</span>))</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>; k &lt; mid; k++) &#123;</span><br><span class="line"><span class="keyword">if</span> (a[i][k] == <span class="number">0</span>) <span class="keyword">continue</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j &lt; m; j++) &#123;</span><br><span class="line"><span class="keyword">if</span> (b[k][j] == <span class="number">0</span>) <span class="keyword">continue</span>;</span><br><span class="line"></span><br><span class="line">c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % MOD;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> c;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function">Matrix <span class="title">qpow</span><span class="params">(Matrix base, <span class="type">int</span> exp)</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> n = base.<span class="built_in">size</span>();</span><br><span class="line"></span><br><span class="line"><span class="function">Matrix <span class="title">res</span><span class="params">(n, vector&lt;<span class="type">int</span>&gt;(n, <span class="number">0</span>))</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line">res[i][i] = <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> (exp &gt; <span class="number">0</span>) &#123;</span><br><span class="line"><span class="keyword">if</span> (exp &amp; <span class="number">1</span>) &#123;</span><br><span class="line">res = <span class="built_in">mul</span>(res, base);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">base = <span class="built_in">mul</span>(base, base);</span><br><span class="line">exp &gt;&gt;= <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> res;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">solve</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> n, l, r;</span><br><span class="line">cin &gt;&gt; n &gt;&gt; l &gt;&gt; r;</span><br><span class="line"><span class="type">int</span> m = r - l + <span class="number">1</span>;</span><br><span class="line"><span class="function">Matrix <span class="title">state</span><span class="params">(<span class="number">2</span> * m, vector&lt;<span class="type">int</span>&gt;(<span class="number">1</span>, <span class="number">0</span>))</span></span>; <span class="comment">//int state[2*m][1]=&#123;0&#125;</span></span><br><span class="line"><span class="function">Matrix <span class="title">trans</span><span class="params">(<span class="number">2</span> * m, vector&lt;<span class="type">int</span>&gt;(<span class="number">2</span> * m, <span class="number">0</span>))</span></span>; <span class="comment">//int trans[2*m][2*m]=&#123;0&#125;</span></span><br><span class="line"><span class="comment">// 长度为 2 的初始状态</span></span><br><span class="line"><span class="comment">// state[0 ... m - 1] 是 up[0 ... m - 1]</span></span><br><span class="line"><span class="comment">// state[m ... 2m - 1] 是 down[0 ... m - 1]</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; m; i++) &#123;</span><br><span class="line">state[i][<span class="number">0</span>] = i;</span><br><span class="line">state[m + i][<span class="number">0</span>] = m - i - <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//求转移矩阵</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> x = <span class="number">0</span>; x &lt; m; x++) &#123;</span><br><span class="line"><span class="comment">// newup[x] = sum(down[y]), y &lt; x</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> y = <span class="number">0</span>; y &lt; x; y++) &#123;</span><br><span class="line">trans[x][ m + y] = <span class="number">1</span>;<span class="comment">//trans[newup][olddown]</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// newdown[x] = sum(up[y]), y &gt; x</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> y = x + <span class="number">1</span>; y &lt; m; y++) &#123;</span><br><span class="line">trans[m + x][y] = <span class="number">1</span>;<span class="comment">//trans[newdown][oldup]</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">Matrix p = <span class="built_in">qpow</span>(trans, n - <span class="number">2</span>);</span><br><span class="line">Matrix finalState = <span class="built_in">mul</span>(p, state);</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> ans = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">2</span> * m; i++) &#123;</span><br><span class="line">ans = (ans + finalState[i][<span class="number">0</span>]) % MOD;</span><br><span class="line">&#125;</span><br><span class="line">cout &lt;&lt; ans &lt;&lt; <span class="string">&#x27;\n&#x27;</span>;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">signed</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">ios_base::<span class="built_in">sync_with_stdio</span>(<span class="number">0</span>);</span><br><span class="line">cin.<span class="built_in">tie</span>(<span class="number">0</span>) ;</span><br><span class="line">cout.<span class="built_in">tie</span>(<span class="number">0</span>);</span><br><span class="line"><span class="built_in">solve</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="区间DP"><a href="#区间DP" class="headerlink" title="区间DP"></a>区间DP</h2><h3 id="（模板题）486-预测赢家"><a href="#（模板题）486-预测赢家" class="headerlink" title="（模板题）486. 预测赢家"></a><a href="https://leetcode.cn/problems/predict-the-winner/">（模板题）486. 预测赢家</a></h3><p>我们在每一步选择的时候会经过这样一个流程：选左或选右导致区间缩小。然后来到下一步面临的还是同样的问题结构</p><ul><li>每一步选择影响的是剩余的连续区间</li><li>状态天然和”子数组首尾”绑定</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">bool</span> <span class="title">predictTheWinner</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> len = nums.<span class="built_in">size</span>();</span><br><span class="line"><span class="type">int</span> dp[len][len]; <span class="comment">// dp[i][j] = 当前玩家从 nums[i..j] 能获得的最大分差（自己 - 对手）</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; len; i++) &#123;</span><br><span class="line">dp[i][i] = nums[i];</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">int</span> ans = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = len - <span class="number">2</span>; i &gt;= <span class="number">0</span>; i--) &#123;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> j = i + <span class="number">1</span>; j &lt; len; j++) &#123;</span><br><span class="line"><span class="comment">// 选左边 nums[i]，对手从 i+1..j 能得 dp[i+1][j]，所以当前分差 = nums[i] - dp[i+1][j]</span></span><br><span class="line"><span class="comment">// 选右边 nums[j]，对手从 i..j-1 能得 dp[i][j-1]，所以当前分差 = nums[j] - dp[i][j-1]</span></span><br><span class="line">dp[i][j] = <span class="built_in">max</span>(nums[i] - dp[i + <span class="number">1</span>][j], nums[j] - dp[i][j - <span class="number">1</span>]);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> dp[<span class="number">0</span>][len - <span class="number">1</span>] &gt;= <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="877-石子游戏（1590）"><a href="#877-石子游戏（1590）" class="headerlink" title="877. 石子游戏（1590）"></a><a href="https://leetcode.cn/problems/stone-game">877. 石子游戏（1590）</a></h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="function"><span class="type">bool</span> <span class="title">stoneGame</span><span class="params">(vector&lt;<span class="type">int</span>&gt;&amp; piles)</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> len = piles.<span class="built_in">size</span>();</span><br><span class="line"><span class="type">int</span> dp[len][len]; <span class="comment">// dp[i][j] = 当前玩家从 nums[i..j] 能获得的最大分差（自己 - 对手）</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; len; i++) &#123;</span><br><span class="line">dp[i][i] = piles[i];</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">int</span> ans = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = len - <span class="number">2</span>; i &gt;= <span class="number">0</span>; i--) &#123;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> j = i + <span class="number">1</span>; j &lt; len; j++) &#123;</span><br><span class="line"><span class="comment">// 选左边 nums[i]，对手从 i+1..j 能得 dp[i+1][j]，所以当前分差 = nums[i] - dp[i+1][j]</span></span><br><span class="line"><span class="comment">// 选右边 nums[j]，对手从 i..j-1 能得 dp[i][j-1]，所以当前分差 = nums[j] - dp[i][j-1]</span></span><br><span class="line">dp[i][j] = <span class="built_in">max</span>(piles[i] - dp[i + <span class="number">1</span>][j], piles[j] - dp[i][j - <span class="number">1</span>]);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> dp[<span class="number">0</span>][len - <span class="number">1</span>] &gt;= <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="1406-石子游戏-III（2027）"><a href="#1406-石子游戏-III（2027）" class="headerlink" title="1406. 石子游戏 III（2027）"></a><a href="https://leetcode.cn/problems/stone-game-iii">1406. 石子游戏 III（2027）</a></h3><h1 id="贪心"><a href="#贪心" class="headerlink" title="贪心"></a>贪心</h1><h2 id="1386-安排电影院座位（1637）"><a href="#1386-安排电影院座位（1637）" class="headerlink" title="1386. 安排电影院座位（1637）"></a><a href="https://leetcode.cn/problems/cinema-seat-allocation/">1386. 安排电影院座位（1637）</a></h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Solution</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">maxNumberOfFamilies</span><span class="params">(<span class="type">int</span> n, vector&lt;vector&lt;<span class="type">int</span>&gt;&gt;&amp; reservedSeats)</span> </span>&#123;</span><br><span class="line">        <span class="built_in">sort</span>(reservedSeats.<span class="built_in">begin</span>(), reservedSeats.<span class="built_in">end</span>(),</span><br><span class="line">             [](<span class="type">const</span> vector&lt;<span class="type">int</span>&gt;&amp; a, <span class="type">const</span> vector&lt;<span class="type">int</span>&gt;&amp; b) &#123;</span><br><span class="line">                 <span class="keyword">if</span> (a[<span class="number">0</span>] != b[<span class="number">0</span>])</span><br><span class="line">                     <span class="keyword">return</span> a[<span class="number">0</span>] &lt; b[<span class="number">0</span>];</span><br><span class="line">                 <span class="keyword">else</span></span><br><span class="line">                     <span class="keyword">return</span> a[<span class="number">1</span>] &lt; b[<span class="number">1</span>];</span><br><span class="line">             &#125;);</span><br><span class="line">        <span class="type">int</span> ans = <span class="number">0</span>;</span><br><span class="line">        <span class="type">int</span> now = reservedSeats[<span class="number">0</span>][<span class="number">0</span>];</span><br><span class="line">        <span class="type">int</span> seat = n;</span><br><span class="line">        <span class="type">int</span> seatcount[<span class="number">11</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">        <span class="type">int</span> family[<span class="number">3</span>] = &#123;<span class="number">2</span>, <span class="number">4</span>, <span class="number">6</span>&#125;;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; reservedSeats.<span class="built_in">size</span>(); i++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (reservedSeats[i][<span class="number">0</span>] != now || i == reservedSeats.<span class="built_in">size</span>() - <span class="number">1</span>) &#123;<span class="comment">//这里是不能加上|| i == reservedSeats.size() - 1的，因为这个分支的作用是进行上一行的计算，**更新条件只能是换行**，也就是reservedSeats[i][0] != now 。如果加上|| i == reservedSeats.size() - 1。那么就导致没有触发换行条件就进行上一行的更新</span></span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> (i == reservedSeats.<span class="built_in">size</span>() - <span class="number">1</span>) &#123;</span><br><span class="line">                    <span class="comment">//没有触发换行条件就进行上一行的更新就会导致下一行里面有上一行的状态信息（因为我是想：比如now=1，当第二行的时候now改为2的同时处理第一行的数据，直到now改为185的时候处理第184行的数据。然后更新我的seatcount=0，当186行的时候处理第185行的数据。但是没有第186行，所以我加上了i == reservedSeats.size() - 1，但是如果这样的话这个分支里面的 seatcount[reservedSeats[i][1]] = 1;就会在第184行加上第185行的数据）</span></span><br><span class="line">                    seatcount[reservedSeats[i][<span class="number">1</span>]] = <span class="number">1</span>;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                now = reservedSeats[i][<span class="number">0</span>];</span><br><span class="line">                seat--;</span><br><span class="line">                <span class="type">int</span> ok = <span class="number">-1</span>;</span><br><span class="line">                <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j &lt;= <span class="number">2</span>; j++) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (j &gt; <span class="number">0</span> &amp;&amp; family[j - <span class="number">1</span>] == ok) &#123;</span><br><span class="line">                        <span class="keyword">continue</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>; k &lt;= <span class="number">3</span>; k++) &#123;</span><br><span class="line">                        <span class="keyword">if</span> (seatcount[family[j] + k] != <span class="number">0</span>)</span><br><span class="line">                            <span class="keyword">break</span>;</span><br><span class="line">                        <span class="keyword">if</span> (k == <span class="number">3</span>) &#123;</span><br><span class="line">                            cout &lt;&lt; family[j] &lt;&lt; endl;</span><br><span class="line">                            ans++;</span><br><span class="line">                            ok = family[j];</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="built_in">memset</span>(seatcount, <span class="number">0</span>, <span class="built_in">sizeof</span>(seatcount));</span><br><span class="line">            &#125;</span><br><span class="line">            seatcount[reservedSeats[i][<span class="number">1</span>]] = <span class="number">1</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        ans += seat * <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> ans;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>解决方法要么把最后的处理方法拿出来，要么加上一个第n+1行的完美行的数据作为空数据强行出触发行的更替，最后再减去2（因为我这里写的是完美行）就可以了</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">maxNumberOfFamilies</span><span class="params">(<span class="type">int</span> n, vector&lt;vector&lt;<span class="type">int</span>&gt;&gt;&amp; reservedSeats)</span> </span>&#123;</span><br><span class="line">       <span class="built_in">sort</span>(reservedSeats.<span class="built_in">begin</span>(), reservedSeats.<span class="built_in">end</span>(),</span><br><span class="line">            [](<span class="type">const</span> vector&lt;<span class="type">int</span>&gt;&amp; a, <span class="type">const</span> vector&lt;<span class="type">int</span>&gt;&amp; b) &#123;</span><br><span class="line">                <span class="keyword">if</span> (a[<span class="number">0</span>] != b[<span class="number">0</span>])</span><br><span class="line">                    <span class="keyword">return</span> a[<span class="number">0</span>] &lt; b[<span class="number">0</span>];</span><br><span class="line">                <span class="keyword">else</span></span><br><span class="line">                    <span class="keyword">return</span> a[<span class="number">1</span>] &lt; b[<span class="number">1</span>];</span><br><span class="line">            &#125;);</span><br><span class="line">       <span class="type">int</span> ans = <span class="number">0</span>;</span><br><span class="line">       <span class="type">int</span> now = reservedSeats[<span class="number">0</span>][<span class="number">0</span>];</span><br><span class="line">       <span class="type">int</span> seat = n;</span><br><span class="line">       <span class="type">int</span> seatcount[<span class="number">11</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">       <span class="type">int</span> family[<span class="number">3</span>] = &#123;<span class="number">2</span>, <span class="number">4</span>, <span class="number">6</span>&#125;;</span><br><span class="line">       <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; reservedSeats.<span class="built_in">size</span>(); i++) &#123;</span><br><span class="line">           <span class="keyword">if</span> (reservedSeats[i][<span class="number">0</span>] != now) &#123;</span><br><span class="line">               now = reservedSeats[i][<span class="number">0</span>];</span><br><span class="line">               seat--;</span><br><span class="line">               <span class="type">int</span> ok = <span class="number">-1</span>;</span><br><span class="line">               <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j &lt;= <span class="number">2</span>; j++) &#123;</span><br><span class="line">                   <span class="keyword">if</span> (j &gt; <span class="number">0</span> &amp;&amp; family[j - <span class="number">1</span>] == ok) &#123;</span><br><span class="line">                       <span class="keyword">continue</span>;</span><br><span class="line">                   &#125;</span><br><span class="line">                   <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>; k &lt;= <span class="number">3</span>; k++) &#123;</span><br><span class="line">                       <span class="keyword">if</span> (seatcount[family[j] + k] != <span class="number">0</span>)</span><br><span class="line">                           <span class="keyword">break</span>;</span><br><span class="line">                       <span class="keyword">if</span> (k == <span class="number">3</span>) &#123;</span><br><span class="line">                           cout &lt;&lt; family[j] &lt;&lt; endl;</span><br><span class="line">                           ans++;</span><br><span class="line">                           ok = family[j];</span><br><span class="line">                       &#125;</span><br><span class="line">                   &#125;</span><br><span class="line">               &#125;</span><br><span class="line">               <span class="built_in">memset</span>(seatcount, <span class="number">0</span>, <span class="built_in">sizeof</span>(seatcount));</span><br><span class="line">           &#125;</span><br><span class="line">           seatcount[reservedSeats[i][<span class="number">1</span>]] = <span class="number">1</span>;</span><br><span class="line">       &#125;</span><br><span class="line">       seat--;</span><br><span class="line">       <span class="type">int</span> ok = <span class="number">-1</span>;</span><br><span class="line">       <span class="keyword">for</span> (<span class="type">int</span> j = <span class="number">0</span>; j &lt;= <span class="number">2</span>; j++) &#123;</span><br><span class="line">           <span class="keyword">if</span> (j &gt; <span class="number">0</span> &amp;&amp; family[j - <span class="number">1</span>] == ok) &#123;</span><br><span class="line">               <span class="keyword">continue</span>;</span><br><span class="line">           &#125;</span><br><span class="line">           <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>; k &lt;= <span class="number">3</span>; k++) &#123;</span><br><span class="line">               <span class="keyword">if</span> (seatcount[family[j] + k] != <span class="number">0</span>)</span><br><span class="line">                   <span class="keyword">break</span>;</span><br><span class="line">               <span class="keyword">if</span> (k == <span class="number">3</span>) &#123;</span><br><span class="line">                   cout &lt;&lt; family[j] &lt;&lt; endl;</span><br><span class="line">                   ans++;</span><br><span class="line">                   ok = family[j];</span><br><span class="line">               &#125;</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;</span><br><span class="line">       ans += seat * <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line">       <span class="keyword">return</span> ans;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://tysweb.pages.dev/2026/06/24/LeetCode%E5%88%B7%E9%A2%98%E7%AC%94%E8%AE%B0/</id>
    <link href="https://tysweb.pages.dev/2026/06/24/LeetCode%E5%88%B7%E9%A2%98%E7%AC%94%E8%AE%B0/"/>
    <published>2026-06-24T10:38:58.000Z</published>
    <summary>
      <![CDATA[<h1 id="基础算法"><a href="#基础算法" class="headerlink" title="基础算法"></a>基础算法</h1><h2 id="位运算"><a href="#位运算" class="headerlink" title="位运算"></a>位运]]>
    </summary>
    <title>LeetCode刷题笔记</title>
    <updated>2026-09-07T01:31:21.833Z</updated>
  </entry>
  <entry>
    <author>
      <name>ctyyy</name>
    </author>
    <category term="算法题" scheme="https://tysweb.pages.dev/categories/%E7%AE%97%E6%B3%95%E9%A2%98/"/>
    <category term="算法" scheme="https://tysweb.pages.dev/tags/%E7%AE%97%E6%B3%95/"/>
    <category term="Codeforces" scheme="https://tysweb.pages.dev/tags/Codeforces/"/>
    <content>
      <![CDATA[<p><a href="https://codeforces.com/contest/2236">题目地址</a></p><h1 id="A-Games-on-the-Train"><a href="#A-Games-on-the-Train" class="headerlink" title="A- Games on the Train"></a>A- Games on the Train</h1><p>因为最后要到达同样的高度，并且每个塔都必须要添加高度。其实就是最矮的塔添加到【最高塔+1】的高度，记为ans。其余中间高度的塔要添加多少高度不用管，因为这个高度肯定包含在ans里面</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">solve</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> t, k;</span><br><span class="line">cin&gt;&gt;t;</span><br><span class="line"><span class="keyword">while</span> (t--) &#123;</span><br><span class="line"><span class="type">int</span> maxx=<span class="number">0</span>,minn=<span class="number">1e9</span><span class="number">+10</span>;</span><br><span class="line"><span class="type">int</span> n,tem;</span><br><span class="line">cin&gt;&gt;n;</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i&lt;n;i++)&#123;</span><br><span class="line">cin&gt;&gt;tem;</span><br><span class="line">maxx=<span class="built_in">max</span>(maxx,tem);</span><br><span class="line">minn=<span class="built_in">min</span>(minn,tem);</span><br><span class="line">&#125;</span><br><span class="line">cout&lt;&lt;(maxx<span class="number">+1</span>)-minn&lt;&lt;<span class="string">&#x27;\n&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="B-Tatar-TV-Show"><a href="#B-Tatar-TV-Show" class="headerlink" title="B. Tatar TV Show"></a>B. Tatar TV Show</h1><p>一次操作会同时翻转两个相距 <code>k</code> 的位置：<code>i</code> 和 <code>i+k</code>。这意味着位置之间按“相差 <code>k</code>”形成若干条链：</p><ul><li><code>1, 1+k, 1+2k, ...</code></li><li><code>2, 2+k, 2+2k, ...</code></li><li>…</li><li><code>k, 2k, 3k, ...</code></li></ul><p>每次操作只会在同一条链里翻转相邻两个点。在同一条链里，<code>1</code> 的个数奇偶性不变。</p><ul><li>如果两个都是 <code>0</code>，<code>1</code> 的数量 <code>+2</code></li><li>如果两个都是 <code>1</code>，<code>1</code> 的数量 <code>-2</code></li><li>如果一 <code>0</code> 一 <code>1</code>，<code>1</code> 的数量不变</li></ul><p>无论哪种情况，<code>1</code> 的数量奇偶性都不变。</p><p>最终目标是全 <code>0</code>，每条链里的 <code>1</code> 数量都是 <code>0</code>，也就是偶数。</p><p>所以答案条件是：</p><blockquote><p>对每个余数类，也就是所有位置 <code>i, i+k, i+2k...</code>，其中 <code>1</code> 的个数必须是偶数。</p></blockquote><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">solve</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> t;</span><br><span class="line">cin &gt;&gt; t;</span><br><span class="line"><span class="keyword">while</span> (t--) &#123;</span><br><span class="line"><span class="type">int</span> n, k;</span><br><span class="line">cin &gt;&gt; n &gt;&gt; k;</span><br><span class="line">string s;</span><br><span class="line">cin &gt;&gt; s;</span><br><span class="line"><span class="type">int</span> num[k]=&#123;<span class="number">0</span>&#125;;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; s.<span class="built_in">size</span>(); i++)</span><br><span class="line"><span class="keyword">if</span> (s[i] == <span class="string">&#x27;1&#x27;</span>)</span><br><span class="line">num[(i + <span class="number">1</span>) % k] += <span class="number">1</span>;</span><br><span class="line"><span class="type">int</span> flag = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; k; i++) &#123;</span><br><span class="line"><span class="keyword">if</span> (num[i] % <span class="number">2</span> != <span class="number">0</span>) &#123;</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;NO&quot;</span> &lt;&lt; <span class="string">&#x27;\n&#x27;</span>;</span><br><span class="line">flag = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> (!flag) &#123;</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;YES&quot;</span> &lt;&lt; <span class="string">&#x27;\n&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="C-Omsk-Programmers"><a href="#C-Omsk-Programmers" class="headerlink" title="C. Omsk Programmers"></a>C. Omsk Programmers</h1><p>对于一个数 <code>v</code>，如果你决定对它做若干次除法，那么就是<br><code>floor(v / x)</code><br><code>floor(v / x^2)</code><br><code>floor(v / x^3)</code><br><code>...</code><br><code>0</code></p><p>因为 <code>v ≤ 1e9</code>，<code>x ≥ 2</code>，所以这个链长度最多三十多。<code>pow(2,30)</code>&#x3D;1073741824，1e9&#x3D;1000000000.所以链长不会超过三十一</p><p>所以进行while循环暴力进行每次次数的记录的O(n)是完全ok的</p><p>时间复杂度：</p><ul><li>构造 <code>mpa</code>：<code>O(La * log La)</code>，因为 <code>map</code> 插入是 <code>log</code></li><li>构造 <code>mpb</code>：<code>O(Lb * log Lb)</code></li><li>双重枚举：<code>O(La * Lb)</code></li><li>单组为：<code>O(La * log La + Lb * log Lb + La * Lb)</code>由于 <code>La,Lb ≤ 31</code>，可以近似看成常数。<code>t ≤ 1e4</code>，所以总复杂度：<code>O(t * 31 * 31)</code>≈<code>O(t)</code></li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">solve</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> t;</span><br><span class="line">cin &gt;&gt; t;</span><br><span class="line"><span class="keyword">while</span> (t--) &#123;</span><br><span class="line"><span class="type">int</span> a, b, x;</span><br><span class="line">cin &gt;&gt; a &gt;&gt; b &gt;&gt; x;</span><br><span class="line">map&lt;<span class="type">int</span>, <span class="type">int</span>&gt; mpa, mpb;</span><br><span class="line"><span class="type">int</span> aans = <span class="number">0</span>, bans = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">while</span> (a != <span class="number">0</span>) &#123;</span><br><span class="line">mpa[a] = aans;</span><br><span class="line">aans++;</span><br><span class="line">a /= x;</span><br><span class="line">&#125;</span><br><span class="line">mpa[<span class="number">0</span>] = aans;</span><br><span class="line"><span class="keyword">while</span> (b != <span class="number">0</span>) &#123;</span><br><span class="line">mpb[b] = bans;</span><br><span class="line">bans++;</span><br><span class="line">b /= x;</span><br><span class="line">&#125;</span><br><span class="line">mpb[<span class="number">0</span>] = bans;</span><br><span class="line"><span class="type">int</span> ans = <span class="number">1e9</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">auto</span> v : mpa)</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">auto</span> v1 : mpb)</span><br><span class="line">ans = <span class="built_in">min</span>(<span class="built_in">abs</span>(v.first - v<span class="number">1.f</span>irst) + v.second + v<span class="number">1.</span>second, ans);</span><br><span class="line">cout &lt;&lt; ans;</span><br><span class="line">cout &lt;&lt; <span class="string">&#x27;\n&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="D-Brand-New-Tatar-TV-Show-DP"><a href="#D-Brand-New-Tatar-TV-Show-DP" class="headerlink" title="D. Brand New Tatar TV Show[DP]"></a>D. Brand New Tatar TV Show[DP]</h1><h2 id="定义dp"><a href="#定义dp" class="headerlink" title="定义dp"></a>定义dp</h2><p>在 Arseniy 第一步选择某个数 <code>x</code> 后，游戏状态为：上一次选择的是 x，x还剩下了y个，轮到 Egor选数，我们让：</p><p><code>dp[i] = 当前上一次被选择的数是 x，现在轮到当前玩家行动时，当前玩家是否必胜</code>。</p><p>那么现在只需要找到一个<code>dp[i]=1</code>就可以了，我们就可以在第一步的时候就让Arseniy选择这个<code>x</code>。那么在第<code>i</code>轮中轮到 Egor选择的时候就会必赢。</p><h2 id="分析选数流程"><a href="#分析选数流程" class="headerlink" title="分析选数流程"></a>分析选数流程</h2><p>我们定义：</p><ul><li>上一次选择的是<code>val[i]</code>，并按照选择的数的大小排序</li><li><code>val[i]</code>还剩下<code>cnt[val[i]]</code>个</li></ul><p>则如果上一次选择了<code>val[i]</code>，那么这一次只能：</p><ol><li><p>选择一个更大的数<code>val[j]</code>，进入下一个状态的博弈（因为一旦有人选择了跳跃下一个阶段，那么是不可以跳回来的。），并且满足：<code>val[i] &lt; val[j] &lt;= val[i] + k</code>。并且如果存在这样一个<code>j</code>使得<code>dp[j]</code>在计算过后为<code>dp[j]==0</code>，那么<code>dp[i]=1</code>，当前玩家获胜。如若不然，当前玩家就不能通过跳跃获胜，只能看同一个数 <code>val[i]</code> 剩下多少个。</p></li><li><p>继续选择<code>val[i]</code>。Arseniy 或上一手已经拿走了一个 <code>val[i]</code>，所以还剩：<code>cnt[val[i]] - 1</code>个。那么<code>cnt[val[i]] - 1</code>：</p><ul><li>如果是奇数，当前玩家可以拿到最后一个，获胜。</li><li>如果是偶数，当前玩家拿不到最后一个，失败。</li></ul><p>所以：如果玩家不能通过方式1来跳跃取胜，那么转移方程为：<code>dp[i] = ((cnt[val[i]] - 1) % 2 == 1)</code></p></li></ol><p>故转移公式为：是否存在 <code>j &gt; i</code>，满足 <code>val[j] &lt;= val[i] + k</code> 且 <code>dp[j] == false</code>。如果存在：<code>dp[i]=1</code>，如果不存在，<code>dp[i] = ((cnt[val[i]] - 1) % 2 == 1)</code></p><h2 id="dp初始状态"><a href="#dp初始状态" class="headerlink" title="dp初始状态"></a>dp初始状态</h2><p>因为通过跳跃的方式来取胜的过程，是要有跳跃之后<code>dp[j]</code>的获胜状态的。所以我们只能先更新<code>dp[j]</code>的获胜状态，然后有<code>dp[j]</code>的状态之后再去更新<code>dp[i]</code>的状态。那么<code>dp[j]</code>的状态是根据<code>dp[l]</code>来更新的，其中：<code>j &lt; l</code>且<code>val[j] &lt; val[l] &lt;= val[j] + k</code>………… 如果一直往后迭代就能找到初始状态：</p><ul><li><code>dp[u]</code>:<code>u</code>为<code>val[n]</code>的最后一个数，不会再去找一个比它大的数来更新它的状态</li><li><code>dp[u]</code>的能否获胜只能取决于方式2</li></ul><h2 id="复杂度优化"><a href="#复杂度优化" class="headerlink" title="复杂度优化"></a>复杂度优化</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">solve</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> t;</span><br><span class="line">cin &gt;&gt; t;</span><br><span class="line"><span class="keyword">while</span> (t--) &#123;</span><br><span class="line"><span class="type">int</span> n, k;</span><br><span class="line">cin &gt;&gt; n &gt;&gt; k;</span><br><span class="line"><span class="type">int</span>  cnt[n + <span class="number">1</span>] = &#123;<span class="number">0</span>&#125;, dp[n + <span class="number">1</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line"><span class="type">int</span> tem = <span class="number">0</span>;</span><br><span class="line">vector&lt;<span class="type">int</span>&gt; val;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line"><span class="type">int</span> x;</span><br><span class="line">cin &gt;&gt; x;</span><br><span class="line">cnt[x]++;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt;= n; i++)</span><br><span class="line"><span class="keyword">if</span> (cnt[i] != <span class="number">0</span>)</span><br><span class="line">val.<span class="built_in">push_back</span>(i);</span><br><span class="line"><span class="built_in">sort</span>(val.<span class="built_in">begin</span>(), val.<span class="built_in">end</span>());</span><br><span class="line"><span class="type">int</span> s = val.<span class="built_in">size</span>();</span><br><span class="line"><span class="comment">//如果上一轮拿走一个是奇数，必赢</span></span><br><span class="line"><span class="keyword">if</span> (cnt[val[s - <span class="number">1</span>]] % <span class="number">2</span> == <span class="number">0</span>) dp[s - <span class="number">1</span>] = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = s - <span class="number">2</span>; i &gt;= <span class="number">0</span>; i--) &#123;</span><br><span class="line"><span class="comment">//当前剩余：cnt[val[i]]-1个数</span></span><br><span class="line"><span class="keyword">if</span> (cnt[val[i]] % <span class="number">2</span> != <span class="number">0</span>) &#123; <span class="comment">//如果当前按方式2继续拿下去的话，当前阶段是必输的。所以只能进行跳跃</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> j = i + <span class="number">1</span>; j &lt; s; j++) &#123;</span><br><span class="line"><span class="comment">//去寻找存不存在一个j使得dp[j]=0,代表当前玩家在这一轮只要取val[j]就能必赢</span></span><br><span class="line"><span class="keyword">if</span> (val[j] - val[i] &lt;= k) &#123;</span><br><span class="line"><span class="keyword">if</span> (dp[j] == <span class="number">0</span>) &#123; <span class="comment">//如果存在，当前玩家就跳到这个必赢的那个阶段</span></span><br><span class="line">dp[i] = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125; <span class="keyword">else</span></span><br><span class="line">dp[i] = <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">int</span> flag = <span class="number">0</span>;</span><br><span class="line"><span class="comment">//cout&lt;&lt;dp[1]&lt;&lt;endl;</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; s; i++)</span><br><span class="line"><span class="keyword">if</span> (dp[i])</span><br><span class="line">flag = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">if</span> (flag) cout &lt;&lt; <span class="string">&quot;YES&quot;</span>;</span><br><span class="line"><span class="keyword">else</span> cout &lt;&lt; <span class="string">&quot;NO&quot;</span>;</span><br><span class="line">cout &lt;&lt; <span class="string">&#x27;\n&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/2026/06/20/Codeforces%20Round%201103%20(Div.%203)/image-20260624174329502.png" alt="image-20260624174329502"></p><p>TLE的原因是因为第二层循环的暴力枚举：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="type">int</span> j = i + <span class="number">1</span>; j &lt; s; j++) &#123;</span><br><span class="line">    <span class="keyword">if</span> (val[j] - val[i] &lt;= k) &#123;</span><br><span class="line">        <span class="keyword">if</span> (dp[j] == <span class="number">0</span>) &#123;</span><br><span class="line">            dp[i] = <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>我们可以用vector和set的STL库快速定位和查找。其中定位和查找的复杂度都为O(logn)</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">solve</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> t;</span><br><span class="line">cin &gt;&gt; t;</span><br><span class="line"><span class="keyword">while</span> (t--) &#123;</span><br><span class="line"><span class="type">int</span> n, k;</span><br><span class="line">cin &gt;&gt; n &gt;&gt; k;</span><br><span class="line"><span class="type">int</span>  cnt[n + <span class="number">1</span>] = &#123;<span class="number">0</span>&#125;, dp[n + <span class="number">1</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line"><span class="type">int</span> tem = <span class="number">0</span>;</span><br><span class="line">vector&lt;<span class="type">int</span>&gt; val;</span><br><span class="line">set&lt;<span class="type">int</span>&gt; lose;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line"><span class="type">int</span> x;</span><br><span class="line">cin &gt;&gt; x;</span><br><span class="line">cnt[x]++;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt;= n; i++)</span><br><span class="line"><span class="keyword">if</span> (cnt[i] != <span class="number">0</span>)</span><br><span class="line">val.<span class="built_in">push_back</span>(i);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="built_in">sort</span>(val.<span class="built_in">begin</span>(), val.<span class="built_in">end</span>());</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> s = val.<span class="built_in">size</span>();</span><br><span class="line"><span class="comment">//如果上一轮拿走一个是奇数，必赢</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (cnt[val[s - <span class="number">1</span>]] % <span class="number">2</span> == <span class="number">0</span>) dp[s - <span class="number">1</span>] = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">if</span> (!dp[s - <span class="number">1</span>]) lose.<span class="built_in">insert</span>(s - <span class="number">1</span>);</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = s - <span class="number">2</span>; i &gt;= <span class="number">0</span>; i--) &#123;</span><br><span class="line"><span class="type">int</span> flag=<span class="number">1</span>;</span><br><span class="line"><span class="comment">//当前剩余：cnt[val[i]]-1个数</span></span><br><span class="line"><span class="keyword">if</span> (cnt[val[i]] % <span class="number">2</span> != <span class="number">0</span>) &#123; </span><br><span class="line"></span><br><span class="line"><span class="comment">//合法的跳跃约区间 O(log(n))</span></span><br><span class="line"><span class="type">int</span> pos = <span class="built_in">upper_bound</span>(val.<span class="built_in">begin</span>(), val.<span class="built_in">end</span>(), val[i] + k) - val.<span class="built_in">begin</span>()<span class="number">-1</span> ;</span><br><span class="line"><span class="comment">//在lose里面找有没有大于i下标(大于i下标就代表是之前记录好的状态)的失败状态</span></span><br><span class="line"><span class="comment">//lose.upper_bound(i)没找到返回lose.end()</span></span><br><span class="line"><span class="keyword">auto</span> it = lose.<span class="built_in">upper_bound</span>(i);</span><br><span class="line"><span class="keyword">if</span>(it!=lose.<span class="built_in">end</span>()&amp;&amp;(*it)&lt;=pos)&#123;</span><br><span class="line">dp[i]=<span class="number">1</span>;</span><br><span class="line">flag=<span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125; <span class="keyword">else</span></span><br><span class="line">dp[i] = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">if</span>(flag) lose.<span class="built_in">insert</span>(i);</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">int</span> flag = <span class="number">0</span>;</span><br><span class="line"><span class="comment">//cout&lt;&lt;dp[1]&lt;&lt;endl;</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; s; i++)</span><br><span class="line"><span class="keyword">if</span> (dp[i])</span><br><span class="line">flag = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">if</span> (flag) cout &lt;&lt; <span class="string">&quot;YES&quot;</span>;</span><br><span class="line"><span class="keyword">else</span> cout &lt;&lt; <span class="string">&quot;NO&quot;</span>;</span><br><span class="line">cout &lt;&lt; <span class="string">&#x27;\n&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="E-Friendly-Gifts"><a href="#E-Friendly-Gifts" class="headerlink" title="E. Friendly Gifts"></a>E. Friendly Gifts</h1><h2 id="题目分析"><a href="#题目分析" class="headerlink" title="题目分析"></a>题目分析</h2><p>如果一个数组是good数组，那么数组要满足</p><ol><li>没有重复，2. 最大值 - 最小值 + 1 &#x3D; 长度</li></ol><p>题目要找两个长度一样的 good 子段，而且它们合起来也要 good。比如长度是 <code>4</code>。第一段如果是：<code>[1,2,3,4]</code>。第二段就必须刚好接上：<code>[5,6,7,8]</code>.这样合起来才是：<code>[1,2,3,4,5,6,7,8]</code>。所以核心为找一段数值范围是 <code>[x, x+len-1]</code>，再找一段数值范围是<code> [x+len, x+2len-1]</code></p><h2 id="定义转移数组"><a href="#定义转移数组" class="headerlink" title="定义转移数组"></a>定义转移数组</h2><p>同一种子段可能出现很多次，我们只记录它们所有起点里最靠左的那个、最靠右的那个，定义：</p><blockquote><p>mnPos[len][x]：长度为 len、最小值为 x 的 good 子段中，最靠左的起点</p><p>mxPos[len][x]：长度为 len、最小值为 x 的 good 子段中，最靠右的起点</p></blockquote><p>比如数组里有很多个长度为 <code>3</code>、最小值为 <code>1</code> 的 good 子段。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">位置 2 开始：[1,2,3]</span><br><span class="line">位置 5 开始：[3,1,2]</span><br><span class="line">位置 8 开始：[2,3,1]</span><br></pre></td></tr></table></figure><p>它们属于同一类：len &#x3D; 3, x &#x3D; 1。这些子段的起点分别是 2, 5, 8。则最小起点 &#x3D; 2<br>最大起点 &#x3D; 8。</p><h3 id="我们为什么要记录最大起点？"><a href="#我们为什么要记录最大起点？" class="headerlink" title="我们为什么要记录最大起点？"></a>我们为什么要记录最大起点？</h3><p>比如另一类子段是：len &#x3D; 3, x &#x3D; 4。假设它只出现在位置 1 开始：[4,5,6]。如果我们只知道第一类的最小起点 <code>2</code>，那它和起点 <code>1</code> 太近就感觉起来会重叠。但其实第一类还有一个起点 <code>8</code>，尽量拉远，就会不重叠。</p><h3 id="那凭什么认为记录最小和最大就是正确答案？万一在中间呢？"><a href="#那凭什么认为记录最小和最大就是正确答案？万一在中间呢？" class="headerlink" title="那凭什么认为记录最小和最大就是正确答案？万一在中间呢？"></a>那凭什么认为记录最小和最大就是正确答案？万一在中间呢？</h3><p>因为我们只需要判断“有没有两个不重叠”，而不是要找某个特殊的中间位置。如果中间某两个能不重叠，那么最左和最右一定也能不重叠。所以，对于同一种 good 子段类型，<span style="color:#FF00FF">我们只需要知道它<strong>最左能从哪里开始</strong>，以及<strong>最右能从哪里开始就可以了</strong>。</span></p><h2 id="AC代码"><a href="#AC代码" class="headerlink" title="AC代码"></a>AC代码</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">solve</span><span class="params">()</span> </span>&#123;</span><br><span class="line"><span class="type">int</span> t;</span><br><span class="line">cin &gt;&gt; t;</span><br><span class="line"><span class="keyword">while</span> (t--) &#123;</span><br><span class="line"><span class="type">int</span> n;</span><br><span class="line">cin &gt;&gt; n;</span><br><span class="line"><span class="function">vector&lt;<span class="type">int</span>&gt; <span class="title">a</span><span class="params">(n + <span class="number">1</span>)</span></span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt;= n; i++) &#123;</span><br><span class="line">cin &gt;&gt; a[i];</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// lPos[len][x]：长度为 len、最小值为 x 的 good 子段中，最靠左的起点</span></span><br><span class="line"><span class="comment">// rPos[len][x]：长度为 len、最小值为 x 的 good 子段中，最靠右的起点</span></span><br><span class="line">vector&lt;vector&lt;<span class="type">int</span>&gt;&gt; <span class="built_in">lpos</span>(n + <span class="number">1</span>, <span class="built_in">vector</span>&lt;<span class="type">int</span>&gt;(n + <span class="number">2</span>, INF));</span><br><span class="line">vector&lt;vector&lt;<span class="type">int</span>&gt;&gt; <span class="built_in">rpos</span>(n + <span class="number">1</span>, <span class="built_in">vector</span>&lt;<span class="type">int</span>&gt;(n + <span class="number">2</span>, -INF));</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> l = <span class="number">1</span>; l &lt;= n; l++) &#123;</span><br><span class="line"><span class="function">vector&lt;<span class="type">int</span>&gt; <span class="title">cnt</span><span class="params">(n + <span class="number">1</span>, <span class="number">0</span>)</span></span>;</span><br><span class="line"><span class="type">int</span> mn = INF;</span><br><span class="line"><span class="type">int</span> mx = -INF;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> r = l; r &lt;= n; r++) &#123;</span><br><span class="line"><span class="type">int</span> tem = a[r];</span><br><span class="line">cnt[tem]++;</span><br><span class="line"><span class="keyword">if</span> (cnt[tem] &gt; <span class="number">1</span>) &#123; <span class="comment">//如果出现相同的数了，那一定不是good序列</span></span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">&#125;</span><br><span class="line">mn = <span class="built_in">min</span>(mn, tem);</span><br><span class="line">mx = <span class="built_in">max</span>(mx, tem);</span><br><span class="line"><span class="keyword">if</span> (mx - mn + <span class="number">1</span> == r - l + <span class="number">1</span>) &#123; <span class="comment">//说明此序列是一个good序列</span></span><br><span class="line">lpos[mx - mn + <span class="number">1</span>][mn] = <span class="built_in">min</span>(l, lpos[mx - mn + <span class="number">1</span>][mn]);</span><br><span class="line">rpos[mx - mn + <span class="number">1</span>][mn] = <span class="built_in">max</span>(l, rpos[mx - mn + <span class="number">1</span>][mn]);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">int</span> ans = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> len = <span class="number">0</span>; len &lt;= n / <span class="number">2</span>; len++) &#123;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> x = <span class="number">1</span>; x &lt;= n; x++) &#123;</span><br><span class="line"><span class="type">int</span> flag = (lpos[len][x] != INF);</span><br><span class="line"><span class="keyword">if</span> (!flag) &#123;</span><br><span class="line"><span class="keyword">continue</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 判断是否能选到两个不重叠的子段</span></span><br><span class="line"><span class="comment">// 一边取最靠左，另一边取最靠右。</span></span><br><span class="line"><span class="comment">// 如果起点差 &gt;= len，则两个长度为 len 的子段不重叠。</span></span><br><span class="line"><span class="type">int</span> flag3 = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">if</span> (<span class="built_in">abs</span>(lpos[len][x] - rpos[len][x + len]) &gt;= len &amp;&amp; rpos[len][x + len] != -INF)</span><br><span class="line">flag3 = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (flag3) ans = <span class="built_in">max</span>(ans, len);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">cout &lt;&lt; ans;</span><br><span class="line">cout &lt;&lt; <span class="string">&#x27;\n&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://tysweb.pages.dev/2026/06/20/Codeforces%20Round%201103%20(Div.%203)/</id>
    <link href="https://tysweb.pages.dev/2026/06/20/Codeforces%20Round%201103%20(Div.%203)/"/>
    <published>2026-06-20T03:25:17.000Z</published>
    <summary>
      <![CDATA[<p><a href="https://codeforces.com/contest/2236">题目地址</a></p>
<h1 id="A-Games-on-the-Train"><a href="#A-Games-on-the-Train" class="headerlin]]>
    </summary>
    <title>Codeforces Round 1103 (Div. 3)</title>
    <updated>2026-09-07T01:31:21.817Z</updated>
  </entry>
  <entry>
    <author>
      <name>ctyyy</name>
    </author>
    <category term="算法题" scheme="https://tysweb.pages.dev/categories/%E7%AE%97%E6%B3%95%E9%A2%98/"/>
    <category term="算法" scheme="https://tysweb.pages.dev/tags/%E7%AE%97%E6%B3%95/"/>
    <category term="LeetCode" scheme="https://tysweb.pages.dev/tags/LeetCode/"/>
    <content>
      <![CDATA[<h1 id="1-两数之和"><a href="#1-两数之和" class="headerlink" title="1.两数之和"></a>1.<a href="https://leetcode.cn/problems/two-sum/description/?envType=study-plan-v2&envId=top-100-liked">两数之和</a></h1>]]>
    </content>
    <id>https://tysweb.pages.dev/2026/06/19/LeetCodeHot100/</id>
    <link href="https://tysweb.pages.dev/2026/06/19/LeetCodeHot100/"/>
    <published>2026-06-19T06:17:10.000Z</published>
    <summary>
      <![CDATA[<h1 id="1-两数之和"><a href="#1-两数之和" class="headerlink" title="1.两数之和"></a>1.<a href="https://leetcode.cn/problems/two-sum/description/?envType]]>
    </summary>
    <title>LeetCodeHot100</title>
    <updated>2026-09-07T01:31:21.829Z</updated>
  </entry>
  <entry>
    <author>
      <name>ctyyy</name>
    </author>
    <category term="大模型" scheme="https://tysweb.pages.dev/categories/%E5%A4%A7%E6%A8%A1%E5%9E%8B/"/>
    <category term="AI" scheme="https://tysweb.pages.dev/tags/AI/"/>
    <category term="Codex" scheme="https://tysweb.pages.dev/tags/Codex/"/>
    <content>
      <![CDATA[<p>Codex是2025年10月<a href="https://baike.baidu.com/item/OpenAI/19758408?fromModule=lemma_inlink">OpenAI</a>公司开发的AI代码生成训练模型，基于<a href="https://baike.baidu.com/item/GPT-3/63687636?fromModule=lemma_inlink">GPT-3</a>架构改进，专注于将自然语言指令转换为多种编程语言代码。该模型通过混合训练自然语言和公开代码数据构建，采用<a href="https://baike.baidu.com/item/Transformer/64429264?fromModule=lemma_inlink">Transformer</a>架构并具备14KB代码记忆容量，支持<a href="https://baike.baidu.com/item/Python/407313?fromModule=lemma_inlink">Python</a>、<a href="https://baike.baidu.com/item/JavaScript/321142?fromModule=lemma_inlink">JavaScript</a>、<a href="https://baike.baidu.com/item/Java/85979?fromModule=lemma_inlink">Java</a>等主流语言，作为[GitHub Copilot](<a href="https://baike.baidu.com/item/GitHub">https://baike.baidu.com/item/GitHub</a> Copilot&#x2F;57754203?fromModule&#x3D;lemma_inlink)的技术基础，核心功能包括代码生成、补全优化及多语言翻译。2025年5月升级为云端软件工程代理后，新增并行处理代码编写、调试和测试功能，集成至<a href="https://baike.baidu.com/item/ChatGPT/62446358?fromModule=lemma_inlink">ChatGPT</a>生态并向企业用户开放。同年6月通过ChatGPT Codex子系统实现多方案生成功能，允许用户为单一任务获取多个代码方案并自主选择最优解。</p><p><img src="/2026/06/15/Codex/image-20260615222538979.png" alt="image-20260615222538979"></p><h1 id="术语介绍"><a href="#术语介绍" class="headerlink" title="术语介绍"></a>术语介绍</h1><h2 id="VPN（魔法，科学上网）"><a href="#VPN（魔法，科学上网）" class="headerlink" title="VPN（魔法，科学上网）"></a>VPN（魔法，科学上网）</h2><p>vpn的本质为<strong>封装</strong>（把一个 IP 数据报塞进另一个 IP 数据报的载荷里）+ <strong>加密</strong>（让外面那个数据报的载荷不可读）。例如访问<code>blocked-site.com</code></p><h3 id="不开vpn的网络传输流程"><a href="#不开vpn的网络传输流程" class="headerlink" title="不开vpn的网络传输流程"></a>不开vpn的网络传输流程</h3><p>当不用vpn的时候，数据报的样子为：</p><p><img src="/2026/06/15/Codex/image-20260716184659477.png" alt="image-20260716184659477"></p><p>其中GFW可以看到</p><ul><li>IP 头里的 <strong>目标 IP</strong> —— 判断是否在黑名单</li><li>TLS 握手里的 <strong>SNI</strong>（Server Name Indication，明文传输）—— 直接看到你要访问哪个域名</li><li>甚至可以做 <strong>DPI</strong>（深度包检测），分析载荷特征</li></ul><p>然后 GFW 发一个 RST 包，或者直接丢包，连接就断开了。</p><h3 id="开vpn的网络传输流程"><a href="#开vpn的网络传输流程" class="headerlink" title="开vpn的网络传输流程"></a>开vpn的网络传输流程</h3><ol><li><p>首先VPN 客户端启动时，会在你的系统里创建一个<strong>虚拟网络接口</strong>（TUN 设备，比如 <code>tun0</code>），然后<strong>修改路由表</strong>，把默认路由（或特定 IP 段）指向 <code>tun0</code>：<code>default via tun0          ← 所有流量先走虚拟网卡</code></p><p>于是当你的浏览器发出上面那个数据报时，OS 的网络栈不会把它送到物理网卡（<code>wlan0</code>），而是送给 <code>tun0</code>。而 <code>tun0</code> 的特点是：<strong>发到它的数据报不会上线路，而是被交给了 VPN 客户端进程</strong>（用户态程序通过 <code>read()</code> 从 TUN fd 读取）。</p></li><li><p>VPN 客户端拿到了那个原始数据报，做两件事：</p><ol><li><strong>加密</strong>：把整个原始 IP 数据报（包括 IP 头）用对称密钥加密</li><li><strong>封装</strong>：把加密后的密文，作为载荷塞进一个全新的数据报里</li></ol><p>结果是这样的（以 tunnel 模式为例）：</p><p><img src="/2026/06/15/Codex/image-20260716185728158.png" alt="image-20260716185728158"></p></li><li><p>这个外层数据报从物理网卡（<code>wlan0</code>）正常发出，经过你的运营商到达 VPN 服务器。</p></li><li><p>VPN 服务器收到外层数据报后：</p><ol><li>看到外层 IP 头的 dst 是自己 → 接收</li><li>检查 VPN 协议头 → 确认是 VPN 隧道流量</li><li>解密载荷 → 还原出内层那个原始数据报</li><li>把内层 IP 头的 src 改成 VPN 服务器自己的 IP（NAT），然后直接转发给目标网站</li></ol></li><li><p>目标网站的响应包发回 VPN 服务器（因为请求的 src 被 NAT 成了服务器 IP），服务器再走一遍反向流程：加密 → 封装 → 发回给你 → 你的客户端解密 → 写回 <code>tun0</code> → OS 交付给浏览器。</p></li></ol><h3 id="为什么VPN能绕过GFW？"><a href="#为什么VPN能绕过GFW？" class="headerlink" title="为什么VPN能绕过GFW？"></a>为什么VPN能绕过GFW？</h3><p>GFW 面临的核心困境确实是一个<strong>误杀问题</strong>（false positive）。它不能无差别丢弃所有去往境外 IP 的加密流量，原因是：</p><ul><li>大量合法服务在境外：GitHub、AWS、Cloudflare CDN、Docker Hub、各种 SaaS</li><li>跨国企业的内网通信、视频会议（Zoom、Teams）都走加密通道</li><li>学术机构访问海外数据库、期刊</li></ul><p>如果 GFW 把”加密 + 境外 IP”一刀切全封掉，经济损失太大。<strong>这个”不敢乱封”的约束，恰恰就是 VPN 能存活的空间。</strong></p><h2 id="大模型和Agent"><a href="#大模型和Agent" class="headerlink" title="大模型和Agent"></a>大模型和Agent</h2><h3 id="Agent"><a href="#Agent" class="headerlink" title="Agent"></a>Agent</h3><p>Agent 是一个<strong>能感知环境、自主决策、采取行动来完成目标的系统</strong>。早期基于规则的自动机器人、游戏 NPC 也叫 agent。只是在 LLM 出现后，”AI agent”才真正有了实用的”大脑”。</p><p>一个完整 agent 通常包含这几个部分：</p><ul><li>感知：从环境获取信息–读文件、收消息、看屏幕、调 API 拿数据</li><li>决策：根据当前目标和感知到的信息，决定下一步做什么。现代 agent 的决策核心通常是大模型，但也可以是规则引擎、搜索算法等</li><li>执行：执行具体操作–调用工具、运行代码、修改文件、发请求、控制设备</li><li>记忆：短期记忆保存当前任务的上下文，长期记忆（向量库、数据库）保存跨会话的信息</li><li>规划：把大目标拆成小步骤，执行后根据结果反馈调整计划，形成”思考→行动→观察→再思考”的循环</li><li>自主性：这是 agent 和普通程序的核心区别–不是你一步步指挥它做什么，而是你给个目标，它自己决定怎么做</li></ul><p>常见的Agent：Codex，Cluadecode。</p><h3 id="大模型"><a href="#大模型" class="headerlink" title="大模型"></a>大模型</h3><p>本质是一个超大规模的神经网络，用海量文本训练出来，核心能力是<strong>根据输入预测下一段文字</strong>。它不”理解”世界，而是学会了语言的统计规律–什么词后面最可能跟什么词、什么问题最可能配什么回答。</p><p>几个关键特点：</p><ul><li>输入输出都是文本：给它文字，它回文字，仅此而已。所谓”会写代码””会推理”，都是文本生成的表现</li><li>训练完就定型：模型参数固定后，它的知识就停在训练数据截止那天，不会自己更新</li><li>无状态：每次调用都是独立的，它不记得你上一轮说了啥，所谓”对话”是靠每次把历史拼进上下文实现的</li><li>不能行动：纯模型只能输出文字，改不了文件、发不了邮件、连不了网</li><li>规模是关键：参数量、训练数据量到了一定规模，会涌现出小模型没有的能力（推理、指令遵循、少样本学习），这就是”涌现能力”</li></ul><p>常见的大模型：GPT-4、Claude、Gemini、LLaMA、Qwen、DeepSeek 等。</p><h3 id="两者的关系"><a href="#两者的关系" class="headerlink" title="两者的关系"></a>两者的关系</h3><p>大模型像是一个博学但被困在玻璃房里的人——你递纸条进去问问题，他写纸条递出来，但碰不到外面的任何东西。</p><p>Agent 就是给这个人开了门、装了电话、配了工具箱，还让他可以自己决定先做哪件事。他还是用同一个大脑思考，但能真正把事办成。</p><p>大模型决定了 agent 能力的上限，Agent决定了它能发挥出多少。同一个 GPT-5，配简陋工具就是个聊天机器人，配上完整工具链和好的规划逻辑，就是个能干活的 agent。</p><h2 id="API中转站"><a href="#API中转站" class="headerlink" title="API中转站"></a>API中转站</h2><p>比如<a href="https://cloud.siliconflow.cn/i/yTIkLdxx">硅基流动</a>，火山方舟等一系列中转站。</p><p><strong>为什么有人用它</strong></p><p>很多大模型官方 API（比如 OpenAI）在国内无法直接访问，中转站部署在能访问的网络环境里，帮你绕开这个障碍，并且支持多个模型（GPT、Claude、Gemini），用同一个 <strong>APIkey</strong> 调用，特别省事。</p><p><strong>它的工作流程</strong></p><ol><li><strong>你的程序把请求发到中转站的地址（比如 <code>https://xxx.com/v1/chat/completions</code>）</strong></li><li>中转站用自己的 key 转发给官方 API</li><li>官方返回结果，中转站再转发给你</li></ol><p><strong>需要注意的风险</strong></p><p>你发给中转站的内容会被它的服务器看到，隐私数据可能经第三方的手。并且中转站可能挂羊头卖狗肉。</p><h2 id="Agent管理工具"><a href="#Agent管理工具" class="headerlink" title="Agent管理工具"></a><strong>Agent管理工具</strong></h2><h3 id="CC-Switch"><a href="#CC-Switch" class="headerlink" title="CC Switch"></a>CC Switch</h3><p>CC Switch是跨平台开源的‌<strong>AI 编程 CLI 统一配置管理与路由代理工具</strong>‌，支持多工具（Codex&#x2F;Claude Code 等）一键切换供应商。有了CCswitch，我们就不用在命令窗口一个一个配置Agent了</p><h3 id="Codex"><a href="#Codex" class="headerlink" title="Codex++"></a><strong>Codex++</strong></h3><p>‌是专为 OpenAI Codex 桌面端打造的外部增强启动器与 UI 功能解锁工具 。‌‌其主要功能是解锁codex的插件（原生codex无法加载一些插件，如computeruse，chrome等）</p><h1 id="下载步骤"><a href="#下载步骤" class="headerlink" title="下载步骤"></a>下载步骤</h1><h2 id="命令行下载（Codex-CLI）"><a href="#命令行下载（Codex-CLI）" class="headerlink" title="命令行下载（Codex CLI）"></a>命令行下载（Codex CLI）</h2><p>根据此安装方式可以从终端调用codex，但是没有UI界面</p><p><code>npm install -g @openai/codex</code></p><p><img src="/2026/06/15/Codex/image-20260615152335348.png" alt="image-20260615152335348"></p><h2 id="官网下载"><a href="#官网下载" class="headerlink" title="官网下载"></a>官网下载</h2><p><a href="https://openai.com/zh-Hans-CN/codex/%EF%BC%88%E9%9C%80%E8%A6%81%E9%AD%94%E6%B3%95%EF%BC%89%E4%B9%9F%E5%8F%AF%E7%9B%B4%E6%8E%A5%E4%BB%8EMicrosoft">https://openai.com/zh-Hans-CN/codex/（需要魔法）也可直接从Microsoft</a> Store下载</p><p><img src="/2026/06/15/Codex/image-20260716205700212.png" alt="image-20260716205700212"></p><p><img src="/2026/06/15/Codex/image-20260615152316000.png" alt="image-20260615152316000"></p><h1 id="登录"><a href="#登录" class="headerlink" title="登录"></a>登录</h1><p><strong>命令行进入的场景 即Codex CLI</strong></p><p>输入codex自动进入登陆界面，大部分情况用用自己的APIkey登录，也就是Provide your own APIkey.</p><p><img src="/2026/06/15/Codex/image-20260615153155820.png" alt="image-20260615153155820"></p><p>登录后，认证信息会保存在<code>~/.codex/auth.json</code> 文件中</p><p><strong>UI界面进入的场景</strong></p><p>点击桌面的codex，可以选择用APIkey和用OpenAI的Chatgpt登录，大部分情况用用自己的APIkey登录，也就是Enter API key</p><p><img src="/2026/06/15/Codex/image-20260716210636972.png" alt="image-20260716210636972"></p><h1 id="一些Question"><a href="#一些Question" class="headerlink" title="一些Question"></a>一些Question</h1><h2 id="关于本地路由映射"><a href="#关于本地路由映射" class="headerlink" title="关于本地路由映射"></a>关于本地路由映射</h2><p><strong>Q：用自己的APIkey，Codex返回response错误</strong></p><p>Codex（OpenAI 的代码助手 CLI）<strong>原生只支持 OpenAI 自己的 Responses API 和 GPT 系列模型</strong>，它本身不认识 DeepSeek、Kimi 这类第三方模型，也不认识 CodingPlan 的 API。</p><p><img src="/2026/06/15/Codex/image-20260615163317770.png" alt="image-20260615163317770"></p><p>开启了「需要本地路由映射」，CC-Switch 正在做一件事：</p><ul><li>把你输入的 CodingPlan API，<strong>伪装成 Codex 能识别的 OpenAI 协议</strong>，让 Codex 以为自己在调用 GPT 模型</li><li>Codex 只知道 “这是一个 OpenAI 风格的模型”，就会默认显示它最高支持的模型名（比如 GPT-5.5），<strong>这不是你实际开通了这个模型，只是 Codex 的默认显示</strong>。只是 CC-Switch 做了协议兼容后，Codex 自己 “脑补” 出来的模型名，和 CodingPlan 实际提供的模型无关</li></ul><p><span style="color:#FF00FF">那么ccswitch提供的自添加模型名就是修改codex给你显示的他所认为的模型名为实际调用的模型名称</span></p><p><img src="/2026/06/15/Codex/image-20260615164311228.png" alt="image-20260615164311228"></p><h2 id="手机验证码问题"><a href="#手机验证码问题" class="headerlink" title="手机验证码问题"></a>手机验证码问题</h2><p><strong>Q：在注册ChatGPT的时候，需要国外的手机验证码</strong></p><p><img src="/2026/06/15/Codex/image-20260615205123522.png" alt="image-20260615205123522"></p><p>目前主流的绕开验证码的方式全都失效了，唯一能用的就是接码平台了。但是接码平台的号码无法二次验证。很可能有二次验证的时候这个号就废了。看看以后会不会有更好的解决方法。<strong>目前先用第三方API吧</strong></p><h2 id="重新连接5-5"><a href="#重新连接5-5" class="headerlink" title="重新连接5&#x2F;5"></a>重新连接5&#x2F;5</h2><p><img src="/2026/06/15/Codex/image-20260615210046180.png" alt="image-20260615210046180"></p><p>这种情况就是开梯子了，VPN 开启时会自动写入系统全局代理环境变量 <code>HTTP_PROXY / HTTPS_PROXY</code>； Codex、Ccswitch 会自动读取这组变量，强行把本地路由请求再次走外网代理，链路彻底断裂。</p>]]>
    </content>
    <id>https://tysweb.pages.dev/2026/06/15/Codex/</id>
    <link href="https://tysweb.pages.dev/2026/06/15/Codex/"/>
    <published>2026-06-15T07:03:43.000Z</published>
    <summary>
      <![CDATA[<p>Codex是2025年10月<a href="https://baike.baidu.com/item/OpenAI/19758408?fromModule=lemma_inlink">OpenAI</a>公司开发的AI代码生成训练模型，基于<a href="https:/]]>
    </summary>
    <title>Codex</title>
    <updated>2026-09-07T01:31:21.823Z</updated>
  </entry>
  <entry>
    <author>
      <name>ctyyy</name>
    </author>
    <category term="大模型" scheme="https://tysweb.pages.dev/categories/%E5%A4%A7%E6%A8%A1%E5%9E%8B/"/>
    <category term="AI" scheme="https://tysweb.pages.dev/tags/AI/"/>
    <category term="PyTorch" scheme="https://tysweb.pages.dev/tags/PyTorch/"/>
    <content>
      <![CDATA[<p>PyTorch是一个用于机器学习和深度学习的开源深度学习框架，由Facebook于2016年发布，其主要实现了自动微分功能，并引入动态计算图使模型建立更加灵活。Pytorch可分为前后端两个部分，前端是与用户直接交互的python API，后端是框架内部实现的部分，包括Autograd，它是一个自动微分引擎。</p><p>Pytorch基于已有的张量库Torch开发，在PyTorch的早期版本中，使用的是Torch7，后来随着PyTorch的发展，逐渐演变成了PyTorch所使用的张量库。</p><p>现如今，Pytorch已经成为开源机器学习系统中，在科研领域市场占有率最高的框架，其在AI顶会上的占比在2022年已达80％ 。</p><h1 id="张量的类型转换"><a href="#张量的类型转换" class="headerlink" title="张量的类型转换"></a>张量的类型转换</h1><h2 id="张量转换NumPy数组"><a href="#张量转换NumPy数组" class="headerlink" title="张量转换NumPy数组"></a>张量转换NumPy数组</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">dem02</span>():</span><br><span class="line">    t1 = torch.tensor([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>])</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;t1: <span class="subst">&#123;t1&#125;</span>, type: <span class="subst">&#123;<span class="built_in">type</span>(t1)&#125;</span>&#x27;</span>)</span><br><span class="line">    <span class="comment"># 2.张量-&gt; numpy.</span></span><br><span class="line">    n1 = t1.numpy()</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;n1: <span class="subst">&#123;n1&#125;</span>, type: <span class="subst">&#123;<span class="built_in">type</span>(n1)&#125;</span>&#x27;</span>)</span><br><span class="line">    <span class="comment"># 3.演示上述方式 共享内存。</span></span><br><span class="line">    n1[<span class="number">0</span>] = <span class="number">100</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;t1: <span class="subst">&#123;t1&#125;</span>&#x27;</span>) <span class="comment"># [100, 2, 3, 4, 5]</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;n1: <span class="subst">&#123;n1&#125;</span>&#x27;</span>) <span class="comment"># [100, 2, 3, 4, 5]</span></span><br></pre></td></tr></table></figure><h2 id="NumPy数组转换张量"><a href="#NumPy数组转换张量" class="headerlink" title="NumPy数组转换张量"></a>NumPy数组转换张量</h2><ul><li>使用from_ numpy 可以将ndarray数组转换为Tensor，默认共享内存，使用 copy 函数避免共享。</li><li>使用 torch.tensor 可以将 ndarray 数组转换为 Tensor，默认不共享内存。（用的多）</li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">dem02</span>():</span><br><span class="line">    <span class="comment"># 1.创建numpy数组</span></span><br><span class="line">    n1 = np.array([<span class="number">11</span>, <span class="number">22</span>, <span class="number">33</span>])</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;n1:<span class="subst">&#123;n1&#125;</span>,type:<span class="subst">&#123;<span class="built_in">type</span>(n1)&#125;</span>&#x27;</span>)</span><br><span class="line">    <span class="comment"># 2.把上述的numpy数组，转换成张量.</span></span><br><span class="line">    t1 = torch.from_numpy(n1).<span class="built_in">type</span>(torch.float32)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;t1: <span class="subst">&#123;t1&#125;</span>, type: <span class="subst">&#123;<span class="built_in">type</span>(t1)&#125;</span>&#x27;</span>)</span><br><span class="line">    t1 = t1.numpy()  <span class="comment"># 把t1转换回numpy，然后演示tensor函数的效果</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;t1: <span class="subst">&#123;t1&#125;</span>, type: <span class="subst">&#123;<span class="built_in">type</span>(t1)&#125;</span>&#x27;</span>)</span><br><span class="line">    t1 = torch.tensor(n1, dtype=torch.float32)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;t1: <span class="subst">&#123;t1&#125;</span>, type: <span class="subst">&#123;<span class="built_in">type</span>(t1)&#125;</span>&#x27;</span>)</span><br></pre></td></tr></table></figure><h2 id="从张量中提取内容"><a href="#从张量中提取内容" class="headerlink" title="从张量中提取内容"></a>从张量中提取内容</h2><p>只能从标量张量中提取内容。也就是这个张量中只能有一个值</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">dem02</span>():</span><br><span class="line">    t1=torch.tensor(<span class="number">100</span>);</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;t1: <span class="subst">&#123;t1&#125;</span>,type:<span class="subst">&#123;<span class="built_in">type</span>(t1)&#125;</span>&#x27;</span>)</span><br><span class="line">    value = t1.item()</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;value: <span class="subst">&#123;value&#125;</span>,type:<span class="subst">&#123;<span class="built_in">type</span>(value)&#125;</span>&#x27;</span>)</span><br></pre></td></tr></table></figure><h1 id="张量的数值计算"><a href="#张量的数值计算" class="headerlink" title="张量的数值计算"></a>张量的数值计算</h1><h2 id="基本运算"><a href="#基本运算" class="headerlink" title="基本运算"></a>基本运算</h2><h3 id="加减乘除"><a href="#加减乘除" class="headerlink" title="加减乘除"></a>加减乘除</h3><p>涉及到的API:</p><ul><li>add(), sub(), mul(), div(), neg()    加减乘除,取反substact，multiply，divide</li><li>add_(), sub_(), mul_() div_(), neg_(）功能同上，只不过可以修改源数据，类似于 Pandas部分的inplace&#x3D;True</li></ul><p>需要你记忆的: +，-，*，&#x2F;</p><p>如果是张量和数值运算，则:该数值会和张量中的每个值依次进行 对应的运算. </p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">dem02</span>():</span><br><span class="line">    t1=torch.tensor([<span class="number">10</span>,<span class="number">12</span>,<span class="number">13</span>]);</span><br><span class="line">    t1+=<span class="number">10</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;t1: <span class="subst">&#123;t1&#125;</span>&#x27;</span>)</span><br></pre></td></tr></table></figure><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260605101130635.png"></p><h3 id="幂运算：pow-、pow"><a href="#幂运算：pow-、pow" class="headerlink" title="幂运算：pow()、pow_()"></a>幂运算：pow()、pow_()</h3><p>接口：<code>Tensor ** exponent</code> &#x2F; <code>Tensor.pow(exponent)</code> &#x2F; <code>Tensor.pow_(exponent)</code></p><p>功能：逐元素求幂。<code>pow()</code> 返回新张量，<code>pow_()</code> 为 in-place。</p><p>参数：<code>exponent</code>：指数（标量或与张量可广播的张量）</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line">tensor1 = torch.tensor([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>])</span><br><span class="line"><span class="built_in">print</span>(tensor1 ** <span class="number">2</span>)   <span class="comment"># tensor([1, 4, 9])</span></span><br><span class="line"><span class="built_in">print</span>(tensor1.<span class="built_in">pow</span>(<span class="number">2</span>)) <span class="comment"># 同上</span></span><br><span class="line">tensor1.pow_(<span class="number">2</span>)       <span class="comment"># in-place</span></span><br><span class="line"><span class="built_in">print</span>(tensor1)        <span class="comment"># tensor([1, 4, 9])</span></span><br></pre></td></tr></table></figure><h3 id="求平方根：sqrt-、sqrt"><a href="#求平方根：sqrt-、sqrt" class="headerlink" title="求平方根：sqrt()、sqrt_()"></a>求平方根：sqrt()、sqrt_()</h3><p>接口：<code>Tensor.sqrt()</code> &#x2F; <code>Tensor.sqrt_()</code></p><p>功能：逐元素平方根。<code>sqrt()</code> 返回新张量，<code>sqrt_()</code> 为 in-place。</p><p>参数：无</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line">tensor1 = torch.tensor([<span class="number">1.0</span>, <span class="number">2.0</span>, <span class="number">3.0</span>])</span><br><span class="line"><span class="built_in">print</span>(tensor1.sqrt())  <span class="comment"># tensor([1., 1.414..., 1.732...])</span></span><br><span class="line">tensor1.sqrt_()</span><br><span class="line"><span class="built_in">print</span>(tensor1)</span><br></pre></td></tr></table></figure><h3 id="以-e-为底：exp-、log"><a href="#以-e-为底：exp-、log" class="headerlink" title="以 e 为底：exp()、log()"></a>以 e 为底：exp()、log()</h3><p>接口：<code>Tensor.exp()</code> &#x2F; <code>Tensor.exp_()</code>、<code>Tensor.log()</code> &#x2F; <code>Tensor.log_()</code></p><p>功能：逐元素以 e 为底求幂（exp）或求自然对数（log）。带下划线版本为 in-place。</p><p>参数：无</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line">tensor1 = torch.tensor([<span class="number">1.0</span>, <span class="number">2.0</span>, <span class="number">3.0</span>])</span><br><span class="line"><span class="built_in">print</span>(tensor1.exp())  <span class="comment"># e^1, e^2, e^3</span></span><br><span class="line"><span class="built_in">print</span>(tensor1.log())  <span class="comment"># ln(1), ln(2), ln(3)</span></span><br></pre></td></tr></table></figure><h3 id="哈达玛积（逐元素乘法）"><a href="#哈达玛积（逐元素乘法）" class="headerlink" title="哈达玛积（逐元素乘法）"></a>哈达玛积（逐元素乘法）</h3><p>接口：<code>*</code>、<code>Tensor.mul(other)</code></p><p>功能：两张量形状相同或可广播时，对应位置相乘（Hadamard product），与矩阵乘法不同。</p><p>参数：<code>other</code>：张量或标量</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line">tensor1 = torch.tensor([[<span class="number">1</span>, <span class="number">2</span>], [<span class="number">3</span>, <span class="number">4</span>]])</span><br><span class="line">tensor2 = torch.tensor([[<span class="number">1</span>, <span class="number">2</span>], [<span class="number">3</span>, <span class="number">4</span>]])</span><br><span class="line"><span class="built_in">print</span>(tensor1 * tensor2)   <span class="comment"># [[1,4],[9,16]]</span></span><br><span class="line"><span class="built_in">print</span>(tensor1.mul(tensor2)) <span class="comment"># 同上</span></span><br></pre></td></tr></table></figure><h2 id="矩阵乘法运算"><a href="#矩阵乘法运算" class="headerlink" title="矩阵乘法运算"></a>矩阵乘法运算</h2><ol><li><p>点乘：<br>要求：两个张量的维度保持一致，对应元素直接做相应的操作.<br>API:</p><ul><li><code>t1 * t2</code></li><li><code>t1.mul(t2)</code>  # multiply: 乘法</li></ul></li><li><p>矩阵乘法：<br>要求：两个张量，第一个张量的列数，等于第二个张量 的行数(A列 &#x3D; B行)<br>结果：A行B列<br>API:</p><ul><li><code>t1 @ t2</code></li><li><code>t1.matmul(t2)</code></li><li><code>t1.dot(t2)</code> 扩展：只针对于一维张量有效.</li></ul></li></ol><p>注意：</p><p><code>X = X @ Y</code> 会先分配新张量再赋给 <code>X</code>；若之后不再使用原来的 <code>X</code>，可用 <code>X[:] = X @ Y</code> 在原有存储上写入，减少一次分配。确保右边的结果能够正确地广播到左边指定的形状。如果形状不匹配，则会导致错误。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line">X = torch.randint(<span class="number">1</span>, <span class="number">9</span>, (<span class="number">3</span>, <span class="number">2</span>, <span class="number">4</span>))</span><br><span class="line">Y = torch.randint(<span class="number">1</span>, <span class="number">9</span>, (<span class="number">3</span>, <span class="number">4</span>, <span class="number">1</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">id</span>(X))</span><br><span class="line">X = X @ Y      <span class="comment"># X 指向新对象，原内存可被回收</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">id</span>(X))   <span class="comment"># 与上面不同</span></span><br><span class="line"></span><br><span class="line">X = torch.randint(<span class="number">1</span>, <span class="number">9</span>, (<span class="number">3</span>, <span class="number">2</span>, <span class="number">4</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">id</span>(X))</span><br><span class="line">X[:] = X @ Y   <span class="comment"># 结果写回 X 的存储，id(X) 不变</span></span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">id</span>(X))</span><br></pre></td></tr></table></figure><h1 id="张量的索引操作"><a href="#张量的索引操作" class="headerlink" title="张量的索引操作"></a>张量的索引操作</h1><h2 id="简单索引与切片"><a href="#简单索引与切片" class="headerlink" title="简单索引与切片"></a>简单索引与切片</h2><p>接口：<code>tensor[i]</code>、<code>tensor[:, j]</code>、<code>tensor[i:j, k:l]</code> 等下标与切片语法</p><p>功能：单整数索引会使该维消失（降维）；切片保留该维；<code>:</code> 表示该维全选。</p><p>参数：<code>i</code>、<code>j</code> 等为整数或切片（start​:end:step），支持负索引。</p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">tensor1 = torch.randint(<span class="number">1</span>, <span class="number">9</span>, (<span class="number">3</span>, <span class="number">5</span>, <span class="number">4</span>)) </span><br><span class="line"><span class="comment">#这行代码的意思是：创建一个形状为 (3, 5, 4) 的三维张量（Tensor），其中的元素是从 1 到 8 之间的随机整数。</span></span><br><span class="line"><span class="built_in">print</span>(tensor1[<span class="number">0</span>].shape)      <span class="comment"># (5, 4)：取第 0 维为 0 的片</span></span><br><span class="line"><span class="built_in">print</span>(tensor1[:, <span class="number">1</span>].shape)   <span class="comment"># (3, 4)：第 1 维取 1</span></span><br><span class="line"><span class="built_in">print</span>(tensor1[<span class="number">2</span>, <span class="number">1</span>, <span class="number">3</span>])      <span class="comment"># 标量</span></span><br><span class="line"><span class="built_in">print</span>(tensor1[<span class="number">1</span>:, <span class="number">1</span>:<span class="number">4</span>, <span class="number">0</span>:<span class="number">3</span>].shape)  <span class="comment"># (2, 3, 3)：切片</span></span><br></pre></td></tr></table></figure><h2 id="⭐列表索引"><a href="#⭐列表索引" class="headerlink" title="⭐列表索引"></a>⭐列表索引</h2><p>接口：<code>tensor[[i1,i2,...],[j1,j2,...],...]</code> 等，下标为整数张量或列表。</p><ul><li><p>：表示选择当前所有行&#x2F;列</p></li><li><p><code>tensor[[[1],[2]],[3,4]]</code>:代表把第2行的3，4两列和第3行的3，4两列读出来</p></li><li><p><span style="color:#FF00FF"><code>tensor[:, tensor[2]&gt;5]</code>：</span></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># tensor[2] &gt; 5 仅以第3个矩阵（索引2）为条件，生成布尔掩码。</span></span><br><span class="line"><span class="comment"># 但 tensor[:, mask] 会在所有矩阵（第1、第2、第3个）的相同位置提取数据，而不管其他矩阵在这    些位置的值是否满足&gt;5</span></span><br><span class="line"><span class="comment"># 结果是所有矩阵在第3个矩阵满足条件的那些位置上的值（共7个位置）。</span></span><br><span class="line"><span class="comment"># 只有第3个矩阵的对应值保证 &gt;5，而第1、第2个矩阵的值只是巧合出现在这些位置，可能完全不符合      &gt;5 的条件。</span></span><br><span class="line">   tensor = torch.tensor([</span><br><span class="line">       [[<span class="number">7</span>, <span class="number">1</span>, <span class="number">4</span>, <span class="number">4</span>],</span><br><span class="line">        [<span class="number">4</span>, <span class="number">8</span>, <span class="number">2</span>, <span class="number">8</span>],</span><br><span class="line">        [<span class="number">7</span>, <span class="number">8</span>, <span class="number">7</span>, <span class="number">2</span>],</span><br><span class="line">        [<span class="number">2</span>, <span class="number">2</span>, <span class="number">7</span>, <span class="number">8</span>],</span><br><span class="line">        [<span class="number">7</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">2</span>]],</span><br><span class="line">  </span><br><span class="line">       [[<span class="number">1</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">3</span>],</span><br><span class="line">        [<span class="number">7</span>, <span class="number">5</span>, <span class="number">7</span>, <span class="number">3</span>],</span><br><span class="line">        [<span class="number">5</span>, <span class="number">8</span>, <span class="number">8</span>, <span class="number">2</span>],</span><br><span class="line">        [<span class="number">7</span>, <span class="number">4</span>, <span class="number">6</span>, <span class="number">7</span>],</span><br><span class="line">        [<span class="number">5</span>, <span class="number">5</span>, <span class="number">4</span>, <span class="number">1</span>]],</span><br><span class="line">        </span><br><span class="line">       [[<span class="number">4</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">7</span>],</span><br><span class="line">        [<span class="number">1</span>, <span class="number">6</span>, <span class="number">8</span>, <span class="number">7</span>],</span><br><span class="line">        [<span class="number">7</span>, <span class="number">1</span>, <span class="number">6</span>, <span class="number">2</span>],</span><br><span class="line">        [<span class="number">4</span>, <span class="number">4</span>, <span class="number">3</span>, <span class="number">1</span>],</span><br><span class="line">        [<span class="number">2</span>, <span class="number">8</span>, <span class="number">1</span>, <span class="number">5</span>]]])</span><br><span class="line">   <span class="built_in">print</span>(tensor[:,tensor[<span class="number">2</span>]&gt;<span class="number">5</span>])</span><br><span class="line">   <span class="comment">#[4, 2, 2, 7],</span></span><br><span class="line">   <span class="comment">#   [1, 6, 8, 7],</span></span><br><span class="line">   <span class="comment">#   [7, 1, 6, 2],</span></span><br><span class="line">   <span class="comment">#   [4, 4, 3, 1],</span></span><br><span class="line">   <span class="comment">#   [2, 8, 1, 5]</span></span><br><span class="line">   <span class="comment">#   [[False, False, False,  True],</span></span><br><span class="line">   <span class="comment"># [False,  True,  True,  True],</span></span><br><span class="line">   <span class="comment"># [ True, False,  True, False],</span></span><br><span class="line">   <span class="comment"># [False, False, False, False],</span></span><br><span class="line">   <span class="comment"># [False,  True, False, False]]</span></span><br><span class="line">   <span class="comment">#得到布尔掩码后返回所有为True的值</span></span><br></pre></td></tr></table></figure></li><li><p><code>t1[:, t1[1, :] &gt; 5]</code>（<code>t1[:, t1[1] &gt; 5]</code>）：<code>t1[1, :] &gt; 5</code>是一个定位，代表选择所有行的第【在矩阵中第二行列数据大于五的】列</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">t1 = torch.tensor([[<span class="number">6</span>, <span class="number">9</span>, <span class="number">9</span>, <span class="number">2</span>, <span class="number">8</span>],</span><br><span class="line">                      [<span class="number">7</span>, <span class="number">8</span>, <span class="number">5</span>, <span class="number">8</span>, <span class="number">4</span>],</span><br><span class="line">                      [<span class="number">7</span>, <span class="number">4</span>, <span class="number">3</span>, <span class="number">9</span>, <span class="number">3</span>],</span><br><span class="line">                      [<span class="number">6</span>, <span class="number">1</span>, <span class="number">4</span>, <span class="number">2</span>, <span class="number">8</span>],</span><br><span class="line">                      [<span class="number">1</span>, <span class="number">2</span>, <span class="number">5</span>, <span class="number">7</span>, <span class="number">4</span>]])</span><br><span class="line">   <span class="built_in">print</span>(t1[:, t1[<span class="number">1</span>, :] &gt; <span class="number">5</span>])</span><br><span class="line">   <span class="comment">#输出所有行的第1，2，4列数据。共5行（所有行），3列</span></span><br><span class="line">   <span class="comment"># tensor([[6, 9, 2],</span></span><br><span class="line">   <span class="comment">#         [7, 8, 8],</span></span><br><span class="line">   <span class="comment">#         [7, 4, 9],</span></span><br><span class="line">   <span class="comment">#         [6, 1, 2],</span></span><br><span class="line">   <span class="comment">#         [1, 2, 7]])</span></span><br></pre></td></tr></table></figure></li></ul><p>功能：多下标按位置配对或广播，可取出不连续或重排后的元素。</p><p>参数：各维传入长度相同的整数序列或可广播的整数张量。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line">   tensor1 = torch.randint(<span class="number">1</span>, <span class="number">9</span>, (<span class="number">3</span>, <span class="number">5</span>, <span class="number">4</span>))</span><br><span class="line">   <span class="comment"># 取 (1,1)、(0,2) 两行</span></span><br><span class="line">   <span class="built_in">print</span>(tensor1)</span><br><span class="line">   <span class="built_in">print</span>(tensor1[[<span class="number">1</span>, <span class="number">0</span>], [<span class="number">1</span>, <span class="number">2</span>]])</span><br><span class="line">   <span class="comment"># [[0],[1]] 与 [1,2] 广播，取 4 个位置，结果形状 (2, 2, 4)</span></span><br><span class="line">   <span class="built_in">print</span>(tensor1[[[<span class="number">0</span>], [<span class="number">1</span>]], [<span class="number">1</span>, <span class="number">2</span>]].shape)</span><br></pre></td></tr></table></figure><p><span style="color:#FF00FF">下面演示一下三维张量的列表索引计算方法</span></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line">tensor = torch.tensor([</span><br><span class="line">       [[<span class="number">7</span>, <span class="number">1</span>, <span class="number">4</span>, <span class="number">4</span>],</span><br><span class="line">        [<span class="number">4</span>, <span class="number">8</span>, <span class="number">2</span>, <span class="number">8</span>],</span><br><span class="line">        [<span class="number">7</span>, <span class="number">8</span>, <span class="number">7</span>, <span class="number">2</span>],</span><br><span class="line">        [<span class="number">2</span>, <span class="number">2</span>, <span class="number">7</span>, <span class="number">8</span>],</span><br><span class="line">        [<span class="number">7</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">2</span>]],</span><br><span class="line"></span><br><span class="line">       [[<span class="number">1</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">3</span>],</span><br><span class="line">        [<span class="number">7</span>, <span class="number">5</span>, <span class="number">7</span>, <span class="number">3</span>],</span><br><span class="line">        [<span class="number">5</span>, <span class="number">8</span>, <span class="number">8</span>, <span class="number">2</span>],</span><br><span class="line">        [<span class="number">7</span>, <span class="number">4</span>, <span class="number">6</span>, <span class="number">7</span>],</span><br><span class="line">        [<span class="number">5</span>, <span class="number">5</span>, <span class="number">4</span>, <span class="number">1</span>]],</span><br><span class="line"></span><br><span class="line">       [[<span class="number">4</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">7</span>],</span><br><span class="line">        [<span class="number">1</span>, <span class="number">6</span>, <span class="number">8</span>, <span class="number">7</span>],</span><br><span class="line">        [<span class="number">7</span>, <span class="number">1</span>, <span class="number">6</span>, <span class="number">2</span>],</span><br><span class="line">        [<span class="number">4</span>, <span class="number">4</span>, <span class="number">3</span>, <span class="number">1</span>],</span><br><span class="line">        [<span class="number">2</span>, <span class="number">8</span>, <span class="number">1</span>, <span class="number">5</span>]]])</span><br><span class="line">   <span class="built_in">print</span>(tensor[[<span class="number">1</span>, <span class="number">0</span>], [<span class="number">1</span>, <span class="number">2</span>]])</span><br><span class="line">    <span class="comment"># 把 tensor 结构拆开：</span></span><br><span class="line">    <span class="comment">#  tensor[0] = [</span></span><br><span class="line">    <span class="comment">#      [7, 1, 4, 4],   # 第0行</span></span><br><span class="line">    <span class="comment">#      [4, 8, 2, 8],   # 第1行 ← tensor[0][1]</span></span><br><span class="line">    <span class="comment">#      [7, 8, 7, 2],   # 第2行</span></span><br><span class="line">    <span class="comment">#      [2, 2, 7, 8],</span></span><br><span class="line">    <span class="comment">#      [7, 2, 2, 2]</span></span><br><span class="line">    <span class="comment">#  ]</span></span><br><span class="line">    <span class="comment">#  tensor[1] = [</span></span><br><span class="line">    <span class="comment">#     [7, 5, 7, 3],   # 第1行 ← tensor[1][1]</span></span><br><span class="line">    <span class="comment">#      [5, 8, 8, 2],</span></span><br><span class="line">    <span class="comment">#      [7, 4, 6, 7],</span></span><br><span class="line">    <span class="comment">#      [5, 5, 4, 1]</span></span><br><span class="line">    <span class="comment">#  ]</span></span><br><span class="line">    <span class="comment">#  所以：</span></span><br><span class="line">    <span class="comment">#  - tensor[1, 1] → tensor[1][1] → [7, 5, 7, 3]</span></span><br><span class="line">    <span class="comment">#  - tensor[0, 2] → tensor[0][2] → [7, 8, 7, 2]</span></span><br></pre></td></tr></table></figure><h2 id="⭐范围索引（切片）"><a href="#⭐范围索引（切片）" class="headerlink" title="⭐范围索引（切片）"></a>⭐范围索引（切片）</h2><p>同上“简单索引”中的切片用法；<code>start:end:step</code>、负索引均支持。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line">tensor1 = torch.randint(<span class="number">1</span>, <span class="number">9</span>, (<span class="number">3</span>, <span class="number">5</span>, <span class="number">4</span>))</span><br><span class="line"><span class="built_in">print</span>(tensor1[<span class="number">1</span>:].shape)          </span><br><span class="line"><span class="built_in">print</span>(tensor1[-<span class="number">1</span>:, <span class="number">1</span>:<span class="number">4</span>, <span class="number">0</span>:<span class="number">3</span>].shape) </span><br></pre></td></tr></table></figure><p><span style="color:#FF00FF">下面演示一下三维张量的范围索引计算方法</span></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">tensor = torch.tensor([</span><br><span class="line">    [[<span class="number">7</span>, <span class="number">1</span>, <span class="number">4</span>, <span class="number">4</span>],</span><br><span class="line">     [<span class="number">4</span>, <span class="number">8</span>, <span class="number">2</span>, <span class="number">8</span>],</span><br><span class="line">     [<span class="number">7</span>, <span class="number">8</span>, <span class="number">7</span>, <span class="number">2</span>],</span><br><span class="line">     [<span class="number">2</span>, <span class="number">2</span>, <span class="number">7</span>, <span class="number">8</span>],</span><br><span class="line">     [<span class="number">7</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">2</span>]],</span><br><span class="line"></span><br><span class="line">    [[<span class="number">1</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">3</span>],</span><br><span class="line">     [<span class="number">7</span>, <span class="number">5</span>, <span class="number">7</span>, <span class="number">3</span>],</span><br><span class="line">     [<span class="number">5</span>, <span class="number">8</span>, <span class="number">8</span>, <span class="number">2</span>],</span><br><span class="line">     [<span class="number">7</span>, <span class="number">4</span>, <span class="number">6</span>, <span class="number">7</span>],</span><br><span class="line">     [<span class="number">5</span>, <span class="number">5</span>, <span class="number">4</span>, <span class="number">1</span>]],</span><br><span class="line"></span><br><span class="line">    [[<span class="number">4</span>, <span class="number">2</span>, <span class="number">2</span>, <span class="number">7</span>],</span><br><span class="line">     [<span class="number">1</span>, <span class="number">6</span>, <span class="number">8</span>, <span class="number">7</span>],</span><br><span class="line">     [<span class="number">7</span>, <span class="number">1</span>, <span class="number">6</span>, <span class="number">2</span>],</span><br><span class="line">     [<span class="number">4</span>, <span class="number">4</span>, <span class="number">3</span>, <span class="number">1</span>],</span><br><span class="line">     [<span class="number">2</span>, <span class="number">8</span>, <span class="number">1</span>, <span class="number">5</span>]]])</span><br><span class="line"><span class="built_in">print</span>(tensor[<span class="number">1</span>:])</span><br><span class="line"><span class="comment"># tensor([[[1, 2, 2, 3],</span></span><br><span class="line"><span class="comment">#          [7, 5, 7, 3],</span></span><br><span class="line"><span class="comment">#          [5, 8, 8, 2],</span></span><br><span class="line"><span class="comment">#          [7, 4, 6, 7],</span></span><br><span class="line"><span class="comment">#          [5, 5, 4, 1]],</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment">#         [[4, 2, 2, 7],</span></span><br><span class="line"><span class="comment">#          [1, 6, 8, 7],</span></span><br><span class="line"><span class="comment">#          [7, 1, 6, 2],</span></span><br><span class="line"><span class="comment">#          [4, 4, 3, 1],</span></span><br><span class="line"><span class="comment">#          [2, 8, 1, 5]]])</span></span><br><span class="line"><span class="comment"># 记录包含第二三维所有数的第一维的下标1之后的数</span></span><br><span class="line"><span class="built_in">print</span>(tensor[-<span class="number">1</span>:, <span class="number">1</span>:<span class="number">4</span>, :<span class="number">3</span>])</span><br><span class="line"><span class="comment"># tensor([[[1, 6, 8],</span></span><br><span class="line"><span class="comment">#          [7, 1, 6],</span></span><br><span class="line"><span class="comment">#          [4, 4, 3]]])</span></span><br><span class="line"><span class="comment">#   ┌───────┬──────┬────────────┬────────────────────────────────────────────┐</span></span><br><span class="line"><span class="comment">#   │ 维度  │ 切片 │    含义    │                  选中内容                   │</span></span><br><span class="line"><span class="comment">#   ├───────┼──────┼────────────┼────────────────────────────────────────────┤</span></span><br><span class="line"><span class="comment">#   │ 维度0 │ -1:  │ 最后一个    │ layer 2 (整个 5×4)                         │</span></span><br><span class="line"><span class="comment">#   ├───────┼──────┼────────────┼────────────────────────────────────────────┤</span></span><br><span class="line"><span class="comment">#   │ 维度1  │ 1:4 │ 行 1, 2, 3 │ [[1, 6, 8, 7], [7, 1, 6, 2], [4, 4, 3, 1]] │</span></span><br><span class="line"><span class="comment">#   ├───────┼──────┼────────────┼────────────────────────────────────────────┤</span></span><br><span class="line"><span class="comment">#   │ 维度2 │  :3  │ 列 0, 1, 2 │ 每行取前3列                                 │</span></span><br><span class="line"><span class="comment">#   └───────┴──────┴────────────┴────────────────────────────────────────────┘</span></span><br><span class="line"><span class="comment">#   最终结果 — 从最后一层 (layer 2)，取行 1~3，列 0~2：</span></span><br></pre></td></tr></table></figure><h2 id="多维索引"><a href="#多维索引" class="headerlink" title="多维索引"></a>多维索引</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">t2 = torch.tensor([</span><br><span class="line">         [</span><br><span class="line">             [</span><br><span class="line">                 <span class="number">3</span>, </span><br><span class="line">              <span class="number">4</span>, </span><br><span class="line">              <span class="number">6</span>, </span><br><span class="line">              <span class="number">5</span></span><br><span class="line">             ],</span><br><span class="line">             </span><br><span class="line">             [</span><br><span class="line">                 <span class="number">8</span>, </span><br><span class="line">                 <span class="number">8</span>, </span><br><span class="line">                 <span class="number">8</span>, </span><br><span class="line">                 <span class="number">3</span></span><br><span class="line">             ],</span><br><span class="line">             </span><br><span class="line">             [<span class="number">4</span>, <span class="number">9</span>, <span class="number">6</span>, <span class="number">7</span>]</span><br><span class="line">         ],</span><br><span class="line"></span><br><span class="line">         [</span><br><span class="line">             [<span class="number">2</span>, <span class="number">8</span>, <span class="number">8</span>, <span class="number">5</span>],</span><br><span class="line">             [<span class="number">6</span>, <span class="number">4</span>, <span class="number">2</span>, <span class="number">2</span>],</span><br><span class="line">             [<span class="number">2</span>, <span class="number">7</span>, <span class="number">9</span>, <span class="number">4</span>]</span><br><span class="line">         ]</span><br><span class="line"> ])</span><br><span class="line"> <span class="comment"># 需求1:获取0轴上的第1个数据.</span></span><br><span class="line"> <span class="built_in">print</span>(t2[<span class="number">0</span>,:,:])</span><br><span class="line"> <span class="comment"># tensor([[3, 4, 6, 5],</span></span><br><span class="line"> <span class="comment">#         [8, 8, 8, 3],</span></span><br><span class="line"> <span class="comment">#         [4, 9, 6, 7]])</span></span><br><span class="line"> <span class="comment"># 需求2:获取1轴上的第1个数据.</span></span><br><span class="line"> <span class="built_in">print</span>(t2[:,<span class="number">0</span>,:])</span><br><span class="line"> <span class="comment"># tensor([[3, 4, 6, 5],</span></span><br><span class="line"> <span class="comment">#         [2, 8, 8, 5]])</span></span><br><span class="line"> <span class="comment"># 需求3:获取2轴上的第1个数据.</span></span><br><span class="line"> <span class="built_in">print</span>(t2[:,:,<span class="number">0</span>])</span><br><span class="line"> <span class="comment"># tensor([[3, 8, 4],</span></span><br><span class="line"> <span class="comment">#         [2, 6, 2]])</span></span><br><span class="line"> </span><br></pre></td></tr></table></figure><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260614103710271.png" alt="image-20260614103710271"></p><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260614103655112.png"></p><p>索引操作<code> t2[:,:,0]</code> 的工作原理</p><p>  当我们使用<code> t2[:,:,0]</code> 时：</p><ul><li>第一个 : 表示保留所有层（2个层）</li><li>第二个 : 表示保留所有行（3行）</li><li>0 表示只选择第0列</li></ul><p>  所以这个操作实际上是：</p><ul><li>从第0层：取第0列 → [3, 8, 4]</li><li>从第1层：取第0列 → [2, 6, 2]</li></ul><h1 id="张量的形状操作"><a href="#张量的形状操作" class="headerlink" title="张量的形状操作"></a>张量的形状操作</h1><h2 id="reshape-与-view-View不常用"><a href="#reshape-与-view-View不常用" class="headerlink" title="reshape 与 view(View不常用)"></a>reshape 与 view(View不常用)</h2><p>接口：</p><ul><li><code>Tensor.reshape(*shape)</code>：在内存不连续时可返回副本</li><li><code>Tensor.view(*shape)</code>：要求张量在内存中连续，否则需先调用 <code>contiguous()</code></li></ul><p>功能：在元素总数不变的前提下调整形状。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">tensor1 = torch.randint(<span class="number">1</span>, <span class="number">9</span>, (<span class="number">3</span>, <span class="number">5</span>, <span class="number">4</span>))  <span class="comment"># 共 60 个元素</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(tensor1.reshape(<span class="number">6</span>, <span class="number">10</span>))   <span class="comment"># 形状 (6, 10)</span></span><br><span class="line"><span class="built_in">print</span>(tensor1.reshape(<span class="number">3</span>, -<span class="number">1</span>))  <span class="comment"># (3, 20)，-1 被推断为 20</span></span><br></pre></td></tr></table></figure><h2 id="unsqueeze：增加大小为-1-的维"><a href="#unsqueeze：增加大小为-1-的维" class="headerlink" title="unsqueeze：增加大小为 1 的维"></a>unsqueeze：增加大小为 1 的维</h2><p>接口：</p><ul><li><code>Tensor.unsqueeze(dim)</code></li><li><code>Tensor.unsqueeze_(dim)</code></li></ul><p>功能：在指定位置插入一个大小为 1 的维度，常用于广播或与某些接口的维度要求对齐。一般在模型欠拟合的时候增加维度</p><p>参数：</p><ul><li><code>dim</code>：插入的维度下标（支持负索引，-1 表示最后一维之后）。</li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 1. 定义2行3列的张量.</span></span><br><span class="line">    t1 = torch.randint(<span class="number">1</span>, <span class="number">10</span>, size=(<span class="number">2</span>, <span class="number">3</span>))</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;t1: <span class="subst">&#123;t1&#125;</span>, shape: <span class="subst">&#123;t1.shape&#125;</span>&#x27;</span>)  <span class="comment"># (2, 3)</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 2. 在0维上, 添加一个维度.</span></span><br><span class="line">    t2 = t1.unsqueeze(<span class="number">0</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;t2: <span class="subst">&#123;t2&#125;</span>, shape: <span class="subst">&#123;t2.shape&#125;</span>&#x27;</span>)  <span class="comment"># (1, 2, 3)</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 3. 在1维上, 添加一个维度.</span></span><br><span class="line">    t3 = t1.unsqueeze(<span class="number">1</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;t3: <span class="subst">&#123;t3&#125;</span>, shape: <span class="subst">&#123;t3.shape&#125;</span>&#x27;</span>)  <span class="comment"># (2, 1, 3) 由原来的两行三列矩阵变为两个一行三列的矩阵</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 4. 在2维上, 添加一个维度.</span></span><br><span class="line">    t4 = t1.unsqueeze(<span class="number">2</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;t4: <span class="subst">&#123;t4&#125;</span>, shape: <span class="subst">&#123;t4.shape&#125;</span>&#x27;</span>)  <span class="comment"># (2, 3, 1)</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 5. 在3维上(不存在), 添加一个维度.</span></span><br><span class="line">    t5 = t1.unsqueeze(<span class="number">3</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;t5: <span class="subst">&#123;t5&#125;</span>, shape: <span class="subst">&#123;t5.shape&#125;</span>&#x27;</span>)  <span class="comment"># (2, 3 , * , 1)  中间跳了一个*，报越界错误</span></span><br></pre></td></tr></table></figure><h2 id="squeeze：删除大小为-1-的维"><a href="#squeeze：删除大小为-1-的维" class="headerlink" title="squeeze：删除大小为 1 的维"></a>squeeze：删除大小为 1 的维</h2><p>接口：</p><ul><li><code>Tensor.squeeze(dim=None)</code></li><li><code>Tensor.squeeze_(dim=None)</code></li></ul><p>功能：删除大小为 1 的维度。不传 <code>dim</code> 时删除所有大小为 1 的维；传 <code>dim</code> 时仅当该维为 1 才删除。</p><p>参数：</p><ul><li><code>dim</code>：可选，指定要删除的维度下标。</li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> torch</span><br><span class="line">tensor1 = torch.tensor([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>])</span><br><span class="line">tensor1 = tensor1.unsqueeze_(dim=<span class="number">0</span>)  <span class="comment"># (1, 5)</span></span><br><span class="line">tensor1 = tensor1.unsqueeze_(dim=<span class="number">0</span>)  <span class="comment"># (1, 1, 5)</span></span><br><span class="line"><span class="built_in">print</span>(tensor1.squeeze())  <span class="comment"># (5,)，删除所有大小为 1 的维</span></span><br></pre></td></tr></table></figure><h2 id="交换维度"><a href="#交换维度" class="headerlink" title="交换维度"></a>交换维度</h2><p>接口：</p><ul><li><code>Tensor.transpose(dim0, dim1)</code>：交换两个指定维度</li><li><span style="color:#FF00FF"><code>Tensor.permute(*dims)</code>：按给定顺序重排所有维度，可一次实现多维交换</span></li></ul><p>参数：</p><ul><li><code>transpose(dim0, dim1)</code>：<code>dim0</code>、<code>dim1</code> 为要交换的两个维度下标（从 0 起）。</li><li><span style="color:#FF00FF"><code>permute(*dims)</code>：<code>*dims</code> 为新的维度顺序，例如原形状 (2,3,6) 传入 (2,0,1) 得到 (6,2,3)。</span></li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">tensor1 = torch.randint(<span class="number">1</span>, <span class="number">9</span>, (<span class="number">2</span>, <span class="number">3</span>, <span class="number">6</span>))</span><br><span class="line"></span><br><span class="line">   <span class="comment"># transpose：只交换第 1 维与第 2 维，结果形状 (2, 6, 3)</span></span><br><span class="line">   <span class="built_in">print</span>(tensor1.transpose(<span class="number">1</span>, <span class="number">2</span>))</span><br><span class="line"></span><br><span class="line">   <span class="comment"># permute：按 (dim2, dim0, dim1) 重排，结果形状 (6, 2, 3)</span></span><br><span class="line">   <span class="built_in">print</span>(tensor1.permute(<span class="number">2</span>, <span class="number">0</span>, <span class="number">1</span>))       <span class="comment"># 第0维的数据为dim2，第1维的数据为dim0，第2维的数据为dim1</span></span><br></pre></td></tr></table></figure><h1 id="张量的拼接操作"><a href="#张量的拼接操作" class="headerlink" title="张量的拼接操作"></a>张量的拼接操作</h1><h2 id="torch-cat"><a href="#torch-cat" class="headerlink" title="torch.cat"></a>torch.cat</h2><p>接口：<code>torch.cat(tensors, dim=0, out=None)</code></p><p>功能：在指定维度上拼接多个张量，除 <code>dim</code> 外其余维度须相同。</p><p>参数：</p><ul><li><code>tensors</code>：张量序列（list 或 tuple）</li><li><code>dim</code>：沿该维拼接</li><li><code>out</code>：可选输出张量</li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 1. 创建两个张量.</span></span><br><span class="line">t1 = torch.randint(<span class="number">1</span>, <span class="number">10</span>, (<span class="number">2</span>, <span class="number">3</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&#x27;t1: <span class="subst">&#123;t1&#125;</span>, shape: <span class="subst">&#123;t1.shape&#125;</span>&#x27;</span>)</span><br><span class="line"></span><br><span class="line">t2 = torch.randint(<span class="number">1</span>, <span class="number">10</span>, (<span class="number">2</span>, <span class="number">3</span>))</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&#x27;t2: <span class="subst">&#123;t2&#125;</span>, shape: <span class="subst">&#123;t2.shape&#125;</span>&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 2. 演示张量的拼接.</span></span><br><span class="line">t3 = torch.cat(tensors=[t1, t2], dim=<span class="number">0</span>)  <span class="comment"># (2, 3) + (2, 3) = (4, 3)</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&#x27;t3: <span class="subst">&#123;t3&#125;</span>, shape: <span class="subst">&#123;t3.shape&#125;</span>&#x27;</span>)</span><br></pre></td></tr></table></figure><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260614222751340.png" alt="image-20260614222751340"></p><h2 id="torch-stack"><a href="#torch-stack" class="headerlink" title="torch.stack"></a>torch.stack</h2><p>接口：<code>torch.stack(tensors, dim=0, out=None)</code></p><p>功能：在新维度上堆叠多个张量，所有输入形状必须一致，结果多出一维。</p><p>参数：</p><ul><li><code>tensors</code>：形状相同的张量序列</li><li><code>dim</code>：插入的新维度位置</li><li><code>out</code>：可选输出张量</li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 1. 创建两个张量.</span></span><br><span class="line">t1 = torch.tensor([[<span class="number">6</span>,<span class="number">9</span>,<span class="number">9</span>],[<span class="number">2</span>,<span class="number">8</span>,<span class="number">7</span>]])</span><br><span class="line"></span><br><span class="line">t2 = torch.tensor([[<span class="number">8</span>,<span class="number">5</span>,<span class="number">8</span>],[<span class="number">4</span>,<span class="number">7</span>,<span class="number">4</span>]])</span><br><span class="line"><span class="comment"># 思路2: stack() 拼接张量, 可以是新维度, 但是无论新旧维度, 所有维度都必须保持一致.</span></span><br><span class="line">t7 = torch.stack([t1, t2], dim=<span class="number">0</span>)    <span class="comment"># (2, 3) + (2, 3) = (2, 2, 3)</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&#x27;t7: <span class="subst">&#123;t7&#125;</span>, shape: <span class="subst">&#123;t7.shape&#125;</span>&#x27;</span>)</span><br><span class="line"></span><br><span class="line">t8 = torch.stack(tensors=[t1, t2], dim=<span class="number">1</span>)    <span class="comment"># (2, 3) + (2, 3) = (2, 2, 3)</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&#x27;t8: <span class="subst">&#123;t8&#125;</span>, shape: <span class="subst">&#123;t8.shape&#125;</span>&#x27;</span>)</span><br><span class="line"></span><br><span class="line">t9 = torch.stack(tensors=[t1, t2], dim=<span class="number">2</span>)  <span class="comment"># (2, 3) + (2, 3) = (2, 3, 2)</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&#x27;t9: <span class="subst">&#123;t9&#125;</span>, shape: <span class="subst">&#123;t9.shape&#125;</span>&#x27;</span>)</span><br></pre></td></tr></table></figure><p>关于<code>t8</code>：</p><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260614223902264.png" alt="image-20260614223902264"></p><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260614223851271.png" alt="image-20260614223851271"></p><p>关于<code>t9</code>：</p><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260614224332820.png" alt="image-20260614224332820"></p><p><span style="color:#FF00FF">⭐这里的二维度相比于前面的维度，只是单个数字，故不用再加中括号</span></p><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260614230021539.png" alt="image-20260614230021539"></p><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260614230104952.png" alt="image-20260614230104952"></p><h1 id="自动微分模块"><a href="#自动微分模块" class="headerlink" title="自动微分模块"></a>自动微分模块</h1><p>训练时 PyTorch 会构建<strong>计算图（computational graph）</strong>，记录数据与运算，并通过内置的微分引擎 <code>torch.autograd</code> 在根节点调用 <code>backward()</code> 自动计算梯度。PyTorch 的 <code>backward()</code> 就是在计算图上自动做链式法则，从根节点（通常是损失）一路把梯度传回叶子节点（如权重、偏置）。</p><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260616222332398.png" alt="image-20260616222332398"></p><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260616223707063.png" alt="image-20260616223707063"></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 1. 定义变量，记录：初始的权重w(旧)</span></span><br><span class="line">  <span class="comment"># 参1：初始值，参2：是否自动微分(求导)，参3：数据类型</span></span><br><span class="line">  w = torch.tensor(data=<span class="number">10</span>, requires_grad=<span class="literal">True</span>, dtype=torch.<span class="built_in">float</span>)</span><br><span class="line"></span><br><span class="line">  <span class="comment"># 2. 定义loss变量，表示损失函数。</span></span><br><span class="line">  loss = <span class="number">2</span> * w ** <span class="number">2</span>  <span class="comment"># loss = 2w² → 求导：4w</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># 3. 打印梯度函数类型(了解)</span></span><br><span class="line">  <span class="comment"># print(f&#x27;梯度函数类型：&#123;type(loss.grad_fn)&#125;&#x27;)    # &lt;class &#x27;MulBackward0&#x27;&gt;</span></span><br><span class="line">  <span class="comment"># print(loss.sum())</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># 4. 计算梯度，梯度 = 损失函数的导数，计算完毕后，会记录到 w.grad属性中。</span></span><br><span class="line">  <span class="comment"># loss.sum().backward()      # 保证loss是1个标量。</span></span><br><span class="line">  loss.backward()  <span class="comment"># 这里因为y本身就是标量，可以不写sum()</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># 5. 代入 权重更新公式：W新 = W旧 - 学习率 * 梯度</span></span><br><span class="line">  w.data = w.data - <span class="number">0.01</span> * w.grad</span><br><span class="line"></span><br><span class="line">  <span class="comment"># 6. 打印最终结果。</span></span><br><span class="line">  <span class="built_in">print</span>(<span class="string">f&#x27;更新后的权重：<span class="subst">&#123;w&#125;</span>&#x27;</span>)  <span class="comment"># 9.6</span></span><br></pre></td></tr></table></figure><p>在真实的神经网络中，情况完全不同：</p><ol><li>损失函数不是 2w²，而是 loss &#x3D; f(w, x, y) —— 依赖输入数据 x 和真实标签 y。</li><li>梯度不会总是把 w 推向 0，因为 loss 的最低点不一定在 w&#x3D;0 处。比如线性回归 loss &#x3D; (wx - y)²，最优 w 是让 wx ≈ y</li></ol><pre><code>的那个值，通常不是 0。</code></pre><ol start="3"><li>多个权重相互制衡，真实网络有成千上万的参数，一个权重的梯度受其他所有权重影响，不会简单归零。</li><li>当模型收敛时，梯度会趋近于 0，此时权重稳定在最优值附近，而不是单纯的 0。</li></ol><p>  一句话总结：这个 demo 的 loss 函数恰好是 2w²（最小值在 w&#x3D;0），所以你看到 w→0<br>  是对的。但在真实场景中，梯度下降会让权重停在让 loss 最小的那个值，那个值一般不是 0。</p><h2 id="自动微分模块案例-循环更新参数"><a href="#自动微分模块案例-循环更新参数" class="headerlink" title="自动微分模块案例-循环更新参数"></a>自动微分模块案例-循环更新参数</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">w = torch.tensor(data=<span class="number">10</span>, requires_grad=<span class="literal">True</span>, dtype=torch.float32)</span><br><span class="line">loss = w ** <span class="number">2</span> + <span class="number">20</span></span><br><span class="line"><span class="comment"># 利用梯度下降法，循环迭代100求最优解</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&#x27;开始权重值:<span class="subst">&#123;w:<span class="number">.5</span>f&#125;</span>, (0.01 * w.grad):无 , loss:<span class="subst">&#123;loss:<span class="number">.5</span>f&#125;</span>&#x27;</span>)</span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">1</span>, <span class="number">101</span>):</span><br><span class="line">    <span class="comment"># 1.正向传播</span></span><br><span class="line">    loss = w ** <span class="number">2</span> + <span class="number">20</span></span><br><span class="line">    <span class="comment"># 2.梯度清零，否则 backward() 会累加梯度</span></span><br><span class="line">    <span class="keyword">if</span> w.grad <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">        w.grad.zero_()</span><br><span class="line">    <span class="comment"># 3.反向传播</span></span><br><span class="line">    <span class="comment"># 这里的loss本身就是一个标量，所以可以不用写sum</span></span><br><span class="line">    <span class="comment"># PyTorch 的 backward() 会累加梯度，而不是覆盖梯度。这是因为一个参数可能被多个 loss 贡献梯度（比如 RNN中同一个权重在不同时间步被使用）。</span></span><br><span class="line">    loss.backward()</span><br><span class="line">    <span class="comment"># print(f&#x27;梯度值为:&#123;w.grad&#125;&#x27;)</span></span><br><span class="line">    <span class="comment"># 4.梯度更新</span></span><br><span class="line">    w.data = w.data - <span class="number">0.01</span> * w.grad</span><br><span class="line">    <span class="comment"># 5.打印本次梯度更新后的权重参数结果</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;第<span class="subst">&#123;i&#125;</span>次，权重初始值：<span class="subst">&#123;w:<span class="number">.5</span>f&#125;</span>,(0.01 * w.grad):<span class="subst">&#123;<span class="number">0.01</span> * w.grad:<span class="number">.5</span>f&#125;</span>, loss:<span class="subst">&#123;loss:<span class="number">.5</span>f&#125;</span>&#x27;</span>)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">f&#x27;最终权重：<span class="subst">&#123;w&#125;</span>,梯度:<span class="subst">&#123;w.grad&#125;</span>,loss=<span class="subst">&#123;loss&#125;</span>&#x27;</span>)</span><br></pre></td></tr></table></figure><h1 id="案例-线性回归案例"><a href="#案例-线性回归案例" class="headerlink" title="案例-线性回归案例"></a>案例-线性回归案例</h1><p>整体流程：准备数据 → 构建模型 → 定义损失与优化器 → 循环训练（前向、算损失、反向、更新参数）。</p><h2 id="⭐⭐⭐用到的函数和知识点"><a href="#⭐⭐⭐用到的函数和知识点" class="headerlink" title="⭐⭐⭐用到的函数和知识点"></a>⭐⭐⭐用到的函数和知识点</h2><h3 id="PyTorch-里处理数据的标准三步流程"><a href="#PyTorch-里处理数据的标准三步流程" class="headerlink" title="PyTorch 里处理数据的标准三步流程"></a>PyTorch 里处理数据的标准三步流程</h3><blockquote><p>tensor → Dataset → DataLoader</p></blockquote><ol><li><p>Tensor：原始数据</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">X = torch.tensor([[<span class="number">1.0</span>, <span class="number">2.0</span>], [<span class="number">3.0</span>, <span class="number">4.0</span>], ...])</span><br><span class="line">y = torch.tensor([<span class="number">0.0</span>, <span class="number">1.0</span>, ...])</span><br></pre></td></tr></table></figure><p>Tensor 只是装着数字的多维数组本身，它不知道怎么<strong>批量取数据、怎么打乱、怎么并行加载</strong>。</p></li><li><p>Dataset：把数据包装成”可索引”的对象</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> torch.utils.data <span class="keyword">import</span> TensorDataset</span><br><span class="line"></span><br><span class="line">dataset = TensorDataset(X, y)</span><br></pre></td></tr></table></figure><p><code>Dataset</code> 的作用是：</p><ul><li>把 <code>X</code> 和 <code>y</code> 配对绑定</li><li>让你可以通过索引拿到一个 <code>(features, label)</code> 样本：</li></ul><blockquote><p><code>x_i, y_i = dataset[0]</code></p></blockquote><p>它回答的是”第 i 个样本是什么”。</p></li><li><p>DataLoader：数据加载器</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> torch.utils.data <span class="keyword">import</span> DataLoader</span><br><span class="line"></span><br><span class="line">loader = DataLoader(dataset, batch_size=<span class="number">32</span>, shuffle=<span class="literal">True</span>)</span><br></pre></td></tr></table></figure><p><strong>数据加载器</strong>就是帮你自动把数据集切分成小批量（batch），然后按批次喂给模型的工具。</p><p>它主要做这几件事：</p><table><thead><tr><th>功能</th><th>作用</th></tr></thead><tbody><tr><td><code>batch_size</code></td><td>每次取多少条样本</td></tr><tr><td><code>shuffle</code></td><td>每个 epoch 是否打乱数据顺序</td></tr><tr><td>自动迭代</td><td>用 <code>for batch in loader</code> 就能逐个 batch 遍历</td></tr><tr><td>多进程加载</td><td><code>num_workers</code> 可以并行读取数据</td></tr></tbody></table><p>例如：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> X_batch, y_batch <span class="keyword">in</span> loader:</span><br><span class="line">    <span class="comment"># X_batch 形状: (32, n_features)</span></span><br><span class="line">    <span class="comment"># y_batch 形状: (32,)</span></span><br><span class="line">    pred = model(X_batch)</span><br><span class="line">    loss = criterion(pred, y_batch)</span><br></pre></td></tr></table></figure></li></ol><h3 id="创造数据make-regression"><a href="#创造数据make-regression" class="headerlink" title="创造数据make_regression"></a>创造数据<code>make_regression</code></h3><p><code>make_regression</code> 是 scikit-learn 中一个用来<strong>生成模拟回归数据</strong>的函数，常用于测试线性回归模型。返回的是 <strong>NumPy 数组（<code>ndarray</code>）</strong></p><p>它的基本作用：根据你指定的参数，自动构造一个带有已知真实系数的人造数据集，这样你可以验证模型能不能学得够准。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">make_regression：我故意设了真实系数，再生成带噪声的数据点</span><br><span class="line">模型训练：不知道真实系数，只看数据，自己学</span><br><span class="line">训练完：对比学出来的 weight/bias 和真实系数</span><br><span class="line"></span><br><span class="line">如果学出来的值接近真实系数，就验证了两件事：</span><br><span class="line">模型没问题：线性回归模型确实能从数据中学到正确的规律</span><br><span class="line">训练流程没问题：损失函数、反向传播、优化器这套流程是能跑通的</span><br></pre></td></tr></table></figure><p>常用参数大概长这样：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> sklearn.datasets <span class="keyword">import</span> make_regression</span><br><span class="line"></span><br><span class="line">X, y, coef = make_regression(</span><br><span class="line">    n_samples=<span class="number">100</span>,    <span class="comment"># 样本数</span></span><br><span class="line">    n_features=<span class="number">5</span>,     <span class="comment"># 特征数</span></span><br><span class="line">    n_informative=<span class="number">3</span>,  <span class="comment"># 真正对 y 有影响的特征数</span></span><br><span class="line">    noise=<span class="number">10</span>,         <span class="comment"># 噪声强度</span></span><br><span class="line">    coef=<span class="literal">True</span>,        <span class="comment"># 是否返回真实系数</span></span><br><span class="line">    random_state=<span class="number">42</span></span><br><span class="line">)</span><br></pre></td></tr></table></figure><p>它会返回：</p><ul><li><code>X</code>：形状为 <code>(n_samples, n_features)</code> 的特征矩阵</li><li><code>y</code>：形状为 <code>(n_samples,)</code> 的目标值</li><li><code>coef</code>：真实特征的权重系数（如果 <code>coef=True</code>）</li></ul><p><code>make_regression</code> 的约定：</p><ul><li><code>x</code>（特征）：永远是 2维 <code>(100, 1)</code>  —  因为特征可以有多个维度</li><li><code>y</code>（目标值）：永远是 1维 <code>(100,)</code>  — <code>sklearn</code> 的习惯，因为目标值就是一个标量</li></ul><p>生成数据的大致公式是：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">y = X @ coef + bias + noise <span class="comment"># 假设 X 是 (100, 3)，coef 是 (3,)，结果 y 是形状 (100,)</span></span><br></pre></td></tr></table></figure><p>其中 <code>noise</code> 是服从正态分布的随机扰动。</p><p>在模拟线性回归时，它的好处是你知道“正确答案”——可以把模型学出来的系数和 <code>make_regression</code> 返回的真实 <code>coef</code> 对比，看偏差有多大，用来评估模型效果或者做教学演示。</p><h3 id="线性回归函数"><a href="#线性回归函数" class="headerlink" title="线性回归函数"></a>线性回归函数</h3><h4 id="理解线性回归函数Linear-的定义"><a href="#理解线性回归函数Linear-的定义" class="headerlink" title="理解线性回归函数Linear()的定义"></a>理解线性回归函数<code>Linear()</code>的定义</h4><ol><li><p>代码<code>nn.Linear(1, 1)</code> 中的 “1” 指的是什么？</p><ul><li><p>第一个 1：每个样本的特征数<code>（in_features）</code></p></li><li><p>第二个 1：每个样本的输出数<code>（out_features）</code></p></li></ul></li><li><p>线性回归公式为<code>output = input × W^T + b</code></p><ul><li><p><code>W</code> 的形状：<code>(1, 1)</code> — 因为输入1维、输出1维</p></li><li><p><code>b</code> 的形状：<code>(1,)</code></p></li></ul><p>根据上述公式，如果我们传入 <code>(100, 1) </code>并且代入公式中： <code> input (100, 1)  ×  W^T (1, 1)  →  (100, 1)  +  b</code>。</p><p>实际意义是 “对 batch 里的每个样本，分别做一次 <code>y = x * w + b&quot;</code>。无论传 (1, 1)、(16, 1) 还是 (100, 1)，PyTorch 自动把 batch 维（第一维）当作”批次”，对每个样本独立做线性变换。</p></li></ol><p><span style="color:red">线性回归运算的本质是只（100,1）的第二维做计算，第一维是做计算的次数。如果传入(100,2)的话，那么线性回归就要为 <code>nn.Linear(2, 1)</code>，表示我的线性回归要对两个特征做一百次计算，计算出100个1个特征的样本</span></p><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260703120004061.png" alt="image-20260703120004061"></p><h4 id="另外：⭐nn-Linear-的两个维度通常是不相等的"><a href="#另外：⭐nn-Linear-的两个维度通常是不相等的" class="headerlink" title="另外：⭐nn.Linear()的两个维度通常是不相等的"></a>另外：⭐<span style="color:#FF00FF"><code>nn.Linear()</code>的两个维度通常是不相等的</span></h4><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">相等的情况反而少见。nn.Linear 的作用就是在不同维度之间做映射（投影）：</span><br><span class="line"></span><br><span class="line">  nn.Linear(<span class="number">2</span>, <span class="number">1</span>)    <span class="comment"># 2维 → 1维：降维（回归输出、二分类...）</span></span><br><span class="line">  nn.Linear(<span class="number">64</span>, <span class="number">10</span>)  <span class="comment"># 64维 → 10维：降维（10分类任务）</span></span><br><span class="line">  nn.Linear(<span class="number">16</span>, <span class="number">32</span>)  <span class="comment"># 16维 → 32维：升维</span></span><br><span class="line">  nn.Linear(<span class="number">128</span>, <span class="number">128</span>) <span class="comment"># 128维 → 128维：保持维度不变（Transformer里常见）</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># 代码里的 nn.Linear(1, 1) 是因为 x 和 y 都是 1 维，所以输入输出都是 1——这只是一个特例，不是规则。</span></span><br><span class="line"></span><br><span class="line">  当做多特征回归时就看出来了：</span><br><span class="line"></span><br><span class="line">  <span class="comment"># 假如有2个特征（如面积、房龄）预测房价</span></span><br><span class="line">  x.shape        <span class="comment"># (100, 2)   ← 2个特征</span></span><br><span class="line">  model = nn.Linear(<span class="number">2</span>, <span class="number">1</span>)  <span class="comment"># 输入2维，输出1维</span></span><br><span class="line"></span><br><span class="line">  这里 <span class="number">2</span> ≠ <span class="number">1</span>，但完全没问题。</span><br></pre></td></tr></table></figure><h3 id="损失函数"><a href="#损失函数" class="headerlink" title="损失函数"></a>损失函数</h3><h4 id="回归问题的损失函数"><a href="#回归问题的损失函数" class="headerlink" title="回归问题的损失函数"></a>回归问题的损失函数</h4><p><code>nn.MSELoss()</code>以均方误差为指导思想来不断逼近真实值</p><p><code>loss = criterion(y_pred,train_y.reshape(-1,1))</code>计算预测值和真实值之间的损失，分两部分解释：</p><ol><li><p><code>criterion(y_pred, ...)   # train_x shape: (16, 1)</code></p><p> <code> criterion</code> 是一个损失函数（比如<code> nn.MSELoss()</code> 或 <code>nn.BCELoss()</code>），计算预测值 <code>y_pred</code><br>  和真实值之间的差异。返回一个标量（张量），数值越小说明预测越准。</p></li><li><p><code>train_y.reshape(-1, 1)</code> <code># train_y</code> 从 DataLoader 来，原始 <code>shape: (16,)</code></p><p>一维：只有一个轴</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">train_y = torch.tensor([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>])</span><br><span class="line">train_y.shape      <span class="comment"># torch.Size([5])    ← 这是1维，不是1行5列, 形状(5,)</span></span><br><span class="line">train_y.ndim       <span class="comment"># 1</span></span><br></pre></td></tr></table></figure><p>二维：两个轴</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">y_pred = torch.tensor([[<span class="number">1</span>], [<span class="number">2</span>], [<span class="number">3</span>], [<span class="number">4</span>], [<span class="number">5</span>]])</span><br><span class="line">  y_pred.shape       <span class="comment"># torch.Size([5, 1]) ← 这是2维</span></span><br><span class="line">  y_pred.ndim        <span class="comment"># 2</span></span><br><span class="line">  y_pred = torch.tensor( [[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>]] ) <span class="comment"># 也是二维，形状(1,5)</span></span><br></pre></td></tr></table></figure><p>⭐⭐<span style="color:#FF00FF"><code>[[1],[2],[3],[4],[5]]</code>和 <code>[[1, 2, 3, 4, 5]]</code>都是二维，他们的区别在哪里呢?</span></p><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260703113328639.png" alt="image-20260703113328639"></p><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260703113349286.png" alt="image-20260703113349286"></p><p>⭐⭐<span style="color:#FF00FF"><code>[1, 2, 3, 4, 5]</code>就是5个样本，零个特征吗？</span></p><p>不是的。<code>[1, 2, 3, 4, 5] </code>形状 (5,) 是 1维张量，它根本没有”样本”和”特征”的概念——就是一排数字（五个数排成一排）。</p><p>由此可得 <code>reshape(-1, 1)</code> 的作用：<br>把 <code>(16,) → (16, 1)</code>，变成16行1列的列向量。</p><p>  <code> reshape</code>前: <code>[ 0.5,  1.2,  3.4, ... ]</code>        <code>shape: (16,)</code><br>  <code>reshape</code>后: <code>[[ 0.5],</code><br>                 <code>[ 1.2],</code><br>                 <code>[ 3.4],</code><br>                   <code>...] </code>                                        <code>shape: (16, 1)</code><br>即：<span style="color:#FF9966">因为<code>train_x</code>是16个数据，每个数据有一个特征，所以也要把一开始仅仅是一行数据的<code>train_y</code>改成16个样本，每个样本有一个特征的形式</span></p></li></ol><h3 id="反向传播和优化器"><a href="#反向传播和优化器" class="headerlink" title="反向传播和优化器"></a>反向传播和优化器</h3><p><code>optimizer.zero_grad()</code>：梯度清零</p><p><code>loss.backward()</code>：反向传播</p><p><code>optimizer.step()</code>：梯度更新</p><h4 id="optimizer-zero-grad-梯度清零函数"><a href="#optimizer-zero-grad-梯度清零函数" class="headerlink" title="optimizer.zero_grad() 梯度清零函数"></a>optimizer.zero_grad() 梯度清零函数</h4><p>给出梯度的概念：梯度就是损失函数对每个参数的导数（偏导数）其实际意义为</p><blockquote><p>“这个参数往哪个方向调一点点，loss 能下降得最快”</p></blockquote><p>比如线性回归 <code>y = wx + b</code>，梯度就是 <code>∂loss/∂w</code> 和 <code>∂loss/∂b</code>，分别告诉你 w 和 b 该怎么调。</p><p>PyTorch 的设计哲学是：梯度累加给用户更多灵活性。比如你想手动模拟一个大 batch（显存不够时），就可以多次 <code>backward()</code> 让梯度自动累加，最后只 <code>step()</code> 一次，效果等价于用大 batch 训练。但代价是：如果你不做累加，就必须手动清零。下面演示累加是什么意思：</p><p>假设某个参数的梯度，第一个 batch 算出来是 <code>0.3</code>：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">loss.backward()</span><br><span class="line"><span class="comment"># param.grad = 0.3</span></span><br></pre></td></tr></table></figure><p>第二个 batch 如果不清零，直接再 backward：</p><figure class="highlight py"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">loss.backward()</span><br><span class="line"><span class="comment"># param.grad = 0.3 + 0.5 = 0.8   ← 累加了</span></span><br></pre></td></tr></table></figure><p>然后 <code>optimizer.step()</code> 会用 <code>0.8</code> 去更新参数，而不是这个 batch 真正的梯度 <code>0.5</code>。</p><p>当显存不够、想用大 batch 但放不下时：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">optimizer.zero_grad()</span><br><span class="line"><span class="keyword">for</span> i, (X_batch, y_batch) <span class="keyword">in</span> <span class="built_in">enumerate</span>(loader):</span><br><span class="line">    loss = criterion(model(X_batch), y_batch) / accumulation_steps</span><br><span class="line">    loss.backward()         <span class="comment"># 梯度累加</span></span><br><span class="line">    <span class="keyword">if</span> (i + <span class="number">1</span>) % accumulation_steps == <span class="number">0</span>:</span><br><span class="line">        optimizer.step()    <span class="comment"># 累加几次后才更新</span></span><br><span class="line">        optimizer.zero_grad()</span><br></pre></td></tr></table></figure><p>此为梯度累加技巧，用小显存模拟大 batch。所以累加这个特性不是 bug，是 feature，只是默认场景下需要手动清零而已。</p><h4 id="loss-backward-反向传播函数"><a href="#loss-backward-反向传播函数" class="headerlink" title="loss.backward() 反向传播函数"></a>loss.backward() 反向传播函数</h4><p>反向传播是计算梯度的高效算法。</p><p>关键在于：神经网络是一个多层的复合函数，从输入到输出要经过很多步计算。要算 loss 对最前面参数的梯度，需要用链式法则一层层往回推。比如：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">输入 x</span><br><span class="line">  → z1 = w1 * x          <span class="comment">#（前向计算第一步） w1为权重</span></span><br><span class="line">  → z2 = w2 * z1         <span class="comment">#（前向计算第二步） w2为权重</span></span><br><span class="line">  → loss = (z2 - y)²     <span class="comment">#（算损失）    拿结果 z2 和真实值 y 比，算误差（即均方误差）</span></span><br><span class="line">    </span><br></pre></td></tr></table></figure><p>现在想求 <code>∂loss/∂w1</code>，也就是 w1 对 loss 的影响有多大。</p><p>直接看不容易，但用链式法则从后往前拆：<code>∂loss/∂w1 = ∂loss/∂z2  ×  ∂z2/∂z1  ×  ∂z1/∂w1</code>,从 loss 出发，反向一层一层乘回去，就能算出最前面 w1 的梯度。这就是”反向传播”名字的由来——和前向计算方向相反。<span style="color:#FF9966">(复合函数求偏导)</span>。PyTorch 在你做前向计算时，会偷偷记录一张<strong>计算图</strong>（记录每一步用了什么运算、依赖关系）。当你调用 <code>loss.backward()</code> 时，它就沿着这张图从后往前，用链式法则一次性算出所有参数的梯度，存到每个参数的 <code>.grad</code> 属性里。所以 <code>loss.backward()</code> 这一行代码，干的事情就是：<strong>从 loss 开始反向走 → 链式法则逐层求导 → 把结果存进每个参数的 .grad</strong></p><h4 id="Why在正向传播的时候把梯度算出来，非要加一个反向传播？"><a href="#Why在正向传播的时候把梯度算出来，非要加一个反向传播？" class="headerlink" title="Why在正向传播的时候把梯度算出来，非要加一个反向传播？"></a>Why在正向传播的时候把梯度算出来，非要加一个反向传播？</h4><p>因为不知道目标是什么。前向传播时还没算出 loss，不知道最终误差是多少，自然没法算”误差对参数的梯度”。必须先走到终点拿到 loss，才能往回推。</p><p>想象开车从 A 到 B，路上经过很多路口：A → 路口1 → 路口2 → 路口3 → B。</p><ul><li><p>前向传播：从 A 出发，一个路口一个路口往前开，最终到达 B，发现走偏了 10 公里</p></li><li><p>反向传播：从 B 往回看，”在路口3 我应该左转一点，在路口2 应该右转一点……”</p></li></ul><p>前向的时候还不知道最终偏了多少，所以我们不知道每个路口该怎么修正。只有到了终点发现误差，才能往回推算每一步该负多少责任。</p><p>从公式上看：<code>∂loss/∂w1 = ∂loss/∂z2 × ∂z2/∂z1 × ∂z1/∂w1</code>,  <code>∂z1/∂w1</code> 前向时确实能算，但其中<code>∂loss/∂z2</code> 要等 loss 算出来才知道。中间的 <code>∂z2/∂z1</code> 也要等 z2 算出来才知道。链条最后一环永远要等前向走完才能确定，所以没法真正”边走边算”，只能”走完再回头”。</p><h4 id="optim-SGD-优化器"><a href="#optim-SGD-优化器" class="headerlink" title="optim.SGD() 优化器"></a><code>optim.SGD()</code> 优化器</h4><p><code>optimizer = optim.SGD(model.parameters(), lr=0.01)</code></p><p><code>optim.SGD</code>：选择 SGD 这个优化算法。SGD 全称是 Stochastic Gradient Descent（随机梯度下降），就是最基础的梯度下降法，每次用一个 batch 的数据算梯度然后更新参数。</p><p><code>model.parameters()</code>：告诉优化器”你要负责更新哪些参数”。这里把模型里所有的 weight 和 bias 都交给它管，之后 <code>optimizer.step()</code> 就会更新这些参数。</p><p><code>lr=0.01</code>：学习率设为 0.01，控制每次参数更新的步子大小。0.01 意味着每次只走梯度值的 1%，步子比较小，更新比较稳。</p><h4 id="optimizer-step-梯度更新函数"><a href="#optimizer-step-梯度更新函数" class="headerlink" title="optimizer.step()梯度更新函数"></a><code>optimizer.step()</code>梯度更新函数</h4><p>拿着反向传播算出来的梯度，按公式修改参数值，让 loss 变小。对于每个参数：新参数 &#x3D; 旧参数 - 学习率 × 梯度（梯度指向的是 loss 增大的方向，而我们要让 loss 减小，所以要反着走（减去梯度）。这叫梯度下降。）即<code>optimizer.step()</code> 这一行代码，帮你对所有参数执行了下面的操作。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">model.weight = model.weight - lr * model.weight.grad</span><br><span class="line">model.bias   = model.bias   - lr * model.bias.grad</span><br><span class="line"><span class="comment"># 假设当前 weight = 2.0，反向传播算出梯度 grad = 0.5，学习率 lr = 0.1</span></span><br><span class="line"><span class="comment"># 新 weight = 2.0 - 0.1 × 0.5 = 2.0 - 0.05 = 1.95</span></span><br><span class="line"><span class="comment"># 参数从 2.0 变成了 1.95，往梯度指的方向走了一小步。</span></span><br><span class="line"><span class="comment"># 下一个 batch 再算、再走一步，反复很多轮，参数就慢慢逼近最优值。</span></span><br></pre></td></tr></table></figure><h4 id="损失函数、反向传播和优化器的关系"><a href="#损失函数、反向传播和优化器的关系" class="headerlink" title="损失函数、反向传播和优化器的关系"></a>损失函数、反向传播和优化器的关系</h4><ol><li><p>不同的损失函数会形成不同的 loss 曲面（可以想象成一个地形）。有的地形像一个光滑的碗，梯度下降能很快滑到最低点；有的地形坑坑洼洼，梯度下降容易卡在小坑里出不来。</p><ul><li><p>好的损失函数：曲面光滑、碗状，梯度明确指向最低点</p></li><li><p>差的损失函数：曲面崎岖、有多个局部最小值，容易卡住</p></li></ul><p>比如均方误差（MSE）对回归问题来说就是一个很好的光滑碗，所以回归任务默认用它。</p></li><li><p>反向传播给出下一步前进方向：比如站在曲面上的某个位置，反向传播看了一下周围，说”往这边走是下坡”。但不知道最低点在哪、离多远。你迈了一步，到了新位置，它再看一次，说”现在往那边走”，就这样一步一步挪。</p></li><li><p>优化器决定如何到达反向传播给出的下一步的方向，优化器选得好能少走弯路、少震荡、更快收敛。比如我们这基础 SGD 就是老老实实按<code>新参数 = 旧参数 - lr × 梯度</code>，但它有几个问题：</p></li></ol><ul><li>遇到平坦区域，梯度很小，走得极慢</li><li>遇到陡峭区域，梯度很大，容易震荡甚至发散</li><li>遇到狭长的山谷地形，会在两侧来回弹，迟迟到不了最低点</li></ul><p>所以还会有其他的优化器，比如Momentum（带惯性）和 Adam（最常用）</p><h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><h3 id="创建数据集"><a href="#创建数据集" class="headerlink" title="创建数据集"></a>创建数据集</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">create_dataset</span>():</span><br><span class="line">    <span class="comment"># 1. 创建数据集对象.</span></span><br><span class="line">    x, y, coef = make_regression(</span><br><span class="line">        n_samples=<span class="number">100</span>,  <span class="comment"># 100个样本</span></span><br><span class="line">        n_features=<span class="number">1</span>,  <span class="comment"># 1个特征（特征点）</span></span><br><span class="line">        noise=<span class="number">10</span>,  <span class="comment"># 噪声，噪声越大，样本点越散</span></span><br><span class="line">        coef=<span class="literal">True</span>,  <span class="comment"># 是否返回系数，默认为False，返回值为None</span></span><br><span class="line">        bias=<span class="number">14.5</span>,  <span class="comment"># 偏置值</span></span><br><span class="line">        random_state=<span class="number">3</span>  <span class="comment"># 随机种子，随机种子相同，输出数据相同</span></span><br><span class="line">    )</span><br><span class="line">    <span class="comment"># 2. 把上述数据转换为张量</span></span><br><span class="line">    x = torch.tensor(x, dtype=torch.float32)</span><br><span class="line">    y = torch.tensor(y, dtype=torch.float32)</span><br><span class="line">    <span class="keyword">return</span> x, y, coef</span><br></pre></td></tr></table></figure><p><strong>输出x,y,coef含义如下如所示</strong></p><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260702161448070.png" alt="image-20260702161448070"></p><h3 id="模型训练"><a href="#模型训练" class="headerlink" title="模型训练"></a>模型训练</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">train</span>(<span class="params">x, y, coef</span>):</span><br><span class="line">    <span class="comment"># 1. 创建数据集对象. 把 tensor → 数据集对象 → 数据加载器.</span></span><br><span class="line">    dataset = TensorDataset(x, y)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 2. 创建数据加载器对象.</span></span><br><span class="line">    <span class="comment"># 参1: 数据集对象, 参2: 批次大小, 参3: 是否打乱数据(训练集打乱, 测试集不打乱)</span></span><br><span class="line">    dataloader = DataLoader(dataset, batch_size=<span class="number">16</span>, shuffle=<span class="literal">True</span>)</span><br><span class="line">    <span class="comment"># 3.创建初始的线性回归模型</span></span><br><span class="line">    <span class="comment"># 参1：输入特征维度，参2：输出特征维度</span></span><br><span class="line">    model = nn.Linear(<span class="number">1</span>, <span class="number">1</span>)</span><br><span class="line">    <span class="comment"># 4. 创建损失函数对象</span></span><br><span class="line">    criterion = nn.MSELoss()  <span class="comment"># 平方损失</span></span><br><span class="line">    <span class="comment"># 5. 创建优化器对象</span></span><br><span class="line">    optimizer = optim.SGD(model.parameters(), lr=<span class="number">0.01</span>)</span><br><span class="line">    <span class="comment"># 6.具体的训练过程</span></span><br><span class="line">    <span class="comment"># 6.1 定义变量，分别表示：训练论述，每轮的（平均）损失值，训练总损失值，训练的样本数</span></span><br><span class="line">    epochs, loss_list, total_loss, total_sample = <span class="number">100</span>, [], <span class="number">0.0</span>, <span class="number">0</span></span><br><span class="line">    <span class="comment"># 6.2 开始训练</span></span><br><span class="line">    <span class="keyword">for</span> epoch <span class="keyword">in</span> <span class="built_in">range</span>(epochs):</span><br><span class="line">        <span class="comment"># 6.3 每轮分批次训练</span></span><br><span class="line">        <span class="keyword">for</span> train_x, train_y <span class="keyword">in</span> dataloader:  <span class="comment"># 7批（16，16，16，16，16，16，4）</span></span><br><span class="line">            <span class="comment"># 6.4 模型预测</span></span><br><span class="line">            y_pred = model(train_x)  <span class="comment"># 输出二维</span></span><br><span class="line">            <span class="comment"># 6.5 计算（每批的平均）损失</span></span><br><span class="line">            loss = criterion(y_pred, train_y.reshape(-<span class="number">1</span>, <span class="number">1</span>))</span><br><span class="line">            <span class="comment"># 6.6 计算总损失 和 样本（批次）数</span></span><br><span class="line">            total_loss += loss.item()</span><br><span class="line">            total_sample += <span class="number">1</span></span><br><span class="line">            <span class="comment"># 6.7 梯度清零 + 反向传播 + 梯度更新</span></span><br><span class="line">            optimizer.zero_grad()  <span class="comment"># 梯度清零</span></span><br><span class="line">            loss.backward()  <span class="comment"># 反向传播。计算梯度</span></span><br><span class="line">            optimizer.step()  <span class="comment"># 梯度更新</span></span><br><span class="line">            <span class="comment"># 6.8 把本轮的（平均损失值），添加到列表中</span></span><br><span class="line">            loss_list.append(total_loss/total_sample)</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&#x27;轮数:<span class="subst">&#123;epoch+<span class="number">1</span>&#125;</span>，平均损失值:<span class="subst">&#123;total_loss/total_sample&#125;</span>&#x27;</span>)</span><br><span class="line">    <span class="comment"># 7.打印最终的训练结果</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;<span class="subst">&#123;epochs&#125;</span>轮的平均损失分别为：<span class="subst">&#123;loss_list&#125;</span>&#x27;</span>)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&#x27;模型参数，权重：<span class="subst">&#123;model.weight&#125;</span>, 偏置：<span class="subst">&#123;model.bias&#125;</span>&#x27;</span>)</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>训练结果：</p><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260704164257692.png" alt="image-20260704164257692"></p><h3 id="What-should-we-do"><a href="#What-should-we-do" class="headerlink" title="What  should we do?"></a>What  should we do?</h3><p>我们在模型训练的过程中来调整<code>超参数</code>使这些数据拟合度更高。从而能对新的数据预测精准，我们在拿到一堆数据之后主要做：</p><ol><li><p>训练过程前选定超参数</p><ul><li><p>模型结构<code>（Linear / 多层网络）</code></p></li><li><p>损失函数<code>（MSE）</code></p></li><li><p>优化器和学习率<code>（Adam, lr=0.001）</code></p></li><li><p>训练轮数（<code>epochs）</code></p></li><li><p>批大小<code>（batch_size）</code></p></li></ul></li><li><p>训练过程中程序自动执行，我们不介入</p><ul><li><p>优化器自动调 <code>weight</code> 和 <code>bias</code></p><ul><li><p><code>loss</code> 随之变化</p></li><li><p>跑完设定的轮数后结束</p></li></ul></li></ul></li><li><p>训练后：看结果决定要不要调</p><ul><li><p>第一轮：用 <code>SGD，lr=0.01</code>，训练 100 轮 → <code>loss</code> 降不下来</p></li><li><p>第二轮：换成 <code>Adam，lr=0.001</code>，训练 500 轮 →<code> loss</code> 降得很好 ✓</p></li><li><p>第三轮：再加一层网络，<code>lr=0.001</code>，训练 500 轮 → 更好了 ✓</p></li></ul></li></ol><h3 id="绘制曲线"><a href="#绘制曲线" class="headerlink" title="绘制曲线"></a>绘制曲线</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 8.绘制损失曲线</span></span><br><span class="line"><span class="comment">#             100轮          每轮的平均损失值</span></span><br><span class="line">plt.plot(<span class="built_in">range</span>(epochs),loss_list)</span><br><span class="line">plt.title(<span class="string">&#x27;损失值曲线变化图&#x27;</span>)</span><br><span class="line">plt.grid()</span><br><span class="line">plt.show()</span><br><span class="line"></span><br><span class="line"><span class="comment"># 9. 绘制预测值和真实值的关系.</span></span><br><span class="line"><span class="comment"># 9.1 绘制样本点分布情况.</span></span><br><span class="line">plt.scatter(x, y)  <span class="comment"># 画散点图。把 x 和 y 的每一对值作为一个点画在图上。</span></span><br><span class="line"><span class="comment"># 9.2 绘制训练模型的预测值.</span></span><br><span class="line"><span class="comment"># x: 100个样本点的特征.</span></span><br><span class="line">y_pred = torch.tensor(data = [v * model.weight + model.bias <span class="keyword">for</span> v <span class="keyword">in</span> x])</span><br><span class="line"><span class="comment"># 9.3 计算真实值.</span></span><br><span class="line">y_true = torch.tensor(data =[v * coef + <span class="number">14.5</span> <span class="keyword">for</span> v <span class="keyword">in</span> x])</span><br><span class="line"><span class="comment"># 9.4 绘制预测值 和 真实值的 折线图.</span></span><br><span class="line">plt.plot( x, y_pred, color = <span class="string">&#x27;red&#x27;</span>, label = <span class="string">&#x27;预测值&#x27;</span>)</span><br><span class="line">plt.plot(x, y_true, color = <span class="string">&#x27;green&#x27;</span>, label = <span class="string">&#x27;真实值&#x27;</span>)</span><br><span class="line"><span class="comment"># 9.5 图例, 网格.</span></span><br><span class="line">plt.legend()</span><br><span class="line">plt.grid()</span><br><span class="line"><span class="comment"># 9.6 显示图像.</span></span><br><span class="line">plt.show()</span><br></pre></td></tr></table></figure><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260704183626622.png" alt="image-20260704183626622"></p><p><img src="/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/image-20260704190145254.png" alt="image-20260704190145254"></p>]]>
    </content>
    <id>https://tysweb.pages.dev/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/</id>
    <link href="https://tysweb.pages.dev/2026/06/04/PyTorch%20%E5%85%A5%E9%97%A8%E2%80%94%E4%BB%8E%E5%BC%A0%E9%87%8F%E5%88%B0%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92/"/>
    <published>2026-06-04T02:04:06.000Z</published>
    <summary>
      <![CDATA[<p>PyTorch是一个用于机器学习和深度学习的开源深度学习框架，由Facebook于2016年发布，其主要实现了自动微分功能，并引入动态计算图使模型建立更加灵活。Pytorch可分为前后端两个部分，前端是与用户直接交互的python API，后端是框架内部实现的部分，包括Au]]>
    </summary>
    <title>PyTorch 入门—从张量到线性回归</title>
    <updated>2026-09-07T01:31:21.861Z</updated>
  </entry>
  <entry>
    <author>
      <name>ctyyy</name>
    </author>
    <category term="大模型" scheme="https://tysweb.pages.dev/categories/%E5%A4%A7%E6%A8%A1%E5%9E%8B/"/>
    <category term="AI" scheme="https://tysweb.pages.dev/tags/AI/"/>
    <category term="Claude Code" scheme="https://tysweb.pages.dev/tags/Claude-Code/"/>
    <content>
      <![CDATA[<h1 id="①安装Git-Bash"><a href="#①安装Git-Bash" class="headerlink" title="①安装Git Bash"></a>①安装Git Bash</h1><h1 id="②安装Claude-Code本体"><a href="#②安装Claude-Code本体" class="headerlink" title="②安装Claude Code本体"></a>②安装Claude Code本体</h1><p>PowerShell中输入</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">irm https:<span class="comment">//daheiai.com/cc.ps1 | iex</span></span><br><span class="line"><span class="comment">//来自：b站up主人工大黑</span></span><br></pre></td></tr></table></figure><p><img src="/images/image-20260527113304701.png" alt="image-20260527113304701"></p><h1 id="③配置环境变量"><a href="#③配置环境变量" class="headerlink" title="③配置环境变量"></a>③配置环境变量</h1><p><span style="color:red">作用：告诉操作系统在哪里可以找到可执行文件，这样你就可以在任何目录下直接运行命令，而不需要输入完整的文件路径。</span></p><p><img src="/images/image-20260527113856618.png" alt="image-20260527113856618"></p><p>输入Claude就可以快捷打开了</p><p><img src="/images/image-20260527114027766.png" alt="image-20260527114027766"></p><h1 id="④改变Claude-code的依赖接口"><a href="#④改变Claude-code的依赖接口" class="headerlink" title="④改变Claude code的依赖接口"></a>④改变Claude code的依赖接口</h1><p>安装CCswitch，用于改变Claude围绕的中间AI模型</p><p><img src="/images/image-20260527114709612.png" alt="image-20260527114709612"></p><p>Claude、GPT 等模型可通过**<a href="https://api.daheiai.com/">API中转站</a>**接入。</p><p>然后添加模型</p><p><img src="/images/image-20260527123658656.png" alt="image-20260527123658656"></p><p>添加完模型之后就会发现命令行中可以正常使用</p><p><img src="/images/image-20260527123211088.png" alt="image-20260527123211088"></p><p><img src="/images/image-20260527115647133.png" alt="image-20260527115647133"></p><h1 id="⑤用法：用于项目指导"><a href="#⑤用法：用于项目指导" class="headerlink" title="⑤用法：用于项目指导"></a>⑤用法：用于项目指导</h1><p><img src="/images/image-20260527124108036.png" alt="image-20260527124108036"></p><p><img src="/images/image-20260527124212256.png" alt="image-20260527124212256"></p><p><span style="color:red">当关闭掉终端，然后再回来的时候，可以输入<code>/resume</code>命令来找到之前的对话内容。</span></p><p><span style="color:red">当对话长度大于上下文长度，就需要通过输入<code>/compact</code>来压缩，但是很难恢复压缩前的上下文。</span></p><h1 id="⑥用法：文献查询功能"><a href="#⑥用法：文献查询功能" class="headerlink" title="⑥用法：文献查询功能"></a>⑥用法：文献查询功能</h1><h3 id="Zotero的使用"><a href="#Zotero的使用" class="headerlink" title="Zotero的使用"></a>Zotero的使用</h3><p>安装zotero桌面版并且注册完之后，需要：</p><ol><li><p>去中文社区安装市场插件，装入zotero。以后所有的其余插件都可以在市场插件搜到</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://zotero-chinese.com/plugins/#search=%E5%B8%82%E5%9C%BA</span><br></pre></td></tr></table></figure><p><img src="/images/image-20260527210859468.png" alt="image-20260527210859468"></p></li><li><p>文献的初抓取</p><ul><li>安装浏览器扩展（zotero的官方链接，下图所示），安装茉莉花插件（从市场插件中安装）</li></ul><p><img src="/images/image-20260527212156114.png" alt="image-20260527212156114"></p><ul><li><p>找到一篇文章：<a href="https://arxiv.org/">https://arxiv.org/</a></p></li><li><p>用浏览器的插件抓取到zotero中<img src="/images/image-20260527212952370.png" alt="image-20260527212952370"></p><p><img src="/images/image-20260527213043138.png" alt="image-20260527213043138"></p></li><li><p>如果抓取失败（反扒机制很好），那么只需要手动下载pdf，然后拖到zotero中就可以了</p><p><img src="/images/image-20260527214359297.png" alt="image-20260527214359297"></p></li></ul><h3 id="Claude-Code进行论文查询"><a href="#Claude-Code进行论文查询" class="headerlink" title="Claude Code进行论文查询"></a>Claude Code进行论文查询</h3><ol><li><p>首先去让CC拉下来Github中zotero的自动化程序</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">https:<span class="comment">//github.com/54yyyu/zotero-mcp</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//Zotero-MCP 是一个基于 Model Context Protocol（MCP）的开源工具，允许 AI 助手（如 Claude、Cursor、Cherry Studio 等）安全地访问和操作本地 Zotero 文献库，实现文献搜索、元数据读取、全文（PDF）提取与 PDF 注释分析，无需手动上传文件。‌</span></span><br></pre></td></tr></table></figure></li><li><p>打开zotero setup</p><p><img src="/images/image-20260527214904059.png" alt="image-20260527214904059"></p></li><li><p>然后直接让CC给你查就行了</p></li></ol></li></ol><p><span style="color:red">注意Claude Code只能访问本地的zotero，然后对本地的zotero中的论文进行管理，不能帮你爬取新的论文</span></p>]]>
    </content>
    <id>https://tysweb.pages.dev/2026/05/27/Claude%20Code/</id>
    <link href="https://tysweb.pages.dev/2026/05/27/Claude%20Code/"/>
    <published>2026-05-27T02:43:00.000Z</published>
    <summary>
      <![CDATA[<h1 id="①安装Git-Bash"><a href="#①安装Git-Bash" class="headerlink" title="①安装Git Bash"></a>①安装Git Bash</h1><h1 id="②安装Claude-Code本体"><a href="#②]]>
    </summary>
    <title>Claude Code</title>
    <updated>2026-09-07T01:31:21.808Z</updated>
  </entry>
</feed>
