<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/rss/feed.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>铃月の小屋</title><description>欢迎光临～今天的甜点也想和你分享</description><link>https://astro-jianyanya.pages.dev</link><item><title>Glowspire</title><link>https://astro-jianyanya.pages.dev/post/glowspire</link><guid isPermaLink="false">glowspire</guid><description>构词: Glow(萤火微光)+sprie(低语,螺旋,也有启迪之意)
界面介绍
UI 界面
设置内容
外观设置
整体以萤火虫为主题,以浅绿色作为主题色,采用可调节透明度的毛玻璃材质
聊天

背景虚化程度变化滑钮
使用模型的名称和版本

TT 语音

填入 MinMax API 密钥
音色克隆 id</description><pubDate>Tue, 13 Oct 2026 15:21:00 GMT</pubDate><content:encoded>&lt;p&gt;构词: Glow(萤火微光)+sprie(低语,螺旋,也有启迪之意)&lt;/p&gt;
&lt;h1&gt;界面介绍&lt;a href=&quot;#界面介绍&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2&gt;UI 界面&lt;a href=&quot;#ui-界面&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;设置内容&lt;a href=&quot;#设置内容&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;外观设置&lt;a href=&quot;#外观设置&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;整体以萤火虫为主题,以浅绿色作为主题色,采用可调节透明度的毛玻璃材质&lt;/p&gt;
&lt;h3&gt;聊天&lt;a href=&quot;#聊天&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;背景虚化程度变化滑钮&lt;/li&gt;
&lt;li&gt;使用模型的名称和版本&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;TT 语音&lt;a href=&quot;#tt-语音&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;填入 MinMax API 密钥&lt;/li&gt;
&lt;li&gt;音色克隆 id&lt;/li&gt;
&lt;li&gt;设置前置静音时长&lt;/li&gt;
&lt;li&gt;语音播放开关&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;ASR 设置&lt;a href=&quot;#asr-设置&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;语音识别开关&lt;/li&gt;
&lt;li&gt;GPU 加速开关&lt;/li&gt;
&lt;li&gt;说话方式选择(按住说话/自由说话)&lt;/li&gt;
&lt;li&gt;识别后发送方式(先填入输入框,确认之后再手动发送/识别完自动发送)&lt;/li&gt;
&lt;li&gt;识别的模型&lt;/li&gt;
&lt;li&gt;识别质量/速度选择&lt;/li&gt;
&lt;li&gt;VAD 灵敏度设置&lt;/li&gt;
&lt;li&gt;静默判定时长设置&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;声纹管理&lt;a href=&quot;#声纹管理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;声纹门禁开关&lt;/li&gt;
&lt;li&gt;声纹严格程度&lt;/li&gt;
&lt;li&gt;声纹录入功能&lt;/li&gt;
&lt;li&gt;麦克风检查是否可用&lt;/li&gt;
&lt;li&gt;输入电平表+频谱柱状图&lt;/li&gt;
&lt;li&gt;声纹录制的提示词引导&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1&gt;角色模型整体(大脑+声音+形象模型)&lt;a href=&quot;#角色模型整体大脑声音形象模型&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;整个聊天室本质是一个循环状态机:&lt;/strong&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/img/posts/glowspire-structure.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;
&lt;h2&gt;选 Qwen 的小模型作为训练对象，用 Unsloth + QLoRA 微调&lt;a href=&quot;#选-qwen-的小模型作为训练对象用-unsloth--qlora-微调&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;下面用 qwen3.5-9B 模型演示流程,因为最后有多个版本&lt;/strong&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/img/posts/glowspire-model-flow.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;效果:&lt;/strong&gt; 模型体量小,数据干净,满足聊天模型的需求
1. 本地部署本地跑,无费用消耗
2. 模型体量小,性能要求低,回复速度快
3. 数据干净,角色扮演效果好&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;本地模型训练(基座模型 + 持续喂数据微调)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置环境: 选用阿里云端开发环境/魔塔社区一条龙部署(优先)&lt;/li&gt;
&lt;li&gt;数据来源: 选用游戏原对话作为”种子对话”,调用其他大模型进行扩写&lt;/li&gt;
&lt;li&gt;定向扩展: 对扩写内容进行润色,筛选,添加偏向预期性格的内容&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Unsloth + QLoRA 微调&lt;a href=&quot;#unsloth--qlora-微调&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;第一步：数据准备&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;格式上,Qwen3 用的是&lt;strong&gt;ChatML&lt;/strong&gt;对话格式,所以对话数据集要按&lt;strong&gt;ShareGPT&lt;/strong&gt;风格组织成 JSONL,每条是一段多轮对话：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&quot;conversations&quot;&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;span&gt;&quot;from&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &quot;system&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;value&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &quot;人设卡部分&quot;&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;span&gt;&quot;from&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &quot;human&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;value&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &quot;今天好累啊&quot;&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;span&gt;&quot;from&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &quot;gpt&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;value&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &quot;怎么啦？过来，跟我说说。&quot;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;记住人设卡是”她”人格的锚点.
然后按之前说的策略：游戏里导出种子对话 → 进行数据筛选和去重 + 编写数据合并 → 训练空白模型(未经过微调,仅保证人设) → 试训得到数据进行数据清洗后加入数据集，数据里的对话轮次要有长短变化(1 轮到 8 轮都有),情绪要多样,否则模型只会复读一种句式，白费功夫。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二步：4-bit 加载模型&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;from unsloth &lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; FastLanguageModel&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;model&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; tokenizer = FastLanguageModel.from_pretrained(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    model_name=&lt;/span&gt;&lt;span&gt;&quot;unsloth/Qwen3.5-4B&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;   # 云上16G档；本地8G卡换成 Qwen3.5-4B&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    max_seq_length=2048&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    load_in_4bit=True&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;               # 4-bit NF4 量化 + 双重量化&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;QLoRA 的原理就是：基座模型冻结不动，用 4-bit 量化压缩到原来的四分之一显存，只训练挂在旁边的 LoRA 适配器（一小撮低秩矩阵）。8B 模型量化后约 4-5GB，加上优化器状态和激活值，16GB 显存很宽裕。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三步：挂 LoRA 适配器&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;model &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; FastLanguageModel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get_peft_model&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    model&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    r&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;                     # 角色类任务 &lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;32&lt;/span&gt;&lt;span&gt; 够用&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    lora_alpha&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    lora_dropout&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    target_modules&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&quot;q_proj&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&quot;k_proj&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&quot;v_proj&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&quot;o_proj&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                    &quot;gate_proj&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&quot;up_proj&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&quot;down_proj&quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;r 是低秩维度，可以理解为”给模型留了多少可塑空间”。r=16 意味着要训练的参数只有几百 MB，这就是为什么 8GB 也能训练 8B 模型，其实只动了模型 1% 不到的参数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第四步：训练超参数&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;学习率 5e-5 起步，epoch 先设 1（角色微调经常一轮就够，多轮极易过拟合成人设复读机），batch size 2 + 梯度累积 4，优化器用 adamw_8bit 省显存，训练时监控 loss。这里有个反直觉的点：&lt;strong&gt;loss 越低不代表模型越好&lt;/strong&gt;，训练 loss 在降而验证集 loss 在升，就是模型在背你的数据集，跟”她”聊新话题就会崩。我记录中的极差最大的比最小大了 3 倍之高&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第五步：中途验证效果&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;训练完先不合并，用验证集那 10-15% 的样本让模型生成回复，跟基座模型对照。检查三件事：回复是否遵循人设、语气是否一致、有没有复读训练数据原文。如果微调后跟基座输出几乎没差别，说明适配器没生效（检查有没有加载对 checkpoint）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第六步：合并与导出&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;LoRA 适配器本身不能独立部署，要合并回基座：model.save_pretrained_merged() 得到完整权重，再用 llama.cpp 的 convert_hf_to_gguf.py 导出 GGUF 格式，量化选 Q5_K_M（8B 模型约 4.6GB）。然后写个 Ollama Modelfile 就能本地加载了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第七步：部署聊天 + 收集问题 + 迭代循环&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这一步必须强调：&lt;strong&gt;训练和推理时的 prompt 模板要完全一致&lt;/strong&gt;。在训练数据里 system 字段写了人设卡，推理时就必须同样把人设卡放进 system 位置，格式错一点，模型的表现就掉一档。部署后进入迭代循环：跟”她”聊 → 记录人设崩掉的场景 → 针对这些场景补数据 → 再训一轮。每次迭代的数据集才是真正的资产，为后面的模型训练垫基。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;角色音声模型+AEC 回声消除+VAD+声纹校验+活检(活体检测)+ASR+TTS 合成&lt;a href=&quot;#角色音声模型aec-回声消除vad声纹校验活检活体检测asrtts-合成&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;figure&gt;&lt;img src=&quot;/img/posts/glowspire-audio-flow.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;效果:&lt;/strong&gt;  复刻角色独有音色,会断句,有情绪语气语调,能识别个人音色
1. 能复刻你想要的角色声色
2. 说话有情绪,更贴近真人,说话更生动
3. 只对你说话有响应,只认你的声音,是你的个人专属盆友哦&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;云端或本地部署,输出情绪,有语气,tts 接口选择&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;音色克隆: minimax 克隆 id/本地训练音色模型&lt;/li&gt;
&lt;li&gt;声纹校验: 现技术较成熟,使用 CAM++可简单精准的实现&lt;/li&gt;
&lt;li&gt;情绪输出: 把情绪标注能力”蒸馏”进微调模型/二次调用分析情绪关键词&lt;/li&gt;
&lt;li&gt;tts 接口: minimax 的 tts 接口(付费)/本地 tts 模型(GPT-SoVITS 完全免费)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;注意事项:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;本地 tts 模型免费但是效果差,且比较占性能,minimax 付费但较便宜,效果更好&lt;/li&gt;
&lt;li&gt;隐私问题,因为一旦调用 tts 接口,消息暴露,对于该项目存在问题,不介意的话推荐选付费&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;第一步: 音色克隆&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;推荐选择&lt;a href=&quot;https://www.minimax.io/audio&quot;&gt;MiniMax 的官方克隆&lt;/a&gt;，需要谷歌账户登录，且首次克隆需要花费额度，只能充值，上传 10 秒以上的人声(越纯净越好)，直接克隆生成就行，会获取克隆模型的 id，后续直接在接口中填写该克隆音色 id 即可，或者走 &lt;strong&gt;GPT-SoVITS&lt;/strong&gt; 的微调流程产出 .ckpt 权重文件.
这一步的关键就在素材的质量,直接决定了成品效果。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二步: 音频采集&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这一步就是把麦克风收到的声音变成程序能用的数字数据(PCM)。Electron 是 Chromium 内核，用 &lt;code&gt;getUserMedia&lt;/code&gt; 打开麦克风拿到音频流，再接到 Web Audio 上:&lt;code&gt;AudioContext&lt;/code&gt; + &lt;code&gt;AudioWorkletNode&lt;/code&gt;，由 AudioWorklet 在&lt;strong&gt;音频线程&lt;/strong&gt;上把声音切成 &lt;strong&gt;512 个样本一帧&lt;/strong&gt;，逐帧抛回主线程。
采样率统一按 &lt;strong&gt;16 kHz&lt;/strong&gt; 走，因为本地 whisper 只接受 16 kHz。麦克风自己是按原生率交付的(我的御葵 D80 是 USB 动圈麦，通常 48 kHz)，所以中间靠 &lt;code&gt;new AudioContext({ sampleRate: 16000 })&lt;/code&gt; 让 Chromium 内部做一次重采样 —— 不是设备本来就这么给。
没用 &lt;code&gt;MediaRecorder&lt;/code&gt; 而是用 AudioWorklet:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;它在音频线程上跑，主线程卡顿也不丢帧；&lt;/li&gt;
&lt;li&gt;是&lt;strong&gt;一次开麦能供多方复用&lt;/strong&gt; —— 电平表/频谱、送识别的音频帧、声纹录入的录音都取同一路流，避免反复开麦(会触发授权弹窗和设备独占)。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;采到的帧在主线程按 512 样本拼成整段，打包成 16 kHz WAV，&lt;code&gt;POST /asr&lt;/code&gt; 交给本地 whisper。
这一步的关键就在&lt;strong&gt;采样率&lt;/strong&gt;&lt;/p&gt;&lt;div&gt;&lt;/div&gt;，whisper 直接识别不出来。&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三步: AEC 回声消除&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;AEC 回声清除，这个的功能就是为了&lt;strong&gt;把设备自己放的歌/说的话，从麦克风里消掉&lt;/strong&gt;
我的回声主要来源就是自己的 TTS 从扬声器播出来的声音。Electron 是 Chromium 内核，&lt;code&gt;getUserMedia({ audio: { echoCancellation: true, noiseSuppression: true, autoGainControl: true } })&lt;/code&gt; 直接启用 WebRTC 的 AEC，只要采集和播放发生在同一个 Electron 窗口里（我的情况正好满足），回声抑制效果就不错。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第四步：VAD 断句(Silero VAD)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;VAD 是”她怎么知道你说完了”这个问题的答案,2026 年本地项目的标配是 silero-vad ,一个 1.7MB 的 ONNX 模型,纯 CPU 跑,自带 Python 库,对音频流逐帧输出”有没有人说话”的概率,逻辑是：检测到语音开始 → 持续累积音频 → 连续 500-800 毫秒静音判定为你这句话说完了 → 把这一整段音频切出来交给下一级,这 500-800ms 是”尾静音”,定短了容易截断你的话,定长了显得她反应慢.还有一个进阶功能叫打断(barge-in): 她在说话时,如果你开口了,VAD 立刻检测到,就中止 TTS 播放切回聆听状态.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第五步：声纹校验(CAM++)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CAM++ 模型(ModelScope 上有现成的,中文场景 SOTA)在 CPU 上处理 3 秒音频只要十几毫秒.流程是: 注册阶段录你 10-30 秒的话,提取出一个 192 维的声纹向量存到本地文件.运行时把 VAD 切出的同一段音频也提一个向量,算余弦相似度,超过阈值(CAM++ 一般取 0.7 左右)判定是你本人.注意它和 ASR 是两码事：ASR 识别”说的什么”,声纹只回答”是不是你”,把校验放在 ASR 之前,不是你的声音就直接丢弃,省一次 ASR 计算.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可选项: 活检&lt;/strong&gt;
防止别人放录音冒充你
但是在这个项目里实用性不大,因为这个也并非是啥隐私应用,只是这里做了声纹检验之后可以加入活检在你的声音上加一层锁,相关应用有微信的声音识别登录,和常规的声音开锁&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;实用路线(推荐)：随机口令挑战——每次解锁时让萤语随机报 4-6 位数字让你跟读，ASR 验证内容 + 声纹验证身份，“内容对 + 声音对”双因子。实现简单，对抗普通录音重放够用。&lt;/li&gt;
&lt;li&gt;学术路线：AASIST 之类的反欺骗模型，ONNX 也有，但误拒率调起来麻烦.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;第六步：ASR 语音转文字（SenseVoice）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;本地路线首选 &lt;strong&gt;whisper.cpp&lt;/strong&gt;：和 llama.cpp 同门，二进制往 &lt;code&gt;portable/&lt;/code&gt; 里一扔，backend 子进程调用，和 &lt;code&gt;llama.js&lt;/code&gt; 管理 llama-server 的代码模式一模一样，ggml-small 模型约 500MB，中文效果可用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第七步：LLM 生成&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;把 ASR 的文本或者输入对话文本接到人设卡 system prompt 的完整对话历史里,然后模型输出结构化格式,比如 {“emotion”: “温柔”, “reply”: “怎么啦，过来跟我说说”},解析出两个字段,文本送 TTS,情绪映射成 TTS 参数.
这里我额外做了一层过滤层&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;过滤动作标签,即去除动作标签后发送给 TTS,不播放动作内容&lt;/li&gt;
&lt;li&gt;过滤情绪标签和插入的语气词,发给用户看&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;第七步：TTS 合成与播放&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;现在用 MiniMax API：拿 voice_id + 文本 + emotion 参数请求合成(可以开 SSE 流式，边合成边播),返回音频流交给 pyaudio 播放,以后切本地方案时,GPT-SoVITS 自带 API 服务模式,代码层只改请求地址,胶水层逻辑一模一样,CosyVoice 2 的流式合成对延迟更友好，作为本地方案的升级选项.&lt;/p&gt;</content:encoded><category>category:复合对话Agent</category><category>tag:LLM</category><category>tag:Agent</category></item><item><title>博客主题样式设计</title><link>https://astro-jianyanya.pages.dev/post/blog-theme-style</link><guid isPermaLink="false">blog-theme-style</guid><description>整体
博客作者名叫 jianyanya
域名就是 Belluna.jjy
日系轻甜女仆咖啡厅 + 红金暖调 + 少量猫娘元素
红是主角，金是亮点，黑白是骨架，粉是糖。
主题整体颜色建议配比: 60% 中性色 + 30% 红/黑 + 10% 金/粉。</description><pubDate>Tue, 13 Oct 2026 15:19:00 GMT</pubDate><content:encoded>&lt;h2&gt;整体&lt;a href=&quot;#整体&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;博客作者名叫 jianyanya
域名就是 Belluna.jjy
&lt;strong&gt;日系轻甜女仆咖啡厅 + 红金暖调 + 少量猫娘元素&lt;/strong&gt;&lt;br /&gt;
红是主角，金是亮点，黑白是骨架，粉是糖。&lt;br /&gt;
主题整体颜色建议配比: &lt;strong&gt;60% 中性色 + 30% 红/黑 + 10% 金/粉&lt;/strong&gt;。
主色来自红发/猫耳/猫尾，辅色来自琥珀金眼睛，黑白女仆装负责结构和文字，粉色做可爱点缀。&lt;/p&gt;
&lt;h2&gt;配色建议&lt;a href=&quot;#配色建议&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;不要做成全黑哥特，也不要全粉幼态，更不要满屏蕾丝猫爪，否则会乱。&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;背景：     &lt;/span&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;FFF8F0&lt;/span&gt;&lt;span&gt;   奶油白&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;卡片：     &lt;/span&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;FFFFFF&lt;/span&gt;&lt;span&gt;   纯白&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;正文：     &lt;/span&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;2B2B2B   深灰&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;弱文字：   &lt;/span&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;6B5B55   暖灰&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;主色：     &lt;/span&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;B83B3B&lt;/span&gt;&lt;span&gt;   女仆红&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;主色hover： &lt;/span&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;972F2F   深红&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;辅色：     &lt;/span&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;D99A2B&lt;/span&gt;&lt;span&gt;   琥珀金&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;浅粉：     &lt;/span&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;F6D6D6&lt;/span&gt;&lt;span&gt;   腮红粉&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;边框：     &lt;/span&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;E8D9CC&lt;/span&gt;&lt;span&gt;   浅暖边&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;页脚：     &lt;/span&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;1F1F23   女仆黑&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;用法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;背景用奶油白，不要纯白刺眼。&lt;/li&gt;
&lt;li&gt;卡片纯白，加圆角和淡阴影。&lt;/li&gt;
&lt;li&gt;标题、链接、主按钮用女仆红。&lt;/li&gt;
&lt;li&gt;琥珀金只做图标、hover、进度条、小装饰。&lt;/li&gt;
&lt;li&gt;浅粉做标签、引用块背景。&lt;/li&gt;
&lt;li&gt;页脚用女仆黑，白字，加一点粉色猫爪。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;注意：&lt;/strong&gt; &lt;code&gt;#D99A2B&lt;/code&gt; 不要拿来当白底正文，对比度不够。金色文字要用 &lt;code&gt;#A66A00&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;整体视觉风格&lt;a href=&quot;#整体视觉风格&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;关键词：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;日系轻甜、女仆咖啡厅、红金暖调、圆角卡片、干净留白、猫娘元素、可爱但不幼态、活泼不花哨&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;具体设计：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;圆角&lt;/strong&gt;：12–16px，不要太尖。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;阴影&lt;/strong&gt;：柔和、低透明度，像咖啡厅暖光。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Logo&lt;/strong&gt;：猫耳剪影 + 小铃铛，或红发侧影。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;列表符号&lt;/strong&gt;：🐾 小爪印，但不要每行都加。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分割线&lt;/strong&gt;：细红金渐变线，像丝带。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;卡片&lt;/strong&gt;：白底，顶部一条 4px 红金渐变，像女仆围裙边。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;按钮&lt;/strong&gt;：主按钮红底白字；次按钮白底红边；hover 变金。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;标签&lt;/strong&gt;：浅粉底、深红字、圆角胶囊。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;引用块&lt;/strong&gt;：左边红色竖线，浅粉背景。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;页脚&lt;/strong&gt;：女仆黑底，白字，加粉色猫爪或爱心。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;头像区&lt;/strong&gt;：角色立绘 + 对话框，像女仆咖啡厅自我介绍。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;字体&lt;a href=&quot;#字体&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;中文标题：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;站酷快乐体、得意黑、霞鹜文楷&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;中文正文：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;思源黑体、更纱黑体、MiSans、HarmonyOS Sans SC&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;英文标题：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;Quicksand、Baloo 2、Comfortaa&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;英文正文：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;Inter、Nunito Sans&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded><category>category:博客建设</category><category>tag:博客</category></item><item><title>基于 WiFi 指纹的社区自习室座位引导与占座检测系统</title><link>https://astro-jianyanya.pages.dev/post/wifi-seat-system-doc</link><guid isPermaLink="false">wifi-seat-system-doc</guid><description>1. 文档说明
本文档用于指导“基于 WiFi 指纹的社区自习室无感座位引导与占座检测系统”的产品设计、软件开发、算法实验、现场部署和结题验收。
本文档基于项目原方案整理，并对原方案中“Android 或微信小程序均可作为前端”的表述进行了工程化修正。原方案要求完成 WiFi</description><pubDate>Tue, 13 Oct 2026 14:46:00 GMT</pubDate><content:encoded>&lt;h2&gt;1. 文档说明&lt;a href=&quot;#1-文档说明&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本文档用于指导“基于 WiFi 指纹的社区自习室无感座位引导与占座检测系统”的产品设计、软件开发、算法实验、现场部署和结题验收。&lt;/p&gt;
&lt;p&gt;本文档基于项目原方案整理，并对原方案中“Android 或微信小程序均可作为前端”的表述进行了工程化修正。原方案要求完成 WiFi 指纹采集、座位级定位、占用识别、占座检测、座位引导、管理统计和现场评估；本文档进一步明确模块边界、技术选型、接口、数据结构、开发顺序和验收标准。&lt;/p&gt;
&lt;p&gt;本文档的核心决策如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户端采用 Android 原生应用，使用 Kotlin 开发。&lt;/li&gt;
&lt;li&gt;Android 端同时承担普通用户功能和 WiFi 指纹采集功能。&lt;/li&gt;
&lt;li&gt;管理员端采用 Web 管理后台，避免把复杂管理功能塞进移动端。&lt;/li&gt;
&lt;li&gt;后端采用 Spring Boot，数据库采用 MySQL。&lt;/li&gt;
&lt;li&gt;算法训练和在线推理由 Python 完成，初期通过独立算法服务提供接口。&lt;/li&gt;
&lt;li&gt;第一版只支持一个自习室，先完成完整闭环，再扩展多房间和小程序入口。&lt;/li&gt;
&lt;li&gt;座位状态采用“算法判断 + 可信度 + 管理员复核”机制，不把设备信号直接等同于人员在座。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;2. 平台选择结论&lt;a href=&quot;#2-平台选择结论&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;2.1 为什么不把微信小程序作为主要客户端&lt;a href=&quot;#21-为什么不把微信小程序作为主要客户端&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;项目的核心能力是 WiFi 指纹采集和基于 RSSI 的座位级判断。微信小程序虽然适合展示座位图和提供轻量服务，但存在以下限制：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;WiFi 扫描接口受手机系统、微信版本和用户授权影响。&lt;/li&gt;
&lt;li&gt;iOS 和 Android 的行为不一致。&lt;/li&gt;
&lt;li&gt;小程序不能保证后台持续采样。&lt;/li&gt;
&lt;li&gt;小程序生命周期较短，无法稳定执行长时间采样任务。&lt;/li&gt;
&lt;li&gt;小程序不能可靠地读取路由器连接日志。&lt;/li&gt;
&lt;li&gt;座位级指纹识别需要连续、重复、可控的采样，不能依赖偶发的一次扫描。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，微信小程序可以作为后期的查询入口，但不适合承担本项目的核心感知链路。&lt;/p&gt;
&lt;h3&gt;2.2 为什么选择 Android 原生应用&lt;a href=&quot;#22-为什么选择-android-原生应用&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Android 原生应用更适合本项目的原因如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;团队已有 Android Studio 和 Java/移动应用开发基础。&lt;/li&gt;
&lt;li&gt;Android 可以在用户授权后获取 WiFi 扫描结果。&lt;/li&gt;
&lt;li&gt;可以使用前台服务执行受控的周期性采样。&lt;/li&gt;
&lt;li&gt;可以直接提供采集模式、座位标注和上传功能。&lt;/li&gt;
&lt;li&gt;便于进行设备型号、权限和采样频率管理。&lt;/li&gt;
&lt;li&gt;适合在实验室和目标自习室中快速进行可重复实验。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Android 也不能绕过系统限制。正式实现必须让用户明确授权定位、附近设备和 WiFi 权限，并在需要持续采样时使用前台服务。系统应提供手动刷新和采样失败提示，不能假设所有设备都能无限制后台扫描。&lt;/p&gt;
&lt;h3&gt;2.3 最终产品形态&lt;a href=&quot;#23-最终产品形态&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img src=&quot;/img/posts/wifi-product.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;
&lt;p&gt;Android 用户端和 Android 采集端可以先做成同一个 APK，通过登录角色和工作模式区分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;普通用户模式：查看座位、开始使用、离开、反馈异常。&lt;/li&gt;
&lt;li&gt;采集模式：选择座位、连续采样、添加备注、上传数据。&lt;/li&gt;
&lt;li&gt;管理员模式：查看状态和处理异常，也可以通过 Web 后台完成。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3. 项目范围&lt;a href=&quot;#3-项目范围&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;3.1 第一版目标&lt;a href=&quot;#31-第一版目标&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;第一版应在一个真实或高度还原的自习室内完成以下闭环：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;建立座位地图和统一座位编号。&lt;/li&gt;
&lt;li&gt;采集多时段、多设备的 WiFi 指纹。&lt;/li&gt;
&lt;li&gt;建立座位级指纹库。&lt;/li&gt;
&lt;li&gt;根据 WiFi 特征识别用户所在座位或候选座位。&lt;/li&gt;
&lt;li&gt;显示空闲、使用中、疑似占座和维护中状态。&lt;/li&gt;
&lt;li&gt;提供空闲座位推荐。&lt;/li&gt;
&lt;li&gt;记录用户使用、离开和异常事件。&lt;/li&gt;
&lt;li&gt;为管理员提供人工复核和手动修正功能。&lt;/li&gt;
&lt;li&gt;输出准确率、召回率、F1、座位周转率和占座事件等评估指标。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;3.2 第一版不做&lt;a href=&quot;#32-第一版不做&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;多社区租户管理。&lt;/li&gt;
&lt;li&gt;在线支付和会员体系。&lt;/li&gt;
&lt;li&gt;人脸识别或摄像头识别。&lt;/li&gt;
&lt;li&gt;需要额外铺设的压力传感器、RFID 或红外设备。&lt;/li&gt;
&lt;li&gt;复杂的预约收费规则。&lt;/li&gt;
&lt;li&gt;全自动处理所有“人不在但设备在”的情况。&lt;/li&gt;
&lt;li&gt;依赖微信小程序后台持续扫描 WiFi。&lt;/li&gt;
&lt;li&gt;跨城市部署和商业化运营能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.3 后续扩展&lt;a href=&quot;#33-后续扩展&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;微信小程序只读查询和推荐入口。&lt;/li&gt;
&lt;li&gt;多房间、多楼层和多社区。&lt;/li&gt;
&lt;li&gt;管理员 Web 大屏。&lt;/li&gt;
&lt;li&gt;用户偏好学习和个性化推荐。&lt;/li&gt;
&lt;li&gt;AP 网关日志接入。&lt;/li&gt;
&lt;li&gt;模型自动重训和漂移检测。&lt;/li&gt;
&lt;li&gt;预约、签到、信用和违规处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4. 用户角色和权限&lt;a href=&quot;#4-用户角色和权限&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;角色&lt;/th&gt;&lt;th&gt;权限&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;普通用户&lt;/td&gt;&lt;td&gt;查看自习室和座位、查看推荐、开始使用、释放座位、查看个人记录、提交反馈&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;采集人员&lt;/td&gt;&lt;td&gt;进入采集模式、选择座位、采集 RSSI、上传指纹、查看采样状态&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;管理员&lt;/td&gt;&lt;td&gt;查看所有座位、人工复核、释放座位、锁定座位、修改配置、查看报表&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;项目管理员&lt;/td&gt;&lt;td&gt;管理用户角色、管理房间和座位、管理 AP、管理模型版本、导出数据&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;所有管理操作都必须写入操作日志，普通用户不能访问原始指纹样本、原始设备标识和算法调试数据。&lt;/p&gt;
&lt;h2&gt;5. 核心业务定义&lt;a href=&quot;#5-核心业务定义&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;5.1 座位状态&lt;a href=&quot;#51-座位状态&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;系统使用以下状态：&lt;/p&gt;





































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;状态&lt;/th&gt;&lt;th&gt;含义&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;AVAILABLE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;当前可使用&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;CANDIDATE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;检测到疑似使用，但证据不足&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;OCCUPIED&lt;/code&gt;&lt;/td&gt;&lt;td&gt;已确认使用中&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;AWAY_CANDIDATE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;使用中的设备或信号暂时消失&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;SUSPECTED_HOLDING&lt;/code&gt;&lt;/td&gt;&lt;td&gt;疑似占座，需要继续观察或人工复核&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;MAINTENANCE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;管理员设置为维护中&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;UNKNOWN&lt;/code&gt;&lt;/td&gt;&lt;td&gt;数据过期、采集异常或系统无法判断&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;前端显示名称可以简化，但后端必须保留完整状态。&lt;/p&gt;
&lt;h3&gt;5.2 占座定义&lt;a href=&quot;#52-占座定义&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;第一版将“占座”定义为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;座位在较长时间内被判定为存在设备或持续占用证据，但缺乏正常使用行为，且超过配置的离开或占用阈值。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;系统输出的是“疑似占座”，不是法律意义上的确定违规。最终结果由管理员确认，管理员确认结果可用于后续模型评估和训练。&lt;/p&gt;
&lt;h3&gt;5.3 无感使用定义&lt;a href=&quot;#53-无感使用定义&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;本项目中的“无感”是指：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户不需要每次都扫码签到；&lt;/li&gt;
&lt;li&gt;用户不需要佩戴专用设备；&lt;/li&gt;
&lt;li&gt;系统尽量根据 WiFi 和时间行为自动更新状态；&lt;/li&gt;
&lt;li&gt;对无法可靠判断的情况提供一次点击确认或管理员复核。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不将“完全不需要用户授权、不需要任何确认”作为目标，因为这会造成误判和隐私风险。&lt;/p&gt;
&lt;h2&gt;6. 功能需求&lt;a href=&quot;#6-功能需求&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;6.1 Android 用户端&lt;a href=&quot;#61-android-用户端&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;登录与权限&lt;a href=&quot;#登录与权限&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;手机号或项目内部账号登录。&lt;/li&gt;
&lt;li&gt;申请 WiFi、定位、附近设备和通知权限。&lt;/li&gt;
&lt;li&gt;清楚说明权限用途。&lt;/li&gt;
&lt;li&gt;拒绝权限时仍可查看静态座位图，但不能使用需要采样的功能。&lt;/li&gt;
&lt;li&gt;支持退出登录和清除本地缓存。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;自习室和座位&lt;a href=&quot;#自习室和座位&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;查看自习室列表。&lt;/li&gt;
&lt;li&gt;查看开放时间、座位总数和空闲数量。&lt;/li&gt;
&lt;li&gt;查看座位平面图。&lt;/li&gt;
&lt;li&gt;按区域、靠窗、安静区等标签筛选。&lt;/li&gt;
&lt;li&gt;点击座位查看状态、更新时间和推荐原因。&lt;/li&gt;
&lt;li&gt;查看当前使用中的个人座位。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;座位推荐&lt;a href=&quot;#座位推荐&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;推荐过程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;过滤维护中和确认占用的座位。&lt;/li&gt;
&lt;li&gt;过滤数据过期的座位。&lt;/li&gt;
&lt;li&gt;根据用户偏好和区域条件排序。&lt;/li&gt;
&lt;li&gt;结合定位候选结果和座位可信度排序。&lt;/li&gt;
&lt;li&gt;返回最多 3 个推荐结果。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;推荐结果必须说明原因，例如“空闲时间较长”“位于安静区”“距离入口较近”，不能只给出一个不可解释的分数。&lt;/p&gt;
&lt;h4&gt;使用和释放&lt;a href=&quot;#使用和释放&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;点击“开始使用”后建立使用会话。&lt;/li&gt;
&lt;li&gt;系统继续根据采样结果更新状态。&lt;/li&gt;
&lt;li&gt;用户可以主动暂时离开。&lt;/li&gt;
&lt;li&gt;用户可以主动释放座位。&lt;/li&gt;
&lt;li&gt;应用异常退出后，后台根据超时机制处理会话。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;反馈&lt;a href=&quot;#反馈&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;座位状态错误。&lt;/li&gt;
&lt;li&gt;座位已被占用但系统显示空闲。&lt;/li&gt;
&lt;li&gt;系统显示占用但实际无人使用。&lt;/li&gt;
&lt;li&gt;WiFi 采样失败。&lt;/li&gt;
&lt;li&gt;地图和实际布局不一致。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6.2 Android 采集模式&lt;a href=&quot;#62-android-采集模式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;选择自习室、楼层和座位。&lt;/li&gt;
&lt;li&gt;显示当前采集设备信息。&lt;/li&gt;
&lt;li&gt;连续采集指定次数。&lt;/li&gt;
&lt;li&gt;每次采集记录时间和环境备注。&lt;/li&gt;
&lt;li&gt;显示已采样 AP 数量和有效 RSSI 数量。&lt;/li&gt;
&lt;li&gt;支持暂停、重采和删除异常样本。&lt;/li&gt;
&lt;li&gt;上传前显示数据摘要。&lt;/li&gt;
&lt;li&gt;上传后生成批次编号。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;建议每个座位每个时段至少采集 5 至 10 次，早、中、晚各采集一轮，并至少使用 2 至 3 种 Android 设备进行交叉验证。&lt;/p&gt;
&lt;h3&gt;6.3 Web 管理后台&lt;a href=&quot;#63-web-管理后台&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h4&gt;首页看板&lt;a href=&quot;#首页看板&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;房间总数。&lt;/li&gt;
&lt;li&gt;座位总数。&lt;/li&gt;
&lt;li&gt;空闲数量。&lt;/li&gt;
&lt;li&gt;使用中数量。&lt;/li&gt;
&lt;li&gt;疑似占座数量。&lt;/li&gt;
&lt;li&gt;数据异常数量。&lt;/li&gt;
&lt;li&gt;今日使用次数。&lt;/li&gt;
&lt;li&gt;今日平均使用时长。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;座位管理&lt;a href=&quot;#座位管理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;创建和编辑房间。&lt;/li&gt;
&lt;li&gt;设置座位编号。&lt;/li&gt;
&lt;li&gt;配置座位坐标。&lt;/li&gt;
&lt;li&gt;设置座位标签。&lt;/li&gt;
&lt;li&gt;设置维护状态。&lt;/li&gt;
&lt;li&gt;导入和导出座位布局。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;实时状态&lt;a href=&quot;#实时状态&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;查看完整座位地图。&lt;/li&gt;
&lt;li&gt;查看状态更新时间。&lt;/li&gt;
&lt;li&gt;查看可信度。&lt;/li&gt;
&lt;li&gt;查看对应设备会话的匿名编号。&lt;/li&gt;
&lt;li&gt;手动修改状态。&lt;/li&gt;
&lt;li&gt;查看状态变化历史。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;占座处理&lt;a href=&quot;#占座处理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;查看疑似占座列表。&lt;/li&gt;
&lt;li&gt;查看触发原因。&lt;/li&gt;
&lt;li&gt;查看信号和时间特征。&lt;/li&gt;
&lt;li&gt;标记为确认占座、正常使用或无法判断。&lt;/li&gt;
&lt;li&gt;添加人工备注。&lt;/li&gt;
&lt;li&gt;释放座位。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;数据和模型&lt;a href=&quot;#数据和模型&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;查看采样批次。&lt;/li&gt;
&lt;li&gt;查看无效样本。&lt;/li&gt;
&lt;li&gt;查看模型版本。&lt;/li&gt;
&lt;li&gt;发布或回滚模型。&lt;/li&gt;
&lt;li&gt;查看定位准确率。&lt;/li&gt;
&lt;li&gt;查看混淆矩阵和错误样本。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;统计分析&lt;a href=&quot;#统计分析&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;分时段使用率。&lt;/li&gt;
&lt;li&gt;座位周转率。&lt;/li&gt;
&lt;li&gt;各区域热度。&lt;/li&gt;
&lt;li&gt;平均使用时长。&lt;/li&gt;
&lt;li&gt;疑似占座数量。&lt;/li&gt;
&lt;li&gt;人工干预次数。&lt;/li&gt;
&lt;li&gt;系统启用前后对比。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;7. 系统架构&lt;a href=&quot;#7-系统架构&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;7.1 模块划分&lt;a href=&quot;#71-模块划分&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;android-app&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── user mode&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── collector mode&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── local cache&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── wifi scanner&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;└── foreground sampling service&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;backend&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── auth module&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── room module&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── seat module&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── occupancy module&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── recommendation module&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── event module&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── admin module&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;└── audit module&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;algorithm-service&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── preprocessing&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── fingerprint matching&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── occupancy scoring&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── model evaluation&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;└── model version management&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;admin-web&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── dashboard&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── room and seat management&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── alert review&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── data analysis&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;└── system configuration&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;7.2 数据流&lt;a href=&quot;#72-数据流&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;sequenceDiagram

    participant App as Android 客户端

    participant API as Spring Boot

    participant Algo as Python 算法服务

    participant DB as MySQL

    participant Admin as 管理后台

  

    App-&amp;gt;&amp;gt;API: 上传 WiFi 样本或使用事件

    API-&amp;gt;&amp;gt;Algo: 请求特征处理和座位推断

    Algo-&amp;gt;&amp;gt;API: 返回候选座位、状态和可信度

    API-&amp;gt;&amp;gt;DB: 保存状态事件和当前状态

    API--&amp;gt;&amp;gt;App: 返回座位状态

    Admin-&amp;gt;&amp;gt;API: 查询疑似占座

    API--&amp;gt;&amp;gt;Admin: 返回事件和特征摘要

    Admin-&amp;gt;&amp;gt;API: 提交人工复核结果

    API-&amp;gt;&amp;gt;DB: 保存复核结果
&lt;/pre&gt;
&lt;h3&gt;7.3 实时更新策略&lt;a href=&quot;#73-实时更新策略&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;第一版使用轮询：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Android 客户端进入房间页面后每 15 至 30 秒请求一次状态。&lt;/li&gt;
&lt;li&gt;后台状态事件产生后立即更新数据库。&lt;/li&gt;
&lt;li&gt;Redis 只缓存房间状态快照，不保存最终业务事实。&lt;/li&gt;
&lt;li&gt;座位状态超过配置时间没有新数据时变为 &lt;code&gt;UNKNOWN&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第二版再评估 WebSocket。只有在用户量和实时性需求确实增加后，才引入长连接。&lt;/p&gt;
&lt;h2&gt;8. Android 客户端设计&lt;a href=&quot;#8-android-客户端设计&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;8.1 技术选型&lt;a href=&quot;#81-技术选型&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Kotlin。&lt;/li&gt;
&lt;li&gt;Android Jetpack。&lt;/li&gt;
&lt;li&gt;MVVM 或单向数据流架构。&lt;/li&gt;
&lt;li&gt;Retrofit + OkHttp 访问后端。&lt;/li&gt;
&lt;li&gt;Room 保存本地任务和离线数据。&lt;/li&gt;
&lt;li&gt;Kotlin Coroutines 处理异步任务。&lt;/li&gt;
&lt;li&gt;WorkManager 处理可延迟同步。&lt;/li&gt;
&lt;li&gt;前台服务处理用户明确开启的连续采样。&lt;/li&gt;
&lt;li&gt;Canvas 或自定义 View 绘制座位地图。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;8.2 页面结构&lt;a href=&quot;#82-页面结构&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;启动页&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── 登录页&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── 权限说明页&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── 首页&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── 自习室选择&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── 座位地图&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── 座位详情&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   └── 推荐结果&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── 使用记录&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── 我的&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;└── 采集模式&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ├── 批次选择&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ├── 座位采样&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ├── 样本检查&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    └── 上传结果&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;8.3 座位地图&lt;a href=&quot;#83-座位地图&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;座位地图不应把所有状态写死在图片中。推荐使用 JSON 描述布局：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;&lt;/span&gt;&lt;span&gt;roomId&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;&lt;/span&gt;&lt;span&gt;width&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 1200&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;&lt;/span&gt;&lt;span&gt;height&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 800&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;&lt;/span&gt;&lt;span&gt;seats&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &quot;&lt;/span&gt;&lt;span&gt;seatId&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 101&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &quot;&lt;/span&gt;&lt;span&gt;code&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &quot;A-01&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &quot;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 120&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &quot;&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 180&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &quot;&lt;/span&gt;&lt;span&gt;width&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 60&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &quot;&lt;/span&gt;&lt;span&gt;height&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 60&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &quot;&lt;/span&gt;&lt;span&gt;zone&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &quot;window&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      &quot;&lt;/span&gt;&lt;span&gt;tags&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;&quot;靠窗&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;安静区&quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;这样可以在不重新发版的情况下更新座位位置、状态和标签。&lt;/p&gt;
&lt;h3&gt;8.4 Android 权限&lt;a href=&quot;#84-android-权限&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;需要根据目标 Android 版本申请并解释：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;WiFi 扫描相关权限。&lt;/li&gt;
&lt;li&gt;位置权限。&lt;/li&gt;
&lt;li&gt;附近设备权限。&lt;/li&gt;
&lt;li&gt;通知权限。&lt;/li&gt;
&lt;li&gt;前台服务权限。&lt;/li&gt;
&lt;li&gt;网络访问权限。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;权限被拒绝时必须有降级流程。不能在没有说明用途的情况下强制用户授权。&lt;/p&gt;
&lt;h2&gt;9. 后端设计&lt;a href=&quot;#9-后端设计&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;9.1 技术选型&lt;a href=&quot;#91-技术选型&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Java 17 或项目统一的 LTS Java 版本。&lt;/li&gt;
&lt;li&gt;Spring Boot 3.x。&lt;/li&gt;
&lt;li&gt;Spring Web。&lt;/li&gt;
&lt;li&gt;Spring Validation。&lt;/li&gt;
&lt;li&gt;Spring Security。&lt;/li&gt;
&lt;li&gt;MyBatis-Plus 或 Spring Data JPA，二选一并保持统一。&lt;/li&gt;
&lt;li&gt;MySQL 8.x。&lt;/li&gt;
&lt;li&gt;Redis 作为可选缓存。&lt;/li&gt;
&lt;li&gt;OpenAPI/Swagger 生成接口文档。&lt;/li&gt;
&lt;li&gt;Docker Compose 管理开发环境。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;9.2 后端职责&lt;a href=&quot;#92-后端职责&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;后端负责：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户登录和角色鉴权。&lt;/li&gt;
&lt;li&gt;房间、楼层和座位管理。&lt;/li&gt;
&lt;li&gt;样本接收和基础校验。&lt;/li&gt;
&lt;li&gt;算法服务调用。&lt;/li&gt;
&lt;li&gt;座位状态机。&lt;/li&gt;
&lt;li&gt;使用会话管理。&lt;/li&gt;
&lt;li&gt;占座事件管理。&lt;/li&gt;
&lt;li&gt;推荐结果生成。&lt;/li&gt;
&lt;li&gt;管理员复核。&lt;/li&gt;
&lt;li&gt;统计查询。&lt;/li&gt;
&lt;li&gt;审计日志。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;算法服务只负责特征处理、指纹匹配、模型推理和评估，不直接修改业务状态。&lt;/p&gt;
&lt;h2&gt;10. 算法方案&lt;a href=&quot;#10-算法方案&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;10.1 指纹向量&lt;a href=&quot;#101-指纹向量&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;单次采样可以表示为：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;F = {bssid_1: rssi_1, bssid_2: rssi_2, ..., bssid_n: rssi_n}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;预处理步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;删除无效和明显异常的 RSSI。&lt;/li&gt;
&lt;li&gt;对 AP 按 BSSID 对齐。&lt;/li&gt;
&lt;li&gt;缺失 AP 使用统一默认值，例如 -100。&lt;/li&gt;
&lt;li&gt;使用中位数、移动平均或指数平滑降低短时波动。&lt;/li&gt;
&lt;li&gt;对不同设备的 RSSI 偏差进行归一化。&lt;/li&gt;
&lt;li&gt;生成可用于距离计算的固定维度向量。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;10.2 座位识别&lt;a href=&quot;#102-座位识别&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;第一版算法顺序：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;最近邻基线。&lt;/li&gt;
&lt;li&gt;加权 KNN。&lt;/li&gt;
&lt;li&gt;决策树或随机森林作为对照。&lt;/li&gt;
&lt;li&gt;规则与算法融合。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;推荐使用加权 KNN 作为第一版在线模型，因为它容易解释、训练成本低、适合样本量较小的项目。&lt;/p&gt;
&lt;p&gt;输出内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Top-1 座位。&lt;/li&gt;
&lt;li&gt;Top-3 候选座位。&lt;/li&gt;
&lt;li&gt;距离分数。&lt;/li&gt;
&lt;li&gt;可信度。&lt;/li&gt;
&lt;li&gt;模型版本。&lt;/li&gt;
&lt;li&gt;是否需要人工确认。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;10.3 占用识别&lt;a href=&quot;#103-占用识别&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;特征包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;设备信号是否持续出现。&lt;/li&gt;
&lt;li&gt;RSSI 的平均值和波动。&lt;/li&gt;
&lt;li&gt;单次连续在线时长。&lt;/li&gt;
&lt;li&gt;累计使用时长。&lt;/li&gt;
&lt;li&gt;设备是否频繁切换座位。&lt;/li&gt;
&lt;li&gt;用户是否主动开始使用。&lt;/li&gt;
&lt;li&gt;用户是否主动释放。&lt;/li&gt;
&lt;li&gt;座位状态是否长期没有人工确认。&lt;/li&gt;
&lt;li&gt;同一匿名会话是否在多个座位间快速跳转。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;规则示例：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;连续两次检测到同一座位候选结果，并且可信度达到阈值 -&amp;gt; CANDIDATE&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;CANDIDATE 持续稳定超过确认时间 -&amp;gt; OCCUPIED&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;OCCUPIED 状态下信号短暂消失 -&amp;gt; AWAY_CANDIDATE&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;AWAY_CANDIDATE 在离开阈值内恢复 -&amp;gt; OCCUPIED&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;AWAY_CANDIDATE 超过离开阈值 -&amp;gt; AVAILABLE&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;设备持续存在但用户行为异常且超过占座阈值 -&amp;gt; SUSPECTED_HOLDING&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;所有阈值都必须放入数据库配置，不能写死在客户端。&lt;/p&gt;
&lt;h3&gt;10.4 模型评估&lt;a href=&quot;#104-模型评估&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;数据划分应按日期、设备或采集批次划分，不能简单随机打散同一批采样数据。&lt;/p&gt;
&lt;p&gt;需要输出：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Top-1 准确率。&lt;/li&gt;
&lt;li&gt;Top-3 准确率。&lt;/li&gt;
&lt;li&gt;Precision。&lt;/li&gt;
&lt;li&gt;Recall。&lt;/li&gt;
&lt;li&gt;F1。&lt;/li&gt;
&lt;li&gt;混淆矩阵。&lt;/li&gt;
&lt;li&gt;不同时间段的准确率。&lt;/li&gt;
&lt;li&gt;不同设备的准确率。&lt;/li&gt;
&lt;li&gt;相邻座位之间的混淆情况。&lt;/li&gt;
&lt;li&gt;环境变化前后的准确率。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;11. 数据库设计&lt;a href=&quot;#11-数据库设计&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;11.1 用户表 &lt;code&gt;user&lt;/code&gt;&lt;a href=&quot;#111-用户表-user&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;字段&lt;/th&gt;&lt;th&gt;类型&lt;/th&gt;&lt;th&gt;说明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;bigint&lt;/td&gt;&lt;td&gt;主键&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;username&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(64)&lt;/td&gt;&lt;td&gt;用户名或内部账号&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;password_hash&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(255)&lt;/td&gt;&lt;td&gt;密码哈希，可选&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;role&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(32)&lt;/td&gt;&lt;td&gt;用户角色&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;&lt;td&gt;tinyint&lt;/td&gt;&lt;td&gt;启用状态&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;created_at&lt;/code&gt;&lt;/td&gt;&lt;td&gt;datetime&lt;/td&gt;&lt;td&gt;创建时间&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;updated_at&lt;/code&gt;&lt;/td&gt;&lt;td&gt;datetime&lt;/td&gt;&lt;td&gt;更新时间&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;11.2 房间表 &lt;code&gt;room&lt;/code&gt;&lt;a href=&quot;#112-房间表-room&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;字段&lt;/th&gt;&lt;th&gt;类型&lt;/th&gt;&lt;th&gt;说明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;bigint&lt;/td&gt;&lt;td&gt;主键&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(128)&lt;/td&gt;&lt;td&gt;房间名称&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;floor&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(32)&lt;/td&gt;&lt;td&gt;楼层&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;layout_version&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(32)&lt;/td&gt;&lt;td&gt;布局版本&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;open_time&lt;/code&gt;&lt;/td&gt;&lt;td&gt;time&lt;/td&gt;&lt;td&gt;开放时间&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;close_time&lt;/code&gt;&lt;/td&gt;&lt;td&gt;time&lt;/td&gt;&lt;td&gt;关闭时间&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(32)&lt;/td&gt;&lt;td&gt;房间状态&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;11.3 座位表 &lt;code&gt;seat&lt;/code&gt;&lt;a href=&quot;#113-座位表-seat&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;




























































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;字段&lt;/th&gt;&lt;th&gt;类型&lt;/th&gt;&lt;th&gt;说明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;bigint&lt;/td&gt;&lt;td&gt;主键&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;room_id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;bigint&lt;/td&gt;&lt;td&gt;房间 ID&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;code&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(32)&lt;/td&gt;&lt;td&gt;座位编号&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;x&lt;/code&gt;&lt;/td&gt;&lt;td&gt;decimal&lt;/td&gt;&lt;td&gt;地图 X 坐标&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;y&lt;/code&gt;&lt;/td&gt;&lt;td&gt;decimal&lt;/td&gt;&lt;td&gt;地图 Y 坐标&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;width&lt;/code&gt;&lt;/td&gt;&lt;td&gt;decimal&lt;/td&gt;&lt;td&gt;显示宽度&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;height&lt;/code&gt;&lt;/td&gt;&lt;td&gt;decimal&lt;/td&gt;&lt;td&gt;显示高度&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;zone&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(64)&lt;/td&gt;&lt;td&gt;区域&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;tags&lt;/code&gt;&lt;/td&gt;&lt;td&gt;json&lt;/td&gt;&lt;td&gt;标签&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(32)&lt;/td&gt;&lt;td&gt;座位维护状态&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;11.4 指纹样本表 &lt;code&gt;fingerprint_sample&lt;/code&gt;&lt;a href=&quot;#114-指纹样本表-fingerprint_sample&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;

































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;字段&lt;/th&gt;&lt;th&gt;类型&lt;/th&gt;&lt;th&gt;说明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;bigint&lt;/td&gt;&lt;td&gt;主键&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;batch_id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(64)&lt;/td&gt;&lt;td&gt;采集批次&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;room_id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;bigint&lt;/td&gt;&lt;td&gt;房间 ID&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;seat_id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;bigint&lt;/td&gt;&lt;td&gt;座位 ID&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;collector_id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;bigint&lt;/td&gt;&lt;td&gt;采集人员&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;device_code&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(64)&lt;/td&gt;&lt;td&gt;匿名采集设备编号&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;sample_time&lt;/code&gt;&lt;/td&gt;&lt;td&gt;datetime&lt;/td&gt;&lt;td&gt;采样时间&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;rssi_data&lt;/code&gt;&lt;/td&gt;&lt;td&gt;json&lt;/td&gt;&lt;td&gt;AP 与 RSSI 数据&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;environment_note&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(512)&lt;/td&gt;&lt;td&gt;环境备注&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;quality_score&lt;/code&gt;&lt;/td&gt;&lt;td&gt;decimal&lt;/td&gt;&lt;td&gt;样本质量&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;status&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(32)&lt;/td&gt;&lt;td&gt;有效或无效&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;11.5 座位状态事件表 &lt;code&gt;seat_state_event&lt;/code&gt;&lt;a href=&quot;#115-座位状态事件表-seat_state_event&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;























































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;字段&lt;/th&gt;&lt;th&gt;类型&lt;/th&gt;&lt;th&gt;说明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;bigint&lt;/td&gt;&lt;td&gt;主键&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;seat_id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;bigint&lt;/td&gt;&lt;td&gt;座位 ID&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;previous_state&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(32)&lt;/td&gt;&lt;td&gt;原状态&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;current_state&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(32)&lt;/td&gt;&lt;td&gt;新状态&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;source&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(32)&lt;/td&gt;&lt;td&gt;算法、用户或管理员&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;confidence&lt;/code&gt;&lt;/td&gt;&lt;td&gt;decimal&lt;/td&gt;&lt;td&gt;可信度&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;anonymous_session&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(128)&lt;/td&gt;&lt;td&gt;匿名会话标识&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;reason&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(512)&lt;/td&gt;&lt;td&gt;状态原因&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;created_at&lt;/code&gt;&lt;/td&gt;&lt;td&gt;datetime&lt;/td&gt;&lt;td&gt;创建时间&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;11.6 占座事件表 &lt;code&gt;occupancy_alert&lt;/code&gt;&lt;a href=&quot;#116-占座事件表-occupancy_alert&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;























































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;字段&lt;/th&gt;&lt;th&gt;类型&lt;/th&gt;&lt;th&gt;说明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;bigint&lt;/td&gt;&lt;td&gt;主键&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;seat_id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;bigint&lt;/td&gt;&lt;td&gt;座位 ID&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;level&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(32)&lt;/td&gt;&lt;td&gt;提示等级&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;trigger_reason&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(512)&lt;/td&gt;&lt;td&gt;触发原因&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;first_detected_at&lt;/code&gt;&lt;/td&gt;&lt;td&gt;datetime&lt;/td&gt;&lt;td&gt;首次发现&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;last_detected_at&lt;/code&gt;&lt;/td&gt;&lt;td&gt;datetime&lt;/td&gt;&lt;td&gt;最近发现&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;review_status&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(32)&lt;/td&gt;&lt;td&gt;待复核、正常、确认占座&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;reviewer_id&lt;/code&gt;&lt;/td&gt;&lt;td&gt;bigint&lt;/td&gt;&lt;td&gt;复核人&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;review_note&lt;/code&gt;&lt;/td&gt;&lt;td&gt;varchar(512)&lt;/td&gt;&lt;td&gt;复核说明&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;12. API 设计&lt;a href=&quot;#12-api-设计&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;12.1 用户接口&lt;a href=&quot;#121-用户接口&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;POST /api/v1/auth/login&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;POST /api/v1/auth/logout&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GET  /api/v1/rooms&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GET  /api/v1/rooms/{roomId}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GET  /api/v1/rooms/{roomId}/layout&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GET  /api/v1/rooms/{roomId}/seat-states&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GET  /api/v1/seats/{seatId}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GET  /api/v1/seats/recommendations&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;POST /api/v1/seats/{seatId}/sessions&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;POST /api/v1/sessions/{sessionId}/away&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;POST /api/v1/sessions/{sessionId}/release&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GET  /api/v1/me/sessions&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;POST /api/v1/reports&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;12.2 采集接口&lt;a href=&quot;#122-采集接口&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;POST /api/v1/collector/batches&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;POST /api/v1/collector/samples&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;POST /api/v1/collector/batches/{batchId}/complete&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GET  /api/v1/collector/batches/{batchId}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;12.3 管理接口&lt;a href=&quot;#123-管理接口&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GET  /api/v1/admin/dashboard&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GET  /api/v1/admin/alerts&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;POST /api/v1/admin/alerts/{alertId}/review&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;POST /api/v1/admin/seats/{seatId}/force-state&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;POST /api/v1/admin/seats/{seatId}/maintenance&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GET  /api/v1/admin/events&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GET  /api/v1/admin/statistics&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;POST /api/v1/admin/models/{modelId}/publish&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;POST /api/v1/admin/config&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;12.4 算法接口&lt;a href=&quot;#124-算法接口&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;POST /internal/algorithm/fingerprint/match&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;POST /internal/algorithm/occupancy/score&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;POST /internal/algorithm/evaluation/run&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GET  /internal/algorithm/models/{modelId}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;算法接口只允许内网或服务间身份访问，不对客户端开放。&lt;/p&gt;
&lt;h2&gt;13. 隐私和安全设计&lt;a href=&quot;#13-隐私和安全设计&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;13.1 数据最小化&lt;a href=&quot;#131-数据最小化&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;不采集图像、人脸和生物特征。&lt;/li&gt;
&lt;li&gt;不向普通用户展示其他用户身份。&lt;/li&gt;
&lt;li&gt;不在客户端保存原始 MAC。&lt;/li&gt;
&lt;li&gt;路由器日志中的 MAC 必须先进行加盐哈希。&lt;/li&gt;
&lt;li&gt;匿名设备标识应定期轮换。&lt;/li&gt;
&lt;li&gt;只保存完成定位和统计所需的数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;13.2 数据保留&lt;a href=&quot;#132-数据保留&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;原始 WiFi 采样：保留至项目实验结束，或按批次脱敏后删除。&lt;/li&gt;
&lt;li&gt;座位状态事件：保留 90 天。&lt;/li&gt;
&lt;li&gt;统计数据：保留脱敏后的聚合结果。&lt;/li&gt;
&lt;li&gt;管理操作日志：保留 180 天。&lt;/li&gt;
&lt;li&gt;用户个人记录：支持用户申请删除。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;13.3 访问控制&lt;a href=&quot;#133-访问控制&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;普通用户只能访问自己的使用记录。&lt;/li&gt;
&lt;li&gt;采集人员只能上传和查看自己负责的采样批次。&lt;/li&gt;
&lt;li&gt;管理员可以查看座位状态和处理事件。&lt;/li&gt;
&lt;li&gt;项目管理员可以管理模型和系统配置。&lt;/li&gt;
&lt;li&gt;管理接口必须使用服务端鉴权，不能仅依赖前端隐藏按钮。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;14. 部署方案&lt;a href=&quot;#14-部署方案&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;14.1 开发环境&lt;a href=&quot;#141-开发环境&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Windows 或 Linux 开发机。&lt;/li&gt;
&lt;li&gt;Android Studio。&lt;/li&gt;
&lt;li&gt;JDK 17。&lt;/li&gt;
&lt;li&gt;MySQL 8。&lt;/li&gt;
&lt;li&gt;Python 3.11。&lt;/li&gt;
&lt;li&gt;Node.js 仅用于管理后台构建。&lt;/li&gt;
&lt;li&gt;Docker Desktop 或 Docker Engine。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;14.2 测试环境&lt;a href=&quot;#142-测试环境&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Nginx&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── /api -&amp;gt; Spring Boot&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;└── /admin -&amp;gt; Web 管理后台&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Spring Boot -&amp;gt; MySQL&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Spring Boot -&amp;gt; Redis&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Spring Boot -&amp;gt; Python Algorithm Service&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;14.3 生产或现场环境&lt;a href=&quot;#143-生产或现场环境&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;最低配置可以使用一台云服务器：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2 核 CPU。&lt;/li&gt;
&lt;li&gt;4 GB 内存。&lt;/li&gt;
&lt;li&gt;50 GB SSD。&lt;/li&gt;
&lt;li&gt;HTTPS 域名。&lt;/li&gt;
&lt;li&gt;MySQL 定期备份。&lt;/li&gt;
&lt;li&gt;防火墙只开放 80、443 和必要的 SSH 端口。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果只是实验室内网试运行，可以先使用局域网服务器，但 Android 设备必须能访问服务端，且应配置固定地址或局域网域名。&lt;/p&gt;
&lt;h2&gt;15. 开发阶段和交付物&lt;a href=&quot;#15-开发阶段和交付物&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;阶段一：需求和场地建模&lt;a href=&quot;#阶段一需求和场地建模&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;工作内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;确定场地。&lt;/li&gt;
&lt;li&gt;记录座位数量和布局。&lt;/li&gt;
&lt;li&gt;记录 AP 数量和位置。&lt;/li&gt;
&lt;li&gt;统一座位编号。&lt;/li&gt;
&lt;li&gt;完成用户和管理员访谈。&lt;/li&gt;
&lt;li&gt;确定第一版指标。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;交付物：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需求规格说明书。&lt;/li&gt;
&lt;li&gt;座位地图。&lt;/li&gt;
&lt;li&gt;AP 分布图。&lt;/li&gt;
&lt;li&gt;数据采集规范。&lt;/li&gt;
&lt;li&gt;隐私说明初稿。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;阶段二：数据采集和指纹建库&lt;a href=&quot;#阶段二数据采集和指纹建库&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;工作内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;开发采集模式。&lt;/li&gt;
&lt;li&gt;多时段采样。&lt;/li&gt;
&lt;li&gt;清洗异常样本。&lt;/li&gt;
&lt;li&gt;分析相邻座位可区分性。&lt;/li&gt;
&lt;li&gt;建立第一版指纹库。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;交付物：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Android 采集功能。&lt;/li&gt;
&lt;li&gt;指纹数据集。&lt;/li&gt;
&lt;li&gt;数据清洗脚本。&lt;/li&gt;
&lt;li&gt;指纹分布分析报告。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;阶段三：算法和状态机&lt;a href=&quot;#阶段三算法和状态机&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;工作内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;实现最近邻和 KNN。&lt;/li&gt;
&lt;li&gt;建立行为标签。&lt;/li&gt;
&lt;li&gt;实现状态机。&lt;/li&gt;
&lt;li&gt;设计占座判定规则。&lt;/li&gt;
&lt;li&gt;完成离线评估。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;交付物：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;模型文件。&lt;/li&gt;
&lt;li&gt;算法服务。&lt;/li&gt;
&lt;li&gt;评估脚本。&lt;/li&gt;
&lt;li&gt;混淆矩阵和指标报告。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;阶段四：业务系统开发&lt;a href=&quot;#阶段四业务系统开发&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;工作内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;完成数据库。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;完成用户端页面。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;完成管理员后台。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;完成状态接口。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;完成推荐接口。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;完成日志和权限。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;交付物：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Android APK。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Web 管理后台。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Spring Boot 服务。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;API 文档。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据库脚本。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;阶段五：联调和试运行&lt;a href=&quot;#阶段五联调和试运行&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;工作内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;实际场地部署。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;连续运行多个自然周。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;记录误判和漏判。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;统计管理员干预。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;收集用户反馈。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;调整模型和阈值。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;交付物：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;试运行日志。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;问题清单。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;修复版本。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用户反馈报告。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;阶段六：结题和推广&lt;a href=&quot;#阶段六结题和推广&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;交付物：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;总结报告。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;技术文档。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;部署手册。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用户手册。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;演示视频。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;软件著作权或论文材料。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可复现实验数据和代码说明。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;16. 测试计划&lt;a href=&quot;#16-测试计划&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;16.1 Android 测试&lt;a href=&quot;#161-android-测试&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Android 版本兼容。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不同手机型号。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;WiFi 权限拒绝。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;定位权限关闭。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;WiFi 开关关闭。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;网络断开后恢复。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;应用切后台。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;前台服务被系统停止。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;电量不足。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;采样上传失败重试。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;16.2 后端测试&lt;a href=&quot;#162-后端测试&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;登录鉴权。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;角色越权。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;座位状态转换。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;重复事件处理。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据过期处理。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;并发更新同一座位。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;管理员强制释放。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据库事务。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;接口参数校验。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;16.3 算法测试&lt;a href=&quot;#163-算法测试&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;不同时间段。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不同采集设备。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;人数变化。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;AP 信号波动。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;AP 暂时不可用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;相邻座位混淆。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;设备信号短暂丢失。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;设备持续存在但人员离开。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;16.4 用户体验测试&lt;a href=&quot;#164-用户体验测试&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;用户能否快速找到空闲座位。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;推荐结果是否容易理解。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;状态更新时间是否清楚。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;权限说明是否明确。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;误判时能否快速反馈。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;管理员能否快速处理异常。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;17. 验收标准&lt;a href=&quot;#17-验收标准&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;17.1 功能验收&lt;a href=&quot;#171-功能验收&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;能创建一个自习室和完整座位地图。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;能完成指纹采集、上传和查询。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;能查看座位实时状态。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;能进行座位推荐。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;能开始和结束使用会话。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;能产生状态变化事件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;能生成疑似占座事件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;管理员能完成人工复核。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;能查询基本统计数据。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;17.2 性能验收&lt;a href=&quot;#172-性能验收&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;核心接口 p95 响应时间不超过 1 秒。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;座位地图加载时间不超过 3 秒。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;状态刷新延迟目标为 30 至 60 秒。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;单房间 100 个座位时页面不卡顿。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;连续运行 7 天不出现数据库明显异常。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;17.3 算法验收&lt;a href=&quot;#173-算法验收&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;目标值建议如下，最终以实际实验结果为准：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Top-1 座位识别准确率不低于 80%。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Top-3 座位识别准确率不低于 90%。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;占用识别 F1 不低于 0.80。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;每个误判样本可以追溯到原始事件、特征和模型版本。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;能够区分正常离开和超过阈值的疑似占座。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;17.4 安全验收&lt;a href=&quot;#174-安全验收&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;普通用户不能访问管理接口。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;普通用户不能查看原始指纹数据。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;原始设备标识不直接展示。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;管理操作有审计记录。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;传输过程使用 HTTPS 或受控内网。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用户隐私说明可在客户端查看。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;18. 主要风险和处理原则&lt;a href=&quot;#18-主要风险和处理原则&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;WiFi 信号不稳定&lt;a href=&quot;#wifi-信号不稳定&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;使用多次采样、时间段建模、滤波和模型版本管理。不能只采集一次就宣称座位识别可靠。&lt;/p&gt;
&lt;h3&gt;设备和系统差异&lt;a href=&quot;#设备和系统差异&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;采集阶段必须使用多个 Android 设备。算法评估必须按设备分别统计，不能只报告总体平均值。&lt;/p&gt;
&lt;h3&gt;设备不等于人员&lt;a href=&quot;#设备不等于人员&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;将结果定义为疑似状态，结合用户操作、时间行为和管理员复核，不把 WiFi 设备存在作为唯一证据。&lt;/p&gt;
&lt;h3&gt;AP 位置或配置变化&lt;a href=&quot;#ap-位置或配置变化&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;维护 AP 登记表，每次调整 AP 后建立新的模型版本，并重新采集受影响区域。&lt;/p&gt;
&lt;h3&gt;项目范围过大&lt;a href=&quot;#项目范围过大&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;先完成单房间闭环。多房间、微信小程序、预约和复杂推荐全部放入后续版本。&lt;/p&gt;
&lt;h3&gt;隐私和用户接受度&lt;a href=&quot;#隐私和用户接受度&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;所有采集都要有明确用途和授权说明，尽可能使用匿名标识，并允许用户查看和删除个人记录。&lt;/p&gt;
&lt;h2&gt;19. 推荐的代码仓库结构&lt;a href=&quot;#19-推荐的代码仓库结构&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;wifi-seat-system/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── android-app/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── app/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── collector/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   └── README.md&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── backend/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── src/main/java/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── src/main/resources/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   └── README.md&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── algorithm-service/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── app/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── scripts/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── models/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── data-sample/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   └── README.md&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── admin-web/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── src/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   └── README.md&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── database/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── schema.sql&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   └── seed.sql&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── deployment/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── docker-compose.yml&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── nginx.conf&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   └── README.md&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;└── docs/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ├── api.md&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ├── data-collection.md&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ├── algorithm-evaluation.md&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ├── privacy.md&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    └── deployment.md&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;20. 开发顺序&lt;a href=&quot;#20-开发顺序&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;建议严格按照以下顺序推进：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;先完成座位地图和座位编号。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;再完成 Android 采集功能。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;再完成离线数据清洗和 KNN 基线。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;再完成后端座位和事件接口。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;再完成 Android 用户端地图和推荐。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;再完成状态机和疑似占座规则。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;再完成管理员后台。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;再做真实场地联调。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;最后做模型优化、统计分析和展示包装。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;不建议先做复杂界面，也不建议先做微信小程序。没有可靠的指纹数据和状态判定，前端界面只能展示静态假数据，无法证明项目核心价值。&lt;/p&gt;
&lt;h2&gt;21. 最终技术路线&lt;a href=&quot;#21-最终技术路线&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本项目最终采用：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Android 原生客户端&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ↓&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;WiFi 指纹采集与用户使用会话&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ↓&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Spring Boot 业务后端&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ↓&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;MySQL 座位、事件和用户数据&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ↓&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Python KNN/规则融合算法服务&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ↓&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;座位状态、推荐结果和疑似占座事件&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ↓&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Android 用户端 + Web 管理后台&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;这条路线与原方案中的研究内容保持一致，同时解决了微信小程序无法稳定承担 WiFi 指纹采集的问题。第一阶段应以单房间、可重复采样、可解释算法和完整运行闭环为目标；只有在实验结果稳定后，才扩展到微信小程序、多房间和更复杂的运营功能。&lt;/p&gt;</content:encoded><category>category:自习室占座系统</category><category>tag:WiFi指纹</category><category>tag:自习室占座</category></item><item><title>自习室占座系统待改进的内容</title><link>https://astro-jianyanya.pages.dev/post/wifi-system-todo</link><guid isPermaLink="false">wifi-system-todo</guid><description>
KNN 实现优化,解决首次偏差问题,进一步优化 RSSI 归一化精度

只能采用不完全归纳法,给不同型号的手机做偏差预处理(一部手机代替该型号手机的所有)



界面风格: 整体以绿色,健康,书香氛围打造一个软件的整体
首页:
上面要有个可以自己滚动的横幅,这样才好看
该软件的简单介绍</description><pubDate>Tue, 13 Oct 2026 14:46:00 GMT</pubDate><content:encoded>&lt;ol&gt;
&lt;li&gt;KNN 实现优化,解决首次偏差问题,进一步优化 RSSI 归一化精度
&lt;ul&gt;
&lt;li&gt;只能采用不完全归纳法,给不同型号的手机做偏差预处理(一部手机代替该型号手机的所有)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;界面风格: 整体以绿色,健康,书香氛围打造一个软件的整体&lt;/p&gt;
&lt;p&gt;首页:
上面要有个可以自己滚动的横幅,这样才好看
该软件的简单介绍
使用流程(只做用户的)
这里要有跳转的图标,分别为”选座”,“最近预约”,“个人中心”.
注意事项&lt;/p&gt;
&lt;p&gt;选座:
就是基础的选座功能
能选择区域,选择座位,这个部分的交互效果你一定要做好
选择座位,选择预约的时间,千万别犯时间冲突上的基本错误
每个座位都能看到其座位的状态
分为图表展示和列表快速预览两个&lt;/p&gt;
&lt;p&gt;个人中心
这个部分同样重要
头像: 要求能上传且实时更新
用户名称
身份(用户,管理员之类的)
然后就是个人中心的一些内容
权限说明
采集模式(采集人员独有)
管理后台(管理员独有)
清除本地缓存
更改个人信息,这个更改的信息要实时更新的,别出现用户更换了头像和名字之类的,出去还是现实旧名字
退出登录&lt;/p&gt;
&lt;p&gt;你可以保留原来的功能,也可以自己选择更好的方法来做,上述的只是大概要实现的内容,你可以在这个之上继续拓展内容,其中应该还有后端没有实现的接口,你都完善一下&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;账号&lt;/th&gt;&lt;th&gt;密码&lt;/th&gt;&lt;th&gt;角色&lt;/th&gt;&lt;th&gt;用途&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;collector1 / collector2&lt;/td&gt;&lt;td&gt;collector123&lt;/td&gt;&lt;td&gt;采集人员&lt;/td&gt;&lt;td&gt;App 采集模式&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;user1 / user2 / user3&lt;/td&gt;&lt;td&gt;user123&lt;/td&gt;&lt;td&gt;普通用户&lt;/td&gt;&lt;td&gt;App 用户端（查看/选座/会话）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;admin&lt;/td&gt;&lt;td&gt;admin123&lt;/td&gt;&lt;td&gt;管理员&lt;/td&gt;&lt;td&gt;管理后台（复核、改状态、看板）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;projectadmin&lt;/td&gt;&lt;td&gt;Admin@2026&lt;/td&gt;&lt;td&gt;项目管理员&lt;/td&gt;&lt;td&gt;管理后台全部（含模型发布、系统配置）&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;</content:encoded><category>category:自习室占座系统</category><category>tag:自习室占座</category></item><item><title>决策树实验对照方法</title><link>https://astro-jianyanya.pages.dev/post/wifi-decision-tree</link><guid isPermaLink="false">wifi-decision-tree</guid><description>先把这三者分清：</description><pubDate>Tue, 13 Oct 2026 14:41:00 GMT</pubDate><content:encoded>&lt;p&gt;先把这三者分清：&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;部分&lt;/th&gt;&lt;th&gt;解决什么问题&lt;/th&gt;&lt;th&gt;判断依据怎么来&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;KNN&lt;/td&gt;&lt;td&gt;当前指纹最可能属于哪个座位？&lt;/td&gt;&lt;td&gt;比较查询指纹与参考指纹的距离，近邻投票&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;决策树&lt;/td&gt;&lt;td&gt;当前指纹最可能属于哪个座位？&lt;/td&gt;&lt;td&gt;从训练数据中学习特征分裂条件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;占座规则引擎&lt;/td&gt;&lt;td&gt;这个座位应该进入什么业务状态？&lt;/td&gt;&lt;td&gt;人制定的业务规则、持续时间和可信度阈值&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;1. 这次决策树具体预测什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;它预测的是&lt;strong&gt;座位编号&lt;/strong&gt;，例如 &lt;code&gt;A-01&lt;/code&gt;、&lt;code&gt;B-03&lt;/code&gt;，并不直接预测“有人”“无人”或“恶意占座”。&lt;/p&gt;
&lt;p&gt;当前流程是：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;手机上传 WiFi 扫描&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ↓&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;清洗、对齐、合并多帧&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ↓&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;KNN 或决策树识别座位&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ↓&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;检查可信度与证据质量&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ↓&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;结合连续命中次数、持续时间、用户会话等信息&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ↓&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;占座规则引擎给出建议&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ↓&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;后端状态机决定是否更新座位状态&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;KNN 和决策树目前是&lt;strong&gt;可按模型版本切换的两条识别路径&lt;/strong&gt;，还没有做二者联合投票。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 决策树吃进去的是什么数据？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;实现位于 &lt;a&gt;decision_tree.py&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;训练数据每行包含扫描时间、设备、真实座位和各 AP 的 RSSI。先按照设备、批次、座位和时间划分连续采样窗口，默认每 &lt;strong&gt;5 帧&lt;/strong&gt;合并一次，逐 AP 取中位数降噪。&lt;/p&gt;
&lt;p&gt;随后构造两组特征：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;相对 RSSI&lt;/strong&gt;：每个有效 AP 的 RSSI，减去当前窗口有效 RSSI 的中位数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;存在标记&lt;/strong&gt;：每个 AP 是否被扫描到，用 &lt;code&gt;1/0&lt;/code&gt; 表示。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;原始 RSSI：[-50, -70, -80, -60]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;中位数：  -65&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;相对 RSSI：[15, -5, -15, 5]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;存在标记：[1, 1, 1, 1]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;假设另一台手机整体读数偏高 &lt;code&gt;4 dB&lt;/code&gt;：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;原始 RSSI：[-46, -66, -76, -56]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;中位数：  -61&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;相对 RSSI：[15, -5, -15, 5]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;两台手机的相对特征相同，因此这种处理能降低&lt;strong&gt;整体 RSSI 偏移&lt;/strong&gt;的影响。&lt;/p&gt;
&lt;p&gt;缺失 AP 的相对值填 &lt;code&gt;0&lt;/code&gt;，同时把存在标记设成 &lt;code&gt;0&lt;/code&gt;，从而区分“缺失”与“恰好等于中位数”。&lt;/p&gt;
&lt;p&gt;当前示例模型有 &lt;strong&gt;12 个 AP 维度，因此输入是 24 个特征&lt;/strong&gt;。设备编号、真实座位标签、批次编号都不作为树的输入特征；真实座位只是训练时的正确答案。&lt;/p&gt;
&lt;p&gt;这个方案也有代价：它丢失了整体信号强弱信息。两个座位如果只有整体 RSSI 不同，相对特征可能无法区分；不同频段的偏移不一致，也不能保证被消除。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 树是怎么训练出来的？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;使用的是 sklearn 的 &lt;code&gt;DecisionTreeClassifier&lt;/code&gt;，即 CART 分类树。&lt;/p&gt;
&lt;p&gt;训练时，算法不断尝试：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;用哪个特征、在哪个阈值处分开，能让分开后的座位类别更集中？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;衡量类别混杂程度的指标是 Gini 不纯度：&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;[Gini(S)=1−∑cpc2][ Gini(S)=1-\sum_c p_c^2 ]&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;G&lt;/span&gt;&lt;span&gt;ini&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;S&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;∑&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;例如，一个节点中 A、B 座位各占一半，Gini 为 &lt;code&gt;0.5&lt;/code&gt;；如果全是 A，Gini 就是 &lt;code&gt;0&lt;/code&gt;。算法选择能让左右子节点的&lt;strong&gt;加权不纯度下降最多&lt;/strong&gt;的分裂。&lt;/p&gt;
&lt;p&gt;需要区分两类参数：&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;内容&lt;/th&gt;&lt;th&gt;来源&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;某节点选哪个 AP、分裂阈值是多少&lt;/td&gt;&lt;td&gt;训练学习&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;最大深度默认 12、叶节点最少 3 个窗口&lt;/td&gt;&lt;td&gt;人指定的训练超参数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;共同 AP 至少 3 个、残差过大要求复核&lt;/td&gt;&lt;td&gt;人制定的证据检查策略&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;本次训练出的树实际深度为 &lt;strong&gt;12&lt;/strong&gt;，共有 &lt;strong&gt;54 个叶节点&lt;/strong&gt;。一个座位可以对应多个叶节点，叶节点数量不必等于座位数量。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. 线上如何得到座位和可信度？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;新扫描经过同样的特征处理后，从根节点逐层判断，最后到达一个叶节点。&lt;/p&gt;
&lt;p&gt;假设某叶节点训练样本的类别分布为：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;A-01：8 个&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;A-02：2 个&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;则输出：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;Top-1：A-01&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;类别频率：0.8&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;第二候选：A-02，频率 0.2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;这里的 0.8 是训练样本在叶节点里的类别频率，不代表已经验证了“实际有 80% 概率正确”。&lt;/strong&gt; 当前决策树没有做独立概率校准；即使纯叶节点输出 &lt;code&gt;1.0&lt;/code&gt;，也可能在新设备或新环境上判断错误。&lt;/p&gt;
&lt;p&gt;因此实现中还增加了证据检查：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;共同有效 AP 不足。&lt;/li&gt;
&lt;li&gt;查询与预测座位参考指纹的残差过大。&lt;/li&gt;
&lt;li&gt;其他座位也能以相近或更低残差解释查询。&lt;/li&gt;
&lt;li&gt;叶节点第一、第二名平票。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;遇到这些情况，可信度会被置为 &lt;code&gt;0&lt;/code&gt;，要求人工确认。这些检查是&lt;strong&gt;人为设计的保护规则&lt;/strong&gt;，不是树学习出来的分支。&lt;/p&gt;
&lt;p&gt;另外，树的 Top-3 只取叶节点中非零频率的类别。如果只有一个类别，就只返回一个，不强行补两个座位。&lt;/p&gt;
&lt;p&gt;模型会保存为 JSON，包含节点、阈值、类别分布、特征重要性和规则文本；接口还返回 &lt;code&gt;decision_path&lt;/code&gt;，可以追溯一次预测经过了哪些判断。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. 这次对比说明了什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们用 Honor、Pixel 的数据训练，完整留出 Redmi 作为测试设备。两种模型评估的是同一批 &lt;strong&gt;288 个窗口&lt;/strong&gt;：&lt;/p&gt;























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;模型&lt;/th&gt;&lt;th&gt;Top-1 准确率&lt;/th&gt;&lt;th&gt;Top-3 准确率&lt;/th&gt;&lt;th&gt;需人工复核&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;KNN&lt;/td&gt;&lt;td&gt;93.06%&lt;/td&gt;&lt;td&gt;100.00%&lt;/td&gt;&lt;td&gt;19.10%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;决策树&lt;/td&gt;&lt;td&gt;65.62%&lt;/td&gt;&lt;td&gt;80.21%&lt;/td&gt;&lt;td&gt;48.96%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;这支持当前继续使用 &lt;strong&gt;KNN 作为默认在线模型，决策树作为实验对照&lt;/strong&gt;。比较包含各自的设备偏移处理，不能单凭这组结果断言所有决策树都不如 KNN；数据也仍是模拟数据，不能作为现场验收成绩。&lt;/p&gt;</content:encoded><category>category:自习室占座系统</category><category>tag:决策树</category></item><item><title>日常记录</title><link>https://astro-jianyanya.pages.dev/post/daily-notes</link><guid isPermaLink="false">daily-notes</guid><description>青阅占座系统

KNN 算法和决策树算法的实现

萤语

蓝牙延迟问题
二次开发萤语项目,转换角色主题

hwsuanfa

洛谷脚本请求问题

铃月小助手
考研

计组
计网
英语

简历</description><pubDate>Tue, 13 Oct 2026 08:26:00 GMT</pubDate><content:encoded>&lt;h2&gt;青阅占座系统&lt;a href=&quot;#青阅占座系统&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;KNN 算法和决策树算法的实现&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;萤语&lt;a href=&quot;#萤语&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;蓝牙延迟问题&lt;/li&gt;
&lt;li&gt;二次开发萤语项目,转换角色主题&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;hwsuanfa&lt;a href=&quot;#hwsuanfa&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;洛谷脚本请求问题&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;铃月小助手&lt;a href=&quot;#铃月小助手&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;考研&lt;a href=&quot;#考研&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;计组&lt;/li&gt;
&lt;li&gt;计网&lt;/li&gt;
&lt;li&gt;英语&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;简历&lt;a href=&quot;#简历&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div&gt;
  &lt;a href=&quot;https://github.com/JOYCEQL/magic-resume&quot; target=&quot;_blank&quot;&gt;
    &lt;div&gt;
      &lt;div&gt;
        &lt;div&gt;
          &lt;img src=&quot;https://github.com/fluidicon.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; /&gt;
          &lt;span&gt;github.com&lt;/span&gt;
        &lt;/div&gt;
        &lt;div&gt;GitHub - JOYCEQL/magic-resume: free online AI resume editor，the only official website is https://magicv.art&lt;/div&gt;
        &lt;p&gt;free online AI resume editor，the only official website is https://magicv.art - JOYCEQL/magic-resume&lt;/p&gt;
        &lt;div&gt;
          &lt;span&gt;https://github.com/JOYCEQL/magic-resume&lt;/span&gt;
           
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div&gt;&lt;img src=&quot;https://repository-images.githubusercontent.com/802821703/ee9a31af-b010-4a6d-84aa-e984a45cac16&quot; alt=&quot;GitHub - JOYCEQL/magic-resume: free online AI resume editor，the only official website is https://magicv.art&quot; loading=&quot;lazy&quot; /&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;博客&lt;a href=&quot;#博客&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div&gt;
  &lt;a href=&quot;https://github.com/CuteLeaf/Firefly&quot; target=&quot;_blank&quot;&gt;
    &lt;div&gt;
      &lt;div&gt;
        &lt;div&gt;
          &lt;img src=&quot;https://github.com/fluidicon.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; /&gt;
          &lt;span&gt;github.com&lt;/span&gt;
        &lt;/div&gt;
        &lt;div&gt;GitHub - CuteLeaf/Firefly: 🍀Firefly, fresh and aesthetic Astro blog theme template.&lt;/div&gt;
        &lt;p&gt;🍀Firefly, fresh and aesthetic Astro blog theme template. - CuteLeaf/Firefly&lt;/p&gt;
        &lt;div&gt;
          &lt;span&gt;https://github.com/CuteLeaf/Firefly&lt;/span&gt;
           
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div&gt;&lt;img src=&quot;https://repository-images.githubusercontent.com/1074250582/e8d5b2c1-80f9-4e34-ba18-525563852ec3&quot; alt=&quot;GitHub - CuteLeaf/Firefly: 🍀Firefly, fresh and aesthetic Astro blog theme template.&quot; loading=&quot;lazy&quot; /&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;想做以铃月为主题的博客&lt;/li&gt;
&lt;li&gt;做一个铃月小助手&lt;/li&gt;
&lt;li&gt;我缺少一个能管理我所有信息的私人助手&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;铃月角色塑造&lt;a href=&quot;#铃月角色塑造&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;外观&lt;a href=&quot;#外观&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h3&gt;性格&lt;a href=&quot;#性格&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h3&gt;声音&lt;a href=&quot;#声音&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h3&gt;聊天记录&lt;a href=&quot;#聊天记录&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h2&gt;模型训练&lt;a href=&quot;#模型训练&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;以铃月为原型训练&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;深度学习课程&lt;a href=&quot;#深度学习课程&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h3&gt;强化学习课程&lt;a href=&quot;#强化学习课程&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h2&gt;开源项目研读&lt;a href=&quot;#开源项目研读&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;流萤双工作轨 agent: &lt;a href=&quot;https://github.com/Jonah-Wu23/HSR_Partner_Harness&quot;&gt;https://github.com/Jonah-Wu23/HSR_Partner_Harness&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;
  &lt;a href=&quot;https://github.com/lobehub/lobe-vidol&quot; target=&quot;_blank&quot;&gt;
    &lt;div&gt;
      &lt;div&gt;
        &lt;div&gt;
          &lt;img src=&quot;https://github.com/fluidicon.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; /&gt;
          &lt;span&gt;github.com&lt;/span&gt;
        &lt;/div&gt;
        &lt;div&gt;GitHub - lobehub/lobe-vidol: 🧸 Lobe Vidol - Making Virtual Idols Accessible for EveryOne&lt;/div&gt;
        &lt;p&gt;🧸 Lobe Vidol - Making Virtual Idols Accessible for EveryOne - lobehub/lobe-vidol&lt;/p&gt;
        &lt;div&gt;
          &lt;span&gt;https://github.com/lobehub/lobe-vidol&lt;/span&gt;
           
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div&gt;&lt;img src=&quot;https://repository-images.githubusercontent.com/784800776/aacc00e0-5ad7-4135-92c8-3da6e70312fd&quot; alt=&quot;GitHub - lobehub/lobe-vidol: 🧸 Lobe Vidol - Making Virtual Idols Accessible for EveryOne&quot; loading=&quot;lazy&quot; /&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;
  &lt;a href=&quot;https://github.com/Open-LLM-VTuber/Open-LLM-VTuber&quot; target=&quot;_blank&quot;&gt;
    &lt;div&gt;
      &lt;div&gt;
        &lt;div&gt;
          &lt;img src=&quot;https://github.com/fluidicon.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; /&gt;
          &lt;span&gt;github.com&lt;/span&gt;
        &lt;/div&gt;
        &lt;div&gt;GitHub - Open-LLM-VTuber/Open-LLM-VTuber: Talk to any LLM with hands-free voice interaction, voice interruption, and Live2D avatar running locally across platforms&lt;/div&gt;
        &lt;p&gt;Talk to any LLM with hands-free voice interaction, voice interruption, and Live2D avatar running locally across platforms - Open-LLM-VTuber/Open-LLM-VTuber&lt;/p&gt;
        &lt;div&gt;
          &lt;span&gt;https://github.com/Open-LLM-VTuber/Open-LLM-VTuber&lt;/span&gt;
           
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div&gt;&lt;img src=&quot;https://repository-images.githubusercontent.com/722844356/70b58869-a621-4db9-a371-387e6cdf9dcf&quot; alt=&quot;GitHub - Open-LLM-VTuber/Open-LLM-VTuber: Talk to any LLM with hands-free voice interaction, voice interruption, and Live2D avatar running locally across platforms&quot; loading=&quot;lazy&quot; /&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;
  &lt;a href=&quot;https://github.com/AstrBotDevs/AstrBot&quot; target=&quot;_blank&quot;&gt;
    &lt;div&gt;
      &lt;div&gt;
        &lt;div&gt;
          &lt;img src=&quot;https://github.com/fluidicon.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; /&gt;
          &lt;span&gt;github.com&lt;/span&gt;
        &lt;/div&gt;
        &lt;div&gt;GitHub - AstrBotDevs/AstrBot: AI Agent Assistant &amp;amp; development framework that integrates lots of IM platforms, LLMs, plugins and AI feature, and can be your openclaw alternative. ✨&lt;/div&gt;
        &lt;p&gt;AI Agent Assistant &amp;amp; development framework that integrates lots of IM platforms, LLMs, plugins and AI feature, and can be your openclaw alternative. ✨ - AstrBotDevs/AstrBot&lt;/p&gt;
        &lt;div&gt;
          &lt;span&gt;https://github.com/AstrBotDevs/AstrBot&lt;/span&gt;
           
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div&gt;&lt;img src=&quot;https://opengraph.githubassets.com/bcb500f903c575152de2adb1a44f73d0e202a8d124acc5f0178359ce8e8d0317/AstrBotDevs/AstrBot&quot; alt=&quot;GitHub - AstrBotDevs/AstrBot: AI Agent Assistant &amp;amp; development framework that integrates lots of IM platforms, LLMs, plugins and AI feature, and can be your openclaw alternative. ✨&quot; loading=&quot;lazy&quot; /&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;文档论文研读&lt;a href=&quot;#文档论文研读&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;ai 应用开发工程&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://joyehuang.me/&quot;&gt;别人的博客&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;harness 工程&lt;/li&gt;
&lt;li&gt;工作流 agent 与记忆模型&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>category:随笔</category><category>tag:日常</category></item><item><title>铃月AI助手项目流程图</title><link>https://astro-jianyanya.pages.dev/post/lingyue-flowcharts</link><guid isPermaLink="false">lingyue-flowcharts</guid><description>这个东西的起源是我想让我的虚拟角色”铃月”来帮助我工作,同时给铃月一个真正的身份
主要有三个模块

博客(可以是其他的): 写入的帖子,文章,日记,学习心得,有一个可以随时访问的个人信息库
云端 bot 部署: 它一直在线, 你合上电脑、它自己重启、中途崩溃，都不影响它继续干活,-它有自己的电脑,</description><pubDate>Tue, 13 Oct 2026 06:14:00 GMT</pubDate><content:encoded>&lt;p&gt;这个东西的起源是我想让我的虚拟角色”铃月”来帮助我工作,同时给铃月一个真正的身份&lt;/p&gt;
&lt;h2&gt;主要有三个模块&lt;a href=&quot;#主要有三个模块&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;博客(可以是其他的): 写入的帖子,文章,日记,学习心得,有一个可以随时访问的个人信息库&lt;/li&gt;
&lt;li&gt;云端 bot 部署: 它一直在线, 你合上电脑、它自己重启、中途崩溃，都不影响它继续干活,-它有自己的电脑, 一台云端的机器，有桌面、文件和浏览器。&lt;/li&gt;
&lt;li&gt;移动端(接入 qq 等聊天软件): 用户接受信息,发送指令&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;关系如下&lt;a href=&quot;#关系如下&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;博客到 bot&lt;a href=&quot;#博客到-bot&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;bot 从博客获取资料,进行分析整理,同时存入&lt;strong&gt;记忆数据库&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;bot 到博客&lt;a href=&quot;#bot-到博客&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;bot 作为插件接入个人博客,相当于往博客里接了一个 ai 助手,这个助手的数据库来源于该博客,观看博客的时候能对内容进行评价和指引&lt;/p&gt;
&lt;h3&gt;bot 到移动端&lt;a href=&quot;#bot-到移动端&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;bot 完成指令或者定时任务后,通知交付给用户,把整理的信息给用户&lt;/p&gt;
&lt;h3&gt;移动端到 bot&lt;a href=&quot;#移动端到-bot&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;用户发布任务让 bot 去做,发送消息让 bot 处理
群接入 bot 后,可以分析群里的聊天记录,同时日志中可以看到 qq 号,可以分清楚哪些是主人的话&lt;/p&gt;
&lt;h2&gt;部分详细&lt;a href=&quot;#部分详细&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;博客就相当于一个”个人”信息库,让 ai 能看到理解记忆
场景 1: 当用户想要写简历时,不用把自己的项目经历全部打包给 ai,bot 之前已经看过你的博客了,你的项目经历都在上面,同时 ai 还有记忆,可以直接帮你全面分析
场景 2: 帮你回顾你之前做的事,当”消息”命中记忆库时,ai 能进行联想.即使记忆缺失,也能从博客里及时补充细节
看起来就是一个很了解你的 ai 助手,不仅能工作,也能作为感情陪伴&lt;/p&gt;
&lt;h2&gt;部分功能详细&lt;a href=&quot;#部分功能详细&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;这里的记忆库不是简单的记忆库,是一个装载所有博客信息的记忆库,这里使用现代的记忆模型,做了向量数据库,即 RAG 技术,能快速找到对应内容&lt;/li&gt;
&lt;li&gt;博客中的个人信息可能会有私人信息(如密码,密钥等),bot 不能直接访问,即插件中做一层安全设施&lt;/li&gt;
&lt;li&gt;bot 不是纯 ai 调用,而是有人设卡,个性化的&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;常驻 bot 的三段式架构说明(你可以作为参考)&lt;a href=&quot;#常驻-bot-的三段式架构说明你可以作为参考&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;触发器: 你直接发消息(手机/桌面 app)&lt;/li&gt;
&lt;li&gt;服务器:
&lt;ul&gt;
&lt;li&gt;队列/路由器: 去重 · 定优先级 · 合并连发 · 要不要打扰用户,(优先级最高)正在跑的 Agent loop 会停下来，先处理你这句话，其他来源的消息排到后面。&lt;/li&gt;
&lt;li&gt;Agent loop: 模型在循环里调用工具；每个任务是一个持久化工作流（Temporal），崩溃后从断点继续&lt;/li&gt;
&lt;li&gt;数据库&lt;div&gt;&lt;/div&gt; · 记忆 · 定时任务 · 状态，每一轮都写进来&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Agent 的电脑(Firecracker 虚拟机)
&lt;ul&gt;
&lt;li&gt;文件：记忆、技能、日志、长输出&lt;/li&gt;
&lt;li&gt;在隔离、锁定的环境里跑命令&lt;/li&gt;
&lt;li&gt;Chrome，一个或多个虚拟桌面（每个 bot 一块屏）&lt;/li&gt;
&lt;li&gt;可以实时查看，必要时亲手接管&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;启动-&amp;gt;使用-&amp;gt;快照-&amp;gt;休眠
一直开着太贵，需要时才从快照唤醒。Agent loop 不在这里，所以虚拟机可以随时重建、打补丁。&lt;/p&gt;</content:encoded><category>category:铃月AI助手</category><category>tag:铃月</category><category>tag:AI助手</category></item><item><title>训练模型日志</title><link>https://astro-jianyanya.pages.dev/post/llm-train-log</link><guid isPermaLink="false">llm-train-log</guid><description>在经过长达数月的学习和相关知识的掌握还有多次计划的制订和预演,在最后决定训练的路线后开始着手进行
数据集的准备难度超乎我的想象,我准备了很长时间,从官方还有 wiki 中找到大量的原文本对话,加上别人已有的数据,经过我整合后保留了 407</description><pubDate>Sat, 10 Oct 2026 04:04:00 GMT</pubDate><content:encoded>&lt;p&gt;在经过长达数月的学习和相关知识的掌握还有多次计划的制订和预演,在最后决定训练的路线后开始着手进行&lt;/p&gt;
&lt;p&gt;数据集的准备难度超乎我的想象,我准备了很长时间,从官方还有 wiki 中找到大量的原文本对话,加上别人已有的数据,经过我整合后保留了 407 条对话作为种子对话,因为这些都是官方的,所以我并没有进行任何修改
因为我的模型还要有生成情绪标签和插入语气词的能力,所以要进行第一次的数据蒸馏,我使用 qwen3.8-max 对文本进行分析和整改,于是得到第一部数据集,这样千问也发现了问题,数据集中包含很多重复,且句子较短的对话,还有不明不白没有上下文环境的对话出现,我因为认为是官方的原对话所以没有进行修改,这里为后面埋下了伏笔&lt;/p&gt;
&lt;p&gt;生成标签的时候,因为 tts 语音系统的限制只能生成我预先设定的 8 个标签,但是 qwen 根据语境生成了额外的标签,我人工审查了每一条记录,并加以修改,这里同样为后面埋下了伏笔&lt;/p&gt;
&lt;p&gt;数据集整理完毕,在借助 gpt 的能力,我在魔塔上快速的搭建了虚拟环境上传数据集并进行训练,期间出现了多次报错,在 dpsk 的帮助下,弄清楚了问题所在,并全程手动 debug 完成了整体运行(因为 ai 无法直接帮我在云端开发环境中修改)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我用相同的问题,对每次试训进行对照实验,并保存试训的版本&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一试训次:&lt;/strong&gt; 我忘记了导入人设和背景信息,导致人设和背景完全不知道&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2026 年 9 月 7 日晚上 11&lt;/strong&gt;&lt;/p&gt;&lt;div&gt;&lt;/div&gt;
&lt;strong&gt;第二试训次:&lt;/strong&gt; 加入人设和背景后,在聊了几句话之后就出现了问题
“出现了我预设定语气标签之外的标签”,这个问题在前面进行文本分析的时候就已经出现过了,我想到的方法是加大限制的力度,但是这层限制仅仅只是在人设部分进行添加提示词罢了,但是效果甚微,还出现了不知道喜欢吃什么的情况(我忘记加了)
我还想到了提前关键词以提高模型对此限制的注意力,但是前面的信息似乎更重要&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三试训次:&lt;/strong&gt; 我补充了一些信息后,同时进行了对语句长度的限制
“不要分段,说话尽量简洁,尽量一句话说完,这样显得更自然”
这次同样出现了很多问题&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;句子明显变短,符合预期&lt;/li&gt;
&lt;li&gt;句子中不再有语气词插入&lt;/li&gt;
&lt;li&gt;标签问题同样存在&lt;/li&gt;
&lt;li&gt;背景人设符合预期&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;第四试训次:&lt;/strong&gt; 这一次我主要来解决情绪标签的问题
这一次我设定了”保底”机制,当 ai 不知道怎么分析的时候就默认使用”平静”的情绪,同时加强对情绪标签的设定&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;因为加了保底机制,导致模型大多数回复都是”平静”标签,与原本严重脱离!&lt;/li&gt;
&lt;li&gt;模型开始出现自动生成”动作”标签,这算是个好迹象&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;第五试训次:&lt;/strong&gt; 依旧来解决标签问题
经过 gpt 分析,得出结论:“平静”兜底让模型倾向于保守选择,删掉兜底后，仅靠文字要求又限制不住标签范围.
针对这个问题,我采用 ai 的方案,对预设情绪进行一定范围的解释,让模型选择更加轻松,同时保留之前的限制提示词,同时在仔细思考下还是保留了”保底”机制&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;效果较好,但依旧出现其他标签&lt;/li&gt;
&lt;li&gt;保底机制被稀释了,但是正常运行&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;第六试训次:&lt;/strong&gt; 依旧测试标签问题
我放松了对情绪标签的限制,并对结果更宽容,这次效果出奇的好,很少再出现标签问题
&lt;strong&gt;第六次是我比较满意的版本,但是当天晚上文件无法保存,急死我了,网络还卡&lt;/strong&gt;
魔塔社区上的工作空间可以保存文件,吐血&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一次正式训练,日期: 2026 年 9 月 8 日上午 9&lt;/strong&gt;&lt;/p&gt;&lt;div&gt;&lt;/div&gt;
在得到稳定和效果较好的对话内容后,检查无误后进行了第一次正式训练
训练结果让人非常难受,经过 lora 训练出来的模型几乎跟智障一样&lt;p&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;说话极短(就几个字回复)&lt;/li&gt;
&lt;li&gt;出现严重的过拟合症状&lt;/li&gt;
&lt;li&gt;出现反问&lt;/li&gt;
&lt;li&gt;出现回复重复内容&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我针对此次失败,我先让 ai 对整体进行了诊断,先将问题锁定到 lora 微调是否正常执行了,ai 做了检测包抓取监视数据,发现整个 lora 流程是正常进行了
那么问题回来了: “为什么进行 lora 微调后,模型会出现质量退化呢?”
问题真的是过拟合吗?,我在仔细思考后发现不全是,我查了 lora 相关的资料,总结了几种可能
lora 会将引导模型向数据集的内容对齐,且经过 gpt 检测,基底模型的能力并没有退化,我数据集中有大量低质的重复和莫名其妙的对话,还有大量短对话,加上过拟合再加上我之前的对语句长度的限制,种种情况叠加导致了模型学会了超短对话
训练前我修改了数据,但是根据 loss 监视,发现 loss 确实下降了不少,同时按理应该会增加稳定性的,其次我害怕过拟合,并没有将训练值调的特别高,但依旧出现了过拟合
过拟合导致了模型失去了多样性和表达能力
于是开始了我的第一次数据清洗,也是流程图中的一部分&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;教训一:&lt;/strong&gt; 我在正式训练前盲目听从了 ai 的判断,ai 提出了降低 loss 值的方法,于是我想试试,于是在给 ai 提出了我的想法后进行了以下调整&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;—num_train_epochs 3          # 从 1 增加到 3&lt;/li&gt;
&lt;li&gt;—learning_rate 2e-5          # 从 5e-5 降到 2e-5（更稳定）&lt;/li&gt;
&lt;li&gt;—max_steps 0&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;教训不是我听从了 ai 的建议,而是我这次修改之后没有经过试训就直接进行了正式训练&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;教训二:&lt;/strong&gt; 我一直强调重视数据集,但是我却没有在个人上落实到位,而是盲目的相信了官方的种子对话,还过于依赖 ai 进行分析了&lt;/p&gt;
&lt;p&gt;我认为,没必要跟官方一模一样,我要做的是独属于我的”流萤”,我能接受她的不足,所以将数据精度可以下降,之前没有用 ai 扩写就是这个原因,我害怕她不像, 但现在看来,完全没必要&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一次数据清洗,日期 2026 年 9 月 8 日下午 4 点 10 分&lt;/strong&gt;
我仔细对数据集中的每个对话进行检查,删改,重组,并对每个对话我都进行了思考分析,预期回复答案,经过这一轮,我的数据只剩下 197 条了
我开始拿之前比较满意的模型版本进行数据扩写,这个过程比我想象中要难,也遇到了些问题
我想到了,先接触对语句长度的限制,增强模型的表达能力和发散性思维,得到高质量的对话,再进行训练后,再加回语句长度类限制,类似 FFN 的”扩张-压缩”模式,但是问 ai,他说不行,但我觉得可以一试&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;新问题:&lt;/strong&gt; 生成的动作标签怎么办?我后续的语音系统会读括号内的内容,所以生成的动作标签会被误读,跟 ai 讨论了一会,我考虑到三个事&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;句子长的问题主要是在语音系统,人看的倒很快,但是读起来就较慢了,对体验不好,所以去除动作标签后,句子短了许多,后续语音系统表现会更好,同时不存在误读&lt;/li&gt;
&lt;li&gt;动作标签生动形象,表现力更强,我真的感觉很好,很有必要保存&lt;/li&gt;
&lt;li&gt;后续加入 VRM 模型,还是需要动作标签的,但是表现形式跟现在不一样,得重新训练&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;针对上述问题,我思考给出了最优解决方案:
不再纠结于模型上的问题,而是聚焦于后续的语音系统,保留动作标签,既然语音系统会误读,那么我做一个”过滤层”用来过滤动作标签,因为动作标签在括号里且为中文,语气词同样在括号里,但是前期已经设定为英文了,这算是立了一项功劳啊,这样就能区分括号里的到底是语气词还是动作标签了,易于过滤&lt;/p&gt;
&lt;p&gt;后续会添加 100+扩写内容,并人工仔细筛选,不再偷懒,依赖 ai&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;日期 2026 年 9 月 9 日晚上 9 点 17 分&lt;/strong&gt;
经过多轮试训以得到数据,发现有个问题,就是模型在逐渐突破我的人设限制,当重置试训后又恢复,但是经过询问后依旧出现该问题,具体表现为:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;刚开始句子短,后面越来越长甚至出现分段&lt;/li&gt;
&lt;li&gt;每次重启试训表现出来的问题都不一样,在前几版中没有出现分段的情况,所以分析,并不是单纯的句子变长,而是在丢掉我对其句子的限制&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;经过分析得出可能原因:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;收到历史回答的影响,会持续影响后续风格,且效果累加&lt;/li&gt;
&lt;li&gt;使用 temperature = 0.7 和 top_p = 0.8,导致起点漂移程度不同,但是为了保证角色的对话多样性和发散性,这不是问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;联想到之前研究 codex 中个性化问题和 app 对本地提示词的处理问题,我给出解决方案:
“每次对话前都对其进行人设提示词投喂”
如果仅仅只是这样也太简单了,我从多个方面进行思考和分析
出现异常回复就丢弃该场景,不继续接着聊
每次异常的时候手动修正,重新限制她
&lt;strong&gt;如何实现?&lt;/strong&gt; 我们围绕最开始的效果最好的方案进行分析和简化
每次对话前都对其进行人设提示词投喂,这太绝对,也没必要,在之前分析 codex 的时候就知道会浪费大量 token,效果确实最好,所以我们采用下面方法(异常时定向提醒)
新对话自然要注入人设,我们设定最大上下文约束,达到最大值时执行上下文压缩,同时执行注入人设,但是有个问题很明显,就是上下文压缩这个条件其实很难触发
要进行综合考虑,对话模型本身消耗就小,上下文本来就短,让记忆容易储存,借鉴 astrbot 设计
使用”静态人设打底+动态情绪调节+对话记忆延续”,这应该到应用层实现&lt;/p&gt;
&lt;p&gt;实际发现,出现突破限制的情况很少,我认为加以些许限制应该就能有很好效果&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;日期 2026 年 9 月 10 日晚上 7 点&lt;/strong&gt;
解除了分段的限制,放宽了语句长度,进行了模拟场景不同时的对话(主要天气),目前为止数据量也已达标,进行整体的重筛和质选,开始第二次正式训练&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二次正式训练,日期: 2026 年 9 月 10 日晚上 10 点 10 分&lt;/strong&gt;
首先,我们设置了对照组:&lt;/p&gt;













































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;组别&lt;/th&gt;&lt;th&gt;学习率&lt;/th&gt;&lt;th&gt;轮次&lt;/th&gt;&lt;th&gt;投喂数据情况&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;原 baseline 模型&lt;/td&gt;&lt;td&gt;5e-5&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;预设对话,作为答案标准&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A 组 1&lt;/td&gt;&lt;td&gt;2e-5&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;额外投喂数据作为限制于测试&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A 组 2&lt;/td&gt;&lt;td&gt;2e-5&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;额外投喂数据作为限制于测试&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;B 组 1&lt;/td&gt;&lt;td&gt;5e-5&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;无额外添加&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;然后我来总结一下所有的问题&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;首先,A 组训练时,都出现了句子会越来越长的情况,而且失控了,故此我加了一句话&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;”你说的太多了,别说这么多话,我都看不过来了,现在你只能说 2 到 4 句话”&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;用来限制,看能否中途进行限制纠正,纠正效果还是比较明显,我加了句对话(嘻嘻,有你真好)看是否真的稳定了,但是后续又有失控的趋势&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A1 组分段严重,A2 组没有分段,但是 A 组表达似乎更加生动多样性更好,应该是句子长的原因&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;B 组句子长度感觉刚刚好,但是表达上差了点,但是后续还是能正常输出动作标签,所以较好&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;上述组别都没有出现语气词插入,但是我综合来说,感觉 B 组最好&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;这里给出分析,A 组的”生动”并非正常,而是在句子过长之后的胡乱展开,且动作丰富不一定等于表达多样,对话中还出现多次重复动作,A 组的失败超出我的想象
出生日期&lt;/p&gt;&lt;div&gt;&lt;/div&gt; 22:25&lt;div&gt;&lt;/div&gt;.373912
故此 B 组作为最优选择,进行了合并,导出 GGUF,量化然后部署到本地了,在 llama 上进行运行&lt;p&gt;&lt;/p&gt;
&lt;p&gt;这里说个有意思的事情,我从云端下载下来的模型文件损坏了,dpsk 让我重新下载,但是 GPT 大人直接自己修,实在太暴力,太强大了&lt;/p&gt;
&lt;p&gt;后续就是做软件整合了,此版圆满结束……&lt;/p&gt;</content:encoded><category>category:复合对话Agent</category><category>tag:LLM</category><category>tag:训练</category></item><item><title>自习室占座项目的KNN算法实现</title><link>https://astro-jianyanya.pages.dev/post/wifi-knn-impl</link><guid isPermaLink="false">wifi-knn-impl</guid><description>这个项目实现的是 “多参考指纹的加权 KNN + 设备 RSSI 偏移适配 + 可信度判断”。
它解决的问题是：手机扫描到一组 WiFi 信号后，判断这组信号最像哪个座位上采集的信号。
算法里的数据是什么。
WiFi 指纹是一组 AP 的信号强度。这里 AP 可以简单理解为无线接入点，RSSI</description><pubDate>Sat, 10 Oct 2026 03:25:00 GMT</pubDate><content:encoded>&lt;p&gt;这个项目实现的是 &lt;strong&gt;“多参考指纹的加权 KNN + 设备 RSSI 偏移适配 + 可信度判断”&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;它解决的问题是：&lt;strong&gt;手机扫描到一组 WiFi 信号后，判断这组信号最像哪个座位上采集的信号。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;算法里的数据是什么。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;WiFi 指纹&lt;/strong&gt;是一组 AP 的信号强度。这里 AP 可以简单理解为无线接入点，RSSI 是手机测到的接收信号强度，通常为负数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-40 dBm&lt;/code&gt; 比较强。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-70 dBm&lt;/code&gt; 比较弱。&lt;/li&gt;
&lt;li&gt;数值越接近 0，信号越强。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;假设房间里选用了 4 个 AP，同一时刻扫描得到：&lt;/p&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;位置&lt;/th&gt;&lt;th&gt;AP1&lt;/th&gt;&lt;th&gt;AP2&lt;/th&gt;&lt;th&gt;AP3&lt;/th&gt;&lt;th&gt;AP4&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;座位 A&lt;/td&gt;&lt;td&gt;-45&lt;/td&gt;&lt;td&gt;-60&lt;/td&gt;&lt;td&gt;-75&lt;/td&gt;&lt;td&gt;-65&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;座位 B&lt;/td&gt;&lt;td&gt;-65&lt;/td&gt;&lt;td&gt;-45&lt;/td&gt;&lt;td&gt;-60&lt;/td&gt;&lt;td&gt;-75&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;当前手机&lt;/td&gt;&lt;td&gt;-46&lt;/td&gt;&lt;td&gt;-59&lt;/td&gt;&lt;td&gt;-74&lt;/td&gt;&lt;td&gt;-66&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;当前手机的信号组合显然更接近座位 A。&lt;/p&gt;
&lt;p&gt;这就是指纹定位的基础：不同位置与各 AP 的距离、遮挡和反射条件不同，形成不同的信号组合。算法比较的是这种组合，输出座位编号。&lt;/p&gt;
&lt;p&gt;需要注意，&lt;strong&gt;这里计算的“距离”是两个 RSSI 向量的差异，不是手机到座位的米数。&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;先看整体流程，可以分为离线建库和在线匹配两部分：&lt;/p&gt;
&lt;pre&gt;flowchart TD
    A[在已知座位采集多设备 WiFi 数据] --&amp;gt; B[估计训练设备的 RSSI 偏移]
    B --&amp;gt; C[清洗数据并合并连续扫描]
    C --&amp;gt; D[按座位和时段生成参考指纹]
    D --&amp;gt; E[计算 AP 权重并保存模型]
    E --&amp;gt; F[在线加载模型]

    G[手机上传 WiFi 扫描] --&amp;gt; H[清洗、对齐、窗口中位数]
    H --&amp;gt; I{模型中是否有该设备的偏移}
    I --&amp;gt;|有| J[减去已知偏移并计算距离]
    I --&amp;gt;|没有| K[针对各参考指纹估计偏移并计算距离]
    J --&amp;gt; L[选出最近 K 条参考指纹]
    K --&amp;gt; L
    F --&amp;gt; J
    F --&amp;gt; K
    L --&amp;gt; M[按座位汇总加权投票]
    M --&amp;gt; N[计算可信度并检查歧义]
    N --&amp;gt; O[输出候选座位和人工复核标记]&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;第一步，把扫描数据整理成可以比较的向量。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对应 &lt;a href=&quot;/E:/wiferoom/algorithm-service/app/preprocessing.py:155&quot;&gt;preprocessing.py (line 155)&lt;/a&gt; 中的 &lt;code&gt;prepare_vector()&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;原始扫描中，每个 AP 至少有两个重要字段：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;bssid：标识 AP 的无线接口&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;rssi：当前信号强度&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;这里使用 BSSID，而不是 WiFi 名称 SSID。因为多个 AP 可以都叫同一个 WiFi 名称，直接用名称会把不同信号源混在一起。&lt;/p&gt;
&lt;p&gt;预处理依次做这些事情：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;统一 BSSID 格式，过滤不合法的 BSSID。&lt;/li&gt;
&lt;li&gt;过滤不在默认 &lt;code&gt;[-95, -25] dBm&lt;/code&gt; 范围内的 RSSI。&lt;/li&gt;
&lt;li&gt;同一次扫描里，重复 BSSID 的读数取中位数。&lt;/li&gt;
&lt;li&gt;按模型保存的 BSSID 顺序排列。&lt;/li&gt;
&lt;li&gt;没扫到的 AP 填 &lt;code&gt;-100&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;多次扫描之间，按 AP 分别取中位数。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;例如，模型规定顺序是：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;[AP1, AP2, AP3, AP4]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;手机只扫到：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;AP3 = -73&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;AP1 = -46&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;AP4 = -65&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;对齐后的向量就是：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;[-46, -100, -73, -65]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;-100&lt;/code&gt; 在这里主要承担“缺失标记”的作用。&lt;/p&gt;
&lt;p&gt;如果同一个 AP 连续 5 次扫描得到：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;[-60, -59, -80, -61, -60]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;取中位数后是：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;-60&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;这样一次突发的 &lt;code&gt;-80&lt;/code&gt; 不会明显拉偏结果。某个 AP 在部分扫描中缺失时，中位数只使用实际有效值；整个窗口都没扫到才保留 &lt;code&gt;-100&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;你需要区分两个同为 5 的参数：&lt;/p&gt;




















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;参数&lt;/th&gt;&lt;th&gt;当前默认值&lt;/th&gt;&lt;th&gt;含义&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;window&lt;/code&gt;&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;离线每组最多合并 5 次扫描，形成一个查询或训练向量&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;k&lt;/code&gt;&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;匹配时选择最近的 5 条参考指纹参与投票&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;它们控制的是两个不同阶段。&lt;/p&gt;
&lt;p&gt;当前离线窗口按“座位、设备、批次”分组，再按时间排序，每 5 条切一组，末尾不足 5 条也会使用。在线接口则处理这次请求中实际上传的扫描列表，&lt;strong&gt;不会自动等到凑够 5 次才匹配&lt;/strong&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;第二步，离线建立“座位参考指纹库”。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对应 &lt;a href=&quot;/E:/wiferoom/algorithm-service/app/pipeline.py:200&quot;&gt;pipeline.py (line 200)&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;KNN 的主要工作是保存参考样本，预测时与参考样本比较。因此这个项目所谓的“训练”，主要包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;估计训练设备的偏移。&lt;/li&gt;
&lt;li&gt;整理扫描窗口。&lt;/li&gt;
&lt;li&gt;构建每个座位的参考向量。&lt;/li&gt;
&lt;li&gt;计算 AP 权重。&lt;/li&gt;
&lt;li&gt;拟合可信度模型。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当前参考指纹按：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;座位编号 + 采集时段&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;分组，时段划分为：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;morning：06:00～11:59&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;afternoon：12:00～17:59&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;evening：其余时间&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;同一组中的窗口向量，在每个 AP 维度上取有效值的平均数。&lt;/p&gt;
&lt;p&gt;因此一个座位可能保存：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;A-01 上午参考指纹&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;A-01 下午参考指纹&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;A-01 晚间参考指纹&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;注意这里有两层聚合：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;一个窗口内的多次扫描 → 中位数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;同座位、同时段的多个窗口 → 平均数&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;当前保存的 &lt;a&gt;knn-v2-device-safe-20261009.json&lt;/a&gt; 包含：&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;内容&lt;/th&gt;&lt;th&gt;数量&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;座位&lt;/td&gt;&lt;td&gt;48 个&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;AP 维度&lt;/td&gt;&lt;td&gt;12 个&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;参考指纹&lt;/td&gt;&lt;td&gt;144 条&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;K&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;也就是这个模型每个座位有 3 条时段参考指纹。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;预测时会同时比较所有时段的参考指纹，不会根据当前时间只查某一个时段。&lt;/strong&gt; 时段在这里用于保留环境变化下的不同信号形态。&lt;/p&gt;
&lt;p&gt;这也解释了为什么之前“每个座位只有一条指纹”会削弱 KNN 的作用：每个座位最多获得一个邻居的票，按反距离评分时，Top-1 基本就是最近的那条参考。现在同一个座位可以获得多条参考的共同支持。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;第三步，训练设备之间先做 RSSI 偏移校正。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对应 &lt;a href=&quot;/E:/wiferoom/algorithm-service/app/pipeline.py:18&quot;&gt;pipeline.py (line 18)&lt;/a&gt; 的 &lt;code&gt;calibrate_device_offsets()&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;不同手机在同一位置测到的 RSSI 可能整体不同，例如：&lt;/p&gt;























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;设备&lt;/th&gt;&lt;th&gt;AP1&lt;/th&gt;&lt;th&gt;AP2&lt;/th&gt;&lt;th&gt;AP3&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;手机 A&lt;/td&gt;&lt;td&gt;-50&lt;/td&gt;&lt;td&gt;-60&lt;/td&gt;&lt;td&gt;-70&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;手机 B&lt;/td&gt;&lt;td&gt;-56&lt;/td&gt;&lt;td&gt;-66&lt;/td&gt;&lt;td&gt;-76&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;A 比 B 整体高了约 6 dB。&lt;/p&gt;
&lt;p&gt;如果直接混合建库，设备差异就会被掺入位置特征。因此当前代码先寻找：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;相同座位 + 相同日期 + 相同时段 + 共同 AP&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;下的不同设备数据。&lt;/p&gt;
&lt;p&gt;先对各组取中位数，再计算两台设备之间的差值中位数，得到关系：&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;[oA−oB≈6][ o_A-o_B\approx 6 ]&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;B&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≈&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;其中 (o_A,o_B) 是设备偏移。&lt;/p&gt;
&lt;p&gt;多台设备会形成一组这样的方程，代码使用最小二乘求解，并添加约束：&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;[∑dod=0][ \sum_d o_d=0 ]&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&lt;span&gt;∑&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;这个约束的作用是确定共同基准。只有相对差值时，整体加上任意常数都满足设备间的差值关系，需要固定一个基准才能得到唯一结果。&lt;/p&gt;
&lt;p&gt;上面两台设备的结果就是：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;A 的偏移：+3&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;B 的偏移：-3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;归一化采用：&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;[RSSInormalized=RSSIraw−od][ RSSI_{\text{normalized}}=RSSI_{\text{raw}}-o_d ]&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;RSS&lt;/span&gt;&lt;span&gt;&lt;span&gt;I&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;normalized&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;RSS&lt;/span&gt;&lt;span&gt;&lt;span&gt;I&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;raw&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;于是：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;A：[-50,-60,-70] - 3  = [-53,-63,-73]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;B：[-56,-66,-76] -(-3)= [-53,-63,-73]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;两台设备被对齐到共同基准。&lt;/p&gt;
&lt;p&gt;这里的偏移是&lt;strong&gt;相对于训练设备共同基准的偏移&lt;/strong&gt;，并不是相对于某个绝对标准仪器的误差。&lt;/p&gt;
&lt;p&gt;另外，设备之间不要求每两台都有直接交叉采样，但交叉关系必须连通。例如 A 与 B 有共同采样，B 与 C 有共同采样，也能建立 A、B、C 的相对关系。完全孤立的设备会让训练报错，要求补采。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;第四步，计算每个 AP 的重要程度。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对应 &lt;a href=&quot;/E:/wiferoom/algorithm-service/app/pipeline.py:143&quot;&gt;pipeline.py (line 143)&lt;/a&gt; 的 &lt;code&gt;estimate_ap_weights()&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;直观上：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果某个 AP 在所有座位上都是 &lt;code&gt;-60&lt;/code&gt; 左右，它不太能区分座位。&lt;/li&gt;
&lt;li&gt;如果另一个 AP 在不同座位上从 &lt;code&gt;-40&lt;/code&gt; 变化到 &lt;code&gt;-80&lt;/code&gt;，它可能更有区分能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;代码计算每个 AP 在参考指纹中的标准差 (\sigma_i)，忽略缺失值，然后转换成权重：&lt;/p&gt;
&lt;p&gt;[ w_i=0.2+0.8\frac{\sigma_i}{\max_j\sigma_j} ]&lt;/p&gt;
&lt;p&gt;所以 AP 权重落在：&lt;/p&gt;
&lt;p&gt;[ [0.2,1.0] ]&lt;/p&gt;
&lt;p&gt;这里准确地说使用的是&lt;strong&gt;标准差&lt;/strong&gt;；文件顶部部分说明写成了方差，以实际函数为准。&lt;/p&gt;
&lt;p&gt;这个做法简单实用，但有一个局限：它统计的是全部参考条目，座位差异和时段波动都会贡献标准差。因此“变化大”未必完全等于“定位可靠”。后续有真实数据后，可以再区分座位间差异与同一座位内部噪声。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;第五步，计算当前指纹与每条参考指纹的距离。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这一步分为已登记设备和新设备两种情况。&lt;/p&gt;
&lt;p&gt;对于模型里已有偏移的设备，先减去设备偏移，再计算加权均方根距离：&lt;/p&gt;
&lt;p&gt;[ d(q,r)= \sqrt{ \frac&lt;ruby&gt;\sum_i w_i’(q_i-r_i)&lt;rp&gt;(&lt;/rp&gt;&lt;rt&gt;2&lt;/rt&gt;&lt;rp&gt;)&lt;/rp&gt;&lt;/ruby&gt; {\sum_i w_i’} } ]&lt;/p&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(q_i)：当前手机校正后的第 (i) 个 AP 信号。&lt;/li&gt;
&lt;li&gt;(r_i)：参考指纹对应信号。&lt;/li&gt;
&lt;li&gt;(w_i’)：本次比较使用的 AP 权重。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果当前查询没有扫到某个 AP，该维度的权重会乘以 &lt;code&gt;0.1&lt;/code&gt;：&lt;/p&gt;
&lt;p&gt;[ w_i’= \begin{cases} 0.1w_i,&amp;amp;q_i=-100\ w_i,&amp;amp;其他 \end{cases} ]&lt;/p&gt;
&lt;p&gt;这样漏扫一个 AP 不会产生过大的影响，但也不会完全忽略缺失。&lt;/p&gt;
&lt;p&gt;举一个权重相同的例子：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;当前指纹 q = [-50,-60,-70]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;参考指纹 r = [-52,-61,-68]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;则：&lt;/p&gt;
&lt;p&gt;[ d= \sqrt{\frac&lt;ruby&gt;2&lt;rp&gt;(&lt;/rp&gt;&lt;rt&gt;2+1^2+(-2)^2&lt;/rt&gt;&lt;rp&gt;)&lt;/rp&gt;&lt;/ruby&gt;{3}} =\sqrt3 \approx1.732 ]&lt;/p&gt;
&lt;p&gt;距离越小，两组信号越接近。&lt;/p&gt;
&lt;p&gt;实现位置是 &lt;a href=&quot;/E:/wiferoom/algorithm-service/app/fingerprint.py:95&quot;&gt;fingerprint.py (line 95)&lt;/a&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;新设备的距离计算，是这次设备适配改动的核心。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对应 &lt;a href=&quot;/E:/wiferoom/algorithm-service/app/fingerprint.py:105&quot;&gt;fingerprint.py (line 105)&lt;/a&gt; 的 &lt;code&gt;_adapted_distances()&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;新设备没有已知偏移。当前代码的做法是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;分别假设当前手机位于每条参考指纹对应的位置，估计这个假设下需要怎样的整体 RSSI 偏移，再检查剩余差异是否合理。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如某条参考是：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;r = [-55,-65,-75,-60]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;新设备上传：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;q = [-50,-60,-70,-55]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;逐项相减：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;q-r = [5,5,5,5]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;这很像设备整体偏强 5 dB。&lt;/p&gt;
&lt;p&gt;针对每条参考，代码执行以下计算。&lt;/p&gt;
&lt;p&gt;先找共同 AP 集合 (C_r)：查询和参考都不是缺失值的 AP。&lt;strong&gt;共同 AP 不足 3 个时，这条参考不参与有效的偏移拟合。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;然后估计偏移：&lt;/p&gt;
&lt;p&gt;[ b_r= \operatorname{clip} \left( \operatorname{weightedMedian}_{i\in C_r}(q_i-r_i), -12,12 \right) ]&lt;/p&gt;
&lt;p&gt;这里用 AP 权重计算加权中位数，降低个别异常 AP 的影响，并把结果限制在 &lt;code&gt;±12 dB&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;接着计算扣除偏移后的残差：&lt;/p&gt;
&lt;p&gt;[ e_r= \sqrt{ \frac{\sum_{i\in C_r}w_i(q_i-r_i-b_r)^2} {\sum_{i\in C_r}w_i} } ]&lt;/p&gt;
&lt;p&gt;如果各 AP 都近似相差 5，那么 (b_r\approx5)，(e_r\approx0)。&lt;/p&gt;
&lt;p&gt;但如果差值是：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;[5,-8,13,-2]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;就难以用一个整体偏移解释，残差通常会更大。&lt;/p&gt;
&lt;p&gt;最后构造用于 KNN 排序的距离：&lt;/p&gt;
&lt;p&gt;[ d_r= \sqrt&lt;ruby&gt;e_r&lt;rp&gt;(&lt;/rp&gt;&lt;rt&gt;2+0.02b_r^2&lt;/rt&gt;&lt;rp&gt;)&lt;/rp&gt;&lt;/ruby&gt; + 2\left(1-\frac{|C_r|}{|Q|}\right) ]&lt;/p&gt;
&lt;p&gt;其中 (Q) 是查询向量中有效 AP 的集合。&lt;/p&gt;
&lt;p&gt;这个公式有三部分作用：&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;项目&lt;/th&gt;&lt;th&gt;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;残差 (e_r)&lt;/td&gt;&lt;td&gt;衡量偏移校正后，信号形状是否相似&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;偏移惩罚 (0.02b_r^2)&lt;/td&gt;&lt;td&gt;避免通过过大的整体平移强行贴合参考&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;覆盖惩罚&lt;/td&gt;&lt;td&gt;惩罚共同 AP 占查询有效 AP 的比例过低&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;即便“偏移 5 dB 后完全重合”，最终距离也不是零：&lt;/p&gt;
&lt;p&gt;[ d=\sqrt&lt;ruby&gt;0.02\times5&lt;rp&gt;(&lt;/rp&gt;&lt;rt&gt;2&lt;/rt&gt;&lt;rp&gt;)&lt;/rp&gt;&lt;/ruby&gt;\approx0.707 ]&lt;/p&gt;
&lt;p&gt;这是代码主动保留的偏移代价。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;每条参考都有自己的临时偏移估计。&lt;/strong&gt; 最终响应中的 &lt;code&gt;device_offset&lt;/code&gt;，取获胜座位中距离最近的那条参考所估计的偏移，当前不会把它永久登记为设备标定值。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;第六步，取最近的 K 条参考指纹，按座位投票。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对应 &lt;a href=&quot;/E:/wiferoom/algorithm-service/app/fingerprint.py:160&quot;&gt;fingerprint.py (line 160)&lt;/a&gt; 中的 &lt;code&gt;match()&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;假设取出的 5 条最近参考是：&lt;/p&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;参考指纹&lt;/th&gt;&lt;th&gt;距离&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;A-01 上午&lt;/td&gt;&lt;td&gt;1.0&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A-02 下午&lt;/td&gt;&lt;td&gt;1.2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A-01 下午&lt;/td&gt;&lt;td&gt;1.4&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A-01 晚间&lt;/td&gt;&lt;td&gt;1.8&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A-03 上午&lt;/td&gt;&lt;td&gt;2.0&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;每条参考的投票权重为：&lt;/p&gt;
&lt;p&gt;[ v_j=\frac1{d_j+10^{-6}} ]&lt;/p&gt;
&lt;p&gt;距离越近，票越重。小常数用于避免除零。&lt;/p&gt;
&lt;p&gt;按座位汇总：&lt;/p&gt;
&lt;p&gt;[ S(c)=\sum_{\substack{j\in TopK\seat(j)=c}}v_j ]&lt;/p&gt;
&lt;p&gt;于是大约得到：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;A-01：1/1.0 + 1/1.4 + 1/1.8 = 2.270&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;A-02：1/1.2                 = 0.833&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;A-03：1/2.0                 = 0.500&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A-01 获胜。&lt;/p&gt;
&lt;p&gt;所以代码中有两种不同的“权重”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AP 权重&lt;/strong&gt;：决定计算距离时，更重视哪些信号维度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;邻居权重&lt;/strong&gt;：决定投票时，更重视哪些参考样本。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最终按座位总分从高到低排序；分数相同时，优先选择最近参考距离更小的座位。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;K=5&lt;/code&gt; 是取 5 条参考，不是 5 个座位。&lt;code&gt;top_n=3&lt;/code&gt; 则表示最多返回 3 个不同座位。假如 K 条参考只涉及两个座位，返回结果也只有两个，不会强行补足。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;第七步，判断这次结果有多可信。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;仅仅获得第一名还不够，因为每次比较总会有一个相对最好的候选，即使整体匹配质量很差。&lt;/p&gt;
&lt;p&gt;代码使用三个特征计算可信度：&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;特征&lt;/th&gt;&lt;th&gt;含义&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;top1_distance&lt;/code&gt;&lt;/td&gt;&lt;td&gt;获胜座位最近一条参考的距离 (d_1)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;separation&lt;/code&gt;&lt;/td&gt;&lt;td&gt;最近其他座位参考的距离与 (d_1) 的差&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;vote_share&lt;/code&gt;&lt;/td&gt;&lt;td&gt;获胜座位得分占全部 K 条邻居总分的比例&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;特别注意 &lt;code&gt;separation&lt;/code&gt;：&lt;/p&gt;
&lt;p&gt;[ separation=d_2-d_1 ]&lt;/p&gt;
&lt;p&gt;其中 (d_2) 来自&lt;strong&gt;所有其他座位参考中的最近距离&lt;/strong&gt;，并不一定是投票第二名座位的距离，也不限于 Top-K 内的参考。&lt;/p&gt;
&lt;p&gt;这样即使 Top-K 的投票集中在一个座位上，代码仍会检查外面是否存在很接近的其他座位。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;vote_share&lt;/code&gt; 为：&lt;/p&gt;
&lt;p&gt;[ vote_share=\frac{S(c_{\text{winner}})}{\sum_cS(c)} ]&lt;/p&gt;
&lt;p&gt;它只是投票得分占比，&lt;strong&gt;不是预测正确概率&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;当前保存的模型用逻辑回归估计可信度：&lt;/p&gt;
&lt;p&gt;[ z=\beta_0+\beta_1d_1+\beta_2separation+\beta_3vote_share ][ confidence=\frac1{1+e^{-z}} ]&lt;/p&gt;
&lt;p&gt;结果再限制在 &lt;code&gt;[0.01,0.99]&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;逻辑回归训练时，把历史预测是否正确作为标签：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;预测座位 = 真实座位 → 1&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;预测座位 ≠ 真实座位 → 0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;用这些样本学习三个特征与预测正确性的关系。&lt;/p&gt;
&lt;p&gt;需要准确理解：这个输出是&lt;strong&gt;根据已有数据拟合出的正确概率估计&lt;/strong&gt;，不是已经得到保证的真实场地正确率。尤其当前模型来自模拟数据，不能把一次输出 &lt;code&gt;0.99&lt;/code&gt; 直接理解成实地一定有 99% 把握。&lt;/p&gt;
&lt;p&gt;还有一个值得指出的现状：当前模型的 (d_1) 系数是正值 &lt;code&gt;0.100526&lt;/code&gt;。这说明模型没有保证“距离越大，可信度必然越低”，不能只凭直觉解释它。后续应使用真实数据检查概率校准效果。&lt;/p&gt;
&lt;p&gt;如果训练数据不足以拟合逻辑回归，例如没有同时包含预测正确和错误的样本，就退回启发式公式：&lt;/p&gt;
&lt;p&gt;[ confidence= \sqrt{ \max(0,1-d_1/5) \cdot \operatorname{clip}(separation/2,0,1) } ]&lt;/p&gt;
&lt;p&gt;同样再限制输出范围。&lt;/p&gt;
&lt;p&gt;可信度拟合位于 &lt;a href=&quot;/E:/wiferoom/algorithm-service/scripts/train_knn.py:143&quot;&gt;train_knn.py (line 143)&lt;/a&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;第八步，还有一些条件会直接要求人工复核。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;即使上面的可信度估计较高，代码仍会检查证据是否充分。&lt;/p&gt;
&lt;p&gt;以下情况会把可信度置为 &lt;code&gt;0&lt;/code&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;查询有效 AP 或获胜参考的共同 AP 少于 3 个。&lt;/li&gt;
&lt;li&gt;新设备估计偏移达到 &lt;code&gt;±12 dB&lt;/code&gt; 上限。&lt;/li&gt;
&lt;li&gt;新设备偏移校正后的残差大于 &lt;code&gt;5 dB&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;存在其他座位，其偏移校正残差不大于获胜参考残差加 &lt;code&gt;0.3 dB&lt;/code&gt;，说明存在歧义。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最后一条非常关键。&lt;/p&gt;
&lt;p&gt;假设：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;座位 A 的参考：[-50,-60,-70]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;座位 B 的参考：[-55,-65,-75]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;当前手机信号：[-50,-60,-70]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;可能有两种解释：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;手机在 A，设备偏移为 0&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;手机在 B，设备偏移为 +5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;两者偏移校正后的残差都为 0。仅凭这一组 RSSI，无法可靠区分位置差异和设备差异。&lt;/p&gt;
&lt;p&gt;所以当前实现会保留候选，但要求人工确认。&lt;/p&gt;
&lt;p&gt;这说明&lt;strong&gt;新设备临时偏移适配能够缓解跨设备问题，却不能保证任何设备第一次进入都能自动准确定位&lt;/strong&gt;。若要进一步消除这种歧义，需要已知位置的标定样本，或者引入更多观测信息。&lt;/p&gt;
&lt;p&gt;此外，可信度低于默认阈值 &lt;code&gt;0.60&lt;/code&gt; 也会要求复核，但这种情况下不一定把可信度清零。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;用实际代码跑一个例子，会更直观。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我取当前保存模型中的：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;A-01 下午参考指纹&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;人为把有效 RSSI 整体增加 &lt;code&gt;5 dB&lt;/code&gt;，四舍五入成整数，然后作为一台未登记设备的扫描输入。正常执行了 RSSI 过滤。&lt;/p&gt;
&lt;p&gt;这是用于解释算法的合成输入，不是独立精度测试。&lt;/p&gt;
&lt;p&gt;得到最近 5 条参考：&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;参考&lt;/th&gt;&lt;th&gt;距离&lt;/th&gt;&lt;th&gt;邻居权重&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;A-01 下午&lt;/td&gt;&lt;td&gt;0.7872&lt;/td&gt;&lt;td&gt;1.270336&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A-01 上午&lt;/td&gt;&lt;td&gt;1.0895&lt;/td&gt;&lt;td&gt;0.917829&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A-01 晚间&lt;/td&gt;&lt;td&gt;1.4124&lt;/td&gt;&lt;td&gt;0.708019&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A-02 下午&lt;/td&gt;&lt;td&gt;2.0619&lt;/td&gt;&lt;td&gt;0.484996&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A-07 上午&lt;/td&gt;&lt;td&gt;2.2236&lt;/td&gt;&lt;td&gt;0.449724&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;聚合后：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;A-01 总分：2.896184&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;A-02 总分：0.484996&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;A-07 总分：0.449724&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;最终响应中的主要字段是：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;top1                 = A-01&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;device_offset        = +4.875 dB&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;offset_source        = reference_fit&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;common_ap_count      = 11&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;vote_share           = 0.756&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;separation           = 1.2747&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;confidence           = 0.99&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;offset_ambiguous     = false&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;needs_manual_review  = false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;人为添加的是 &lt;code&gt;+5 dB&lt;/code&gt;，估计得到 &lt;code&gt;+4.875 dB&lt;/code&gt;，差异来自整数化、过滤和加权中位数计算。&lt;/p&gt;
&lt;p&gt;这个例子展示了完整过程：新设备存在整体偏移，算法仍能根据多个 AP 的相对信号形状找到 A-01，并通过该座位的多条参考聚合投票。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;最后，把训练评估、运行代价和业务边界连起来看。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;目前训练采用严格的设备留出。例如用 A、B 设备训练，C 设备只做最终测试：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;A、B 的数据：&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;构建参考指纹、估计 AP 权重、估计设备偏移&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;A、B 内部轮流留出：&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;生成预测，拟合可信度&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;C 的数据：&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;只用于最终评估&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;这样才能检验“模型遇到新设备时怎么样”。如果同一台设备的数据同时进入训练和测试，测出来的成绩会更容易偏乐观。&lt;/p&gt;
&lt;p&gt;算法复杂度方面，设：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(N)：参考指纹数量。&lt;/li&gt;
&lt;li&gt;(M)：AP 数量。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;已登记设备的一次查询主要是：&lt;/p&gt;
&lt;p&gt;[ O(NM+N\log N) ]&lt;/p&gt;
&lt;p&gt;前一项是计算所有距离，后一项是当前实现对所有参考完整排序。&lt;/p&gt;
&lt;p&gt;新设备需要为每条参考计算加权中位数，其中包含排序，大致为：&lt;/p&gt;
&lt;p&gt;[ O(NM\log M+N\log N) ]&lt;/p&gt;
&lt;p&gt;目前 (N=144,M=12)，这个规模很小，直接遍历匹配足够合适。&lt;/p&gt;
&lt;p&gt;在业务上，&lt;strong&gt;KNN 输出的是“这台手机的信号最像哪个座位”，座位是否被占用还要结合连续命中、持续时间、会话和状态机判断。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当前 &lt;a href=&quot;/E:/wiferoom/backend/src/main/java/com/wifiseat/collector/service/CollectorService.java:213&quot;&gt;CollectorService.java (line 213)&lt;/a&gt; 已经做了保护：低可信度或需要复核时，清空连续命中计数，保持座位原状态；只有符合条件的在线匹配结果才继续进入占用判断。&lt;/p&gt;
&lt;p&gt;因此，整个实现的关键不只是找最近样本，还包括：&lt;strong&gt;先减少设备和测量噪声带来的差异，用多条参考共同支持一个座位，再对证据不足的结果保留人工复核。&lt;/strong&gt;&lt;/p&gt;</content:encoded><category>category:自习室占座系统</category><category>tag:KNN</category><category>tag:WiFi指纹</category></item><item><title>对于WiFi指纹的介绍</title><link>https://astro-jianyanya.pages.dev/post/wifi-fingerprint-intro</link><guid isPermaLink="false">wifi-fingerprint-intro</guid><description>这里的“WiFi 指纹”不是 WiFi 密码，也不是简单判断“手机是否连接了某个 WiFi”，而是利用不同位置接收到的多个 AP 信号强度组合，推断设备所在的座位。
1. WiFi 指纹到底是什么
一个自习室通常有多个无线 AP。手机在不同座位上扫描到的 AP 信号强度不同。
例如，手机在座位 A</description><pubDate>Thu, 01 Oct 2026 09:25:00 GMT</pubDate><content:encoded>&lt;p&gt;这里的“WiFi 指纹”不是 WiFi 密码，也不是简单判断“手机是否连接了某个 WiFi”，而是利用不同位置接收到的多个 AP 信号强度组合，推断设备所在的座位。&lt;/p&gt;
&lt;h2&gt;1. WiFi 指纹到底是什么&lt;a href=&quot;#1-wifi-指纹到底是什么&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;一个自习室通常有多个无线 AP。手机在不同座位上扫描到的 AP 信号强度不同。&lt;/p&gt;
&lt;p&gt;例如，手机在座位 A 扫描得到：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;AP_001: -42 dBm&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;AP_002: -67 dBm&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;AP_003: -75 dBm&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;AP_004: -89 dBm&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;在座位 B 可能得到：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;AP_001: -58 dBm&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;AP_002: -52 dBm&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;AP_003: -81 dBm&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;AP_004: -70 dBm&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;虽然两个座位都连接同一个 WiFi，但各 AP 的信号强度组合不同。这个组合就像该位置的“无线指纹”。&lt;/p&gt;
&lt;p&gt;可以表示为：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;F = {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    BSSID_001: -42,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    BSSID_002: -67,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    BSSID_003: -75,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    BSSID_004: -89&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;BSSID&lt;/code&gt;：某个 AP 的唯一标识；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RSSI&lt;/code&gt;：手机接收到该 AP 的信号强度；&lt;/li&gt;
&lt;li&gt;RSSI 通常是负数；&lt;/li&gt;
&lt;li&gt;越接近 0，信号越强；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-42 dBm&lt;/code&gt; 通常比 &lt;code&gt;-75 dBm&lt;/code&gt; 强。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不能只记录 WiFi 名称 SSID，因为多个 AP 可能使用同一个 SSID。应优先使用 BSSID 作为特征标识。&lt;/p&gt;
&lt;h2&gt;2. 它是如何定位座位的&lt;a href=&quot;#2-它是如何定位座位的&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;WiFi 指纹定位不是通过公式直接计算距离，而是一个“采集样本、建立数据库、进行匹配”的过程。&lt;/p&gt;
&lt;h3&gt;第一步：建立指纹库&lt;a href=&quot;#第一步建立指纹库&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;提前在每个座位采集大量样本。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;座位&lt;/th&gt;&lt;th&gt;AP_001&lt;/th&gt;&lt;th&gt;AP_002&lt;/th&gt;&lt;th&gt;AP_003&lt;/th&gt;&lt;th&gt;采集时间&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;A-01&lt;/td&gt;&lt;td&gt;-42&lt;/td&gt;&lt;td&gt;-67&lt;/td&gt;&lt;td&gt;-75&lt;/td&gt;&lt;td&gt;上午&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A-01&lt;/td&gt;&lt;td&gt;-45&lt;/td&gt;&lt;td&gt;-65&lt;/td&gt;&lt;td&gt;-77&lt;/td&gt;&lt;td&gt;上午&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A-01&lt;/td&gt;&lt;td&gt;-41&lt;/td&gt;&lt;td&gt;-70&lt;/td&gt;&lt;td&gt;-73&lt;/td&gt;&lt;td&gt;下午&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A-02&lt;/td&gt;&lt;td&gt;-58&lt;/td&gt;&lt;td&gt;-52&lt;/td&gt;&lt;td&gt;-81&lt;/td&gt;&lt;td&gt;上午&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A-02&lt;/td&gt;&lt;td&gt;-61&lt;/td&gt;&lt;td&gt;-50&lt;/td&gt;&lt;td&gt;-79&lt;/td&gt;&lt;td&gt;下午&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;同一个座位不会只有一条指纹，而是会有一组指纹，因为 WiFi 信号会波动。&lt;/p&gt;
&lt;h3&gt;第二步：用户现场采集&lt;a href=&quot;#第二步用户现场采集&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;用户进入自习室后，Android 客户端扫描当前环境：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;当前观测：&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;AP_001: -44&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;AP_002: -68&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;AP_003: -76&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;第三步：和指纹库匹配&lt;a href=&quot;#第三步和指纹库匹配&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;系统把当前观测与所有座位的历史指纹进行比较。&lt;/p&gt;
&lt;p&gt;如果当前数据与 A-01 的样本最接近，则认为用户可能位于 A-01。&lt;/p&gt;
&lt;h2&gt;3. 为什么不能只看一个 AP&lt;a href=&quot;#3-为什么不能只看一个-ap&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;如果只使用一个 AP 的 RSSI，会出现很多问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;相邻座位信号差异很小；&lt;/li&gt;
&lt;li&gt;手机方向变化会影响 RSSI；&lt;/li&gt;
&lt;li&gt;人体、桌椅、墙壁会造成遮挡；&lt;/li&gt;
&lt;li&gt;某个 AP 可能暂时拥塞或失效；&lt;/li&gt;
&lt;li&gt;5 GHz 和 2.4 GHz 的传播特性不同。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此需要使用多个 AP 的组合：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;[AP_001, AP_002, AP_003, AP_004, ...]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;通常 AP 越多、空间分布越合理，座位之间越容易区分。但 AP 数量不是越多越好，过弱、经常消失或变化很大的 AP 可能增加噪声。&lt;/p&gt;
&lt;h2&gt;4. 指纹数据如何预处理&lt;a href=&quot;#4-指纹数据如何预处理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;原文档中提到的预处理主要解决三个问题：缺失、波动和设备差异。&lt;/p&gt;
&lt;h3&gt;4.1 AP 对齐&lt;a href=&quot;#41-ap-对齐&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;不同手机扫描到的 AP 集合可能不完全一样，所以要建立统一的 AP 列表：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;AP_001, AP_002, AP_003, AP_004&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;如果某次扫描没有发现 AP_003，就需要补一个特殊值，例如：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;AP_003 = -100&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;这里的 &lt;code&gt;-100&lt;/code&gt; 不是实际测得的 RSSI，而是“没有检测到”的标记。实际实现时也可以额外增加一个“是否检测到”的字段，避免把缺失误认为真实弱信号。&lt;/p&gt;
&lt;h3&gt;4.2 去除异常值&lt;a href=&quot;#42-去除异常值&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;例如某个 AP 平时在 &lt;code&gt;-60&lt;/code&gt; 到 &lt;code&gt;-75&lt;/code&gt; 之间，突然出现 &lt;code&gt;-20&lt;/code&gt; 或 &lt;code&gt;-110&lt;/code&gt;，就需要检查：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;是否扫描异常；&lt;/li&gt;
&lt;li&gt;是否 AP 发生切换；&lt;/li&gt;
&lt;li&gt;是否数据解析错误；&lt;/li&gt;
&lt;li&gt;是否设备靠近 AP；&lt;/li&gt;
&lt;li&gt;是否环境突然变化。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4.3 平滑处理&lt;a href=&quot;#43-平滑处理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;连续采样可能是：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;-61, -65, -59, -70, -63&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;可以使用中位数：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;-63&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;也可以使用移动平均或指数平滑，减少瞬时波动。&lt;/p&gt;
&lt;p&gt;不过中位数、移动平均、指数平滑不一定全部叠加使用，应通过实验比较哪种效果最好。&lt;/p&gt;
&lt;h3&gt;4.4 设备差异校准&lt;a href=&quot;#44-设备差异校准&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;不同手机的 WiFi 芯片和天线不同。同一个位置上：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;手机 A 可能测到 &lt;code&gt;-60&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;手机 B 可能测到 &lt;code&gt;-67&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;手机 C 可能测到 &lt;code&gt;-55&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此采集指纹库时不能只使用一部手机。至少应使用 2 至 3 种 Android 设备进行测试，并分别统计准确率。&lt;/p&gt;
&lt;h2&gt;5. KNN 如何匹配座位&lt;a href=&quot;#5-knn-如何匹配座位&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;KNN 的基本思想是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;当前观测和哪些历史样本最接近，就把当前设备判定到这些样本所属的座位。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;假设当前向量是：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;X = [-44, -68, -76, -88]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;某个历史样本是：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;Y = [-42, -67, -75, -89]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;可以计算它们的距离：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;distance = sqrt(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    (-44 + 42)^2 +&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    (-68 + 67)^2 +&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    (-76 + 75)^2 +&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    (-88 + 89)^2&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;距离越小，说明两个指纹越相似。&lt;/p&gt;
&lt;p&gt;加权 KNN 会让距离更近的样本拥有更高权重：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;权重 = 1 / (距离 + ε)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;最后统计最近的若干个样本属于哪个座位。&lt;/p&gt;
&lt;p&gt;输出可以是：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;top1Seat&quot;: &quot;A-01&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;candidates&quot;: [&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    {&quot;seat&quot;: &quot;A-01&quot;, &quot;score&quot;: 0.86},&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    {&quot;seat&quot;: &quot;A-02&quot;, &quot;score&quot;: 0.63},&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    {&quot;seat&quot;: &quot;B-01&quot;, &quot;score&quot;: 0.41}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;confidence&quot;: 0.86,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;needManualReview&quot;: false&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;这里的 &lt;code&gt;confidence&lt;/code&gt; 不是严格意义上的概率，而是一个用于比较和决策的可信度分数。必须在实验中进行校准，不能直接把 &lt;code&gt;0.86&lt;/code&gt; 宣称成 86% 的真实准确率。&lt;/p&gt;
&lt;h2&gt;6. 为什么需要 Top-3，而不是只给一个座位&lt;a href=&quot;#6-为什么需要-top-3而不是只给一个座位&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;相邻座位的 WiFi 指纹可能非常接近。例如 A-01 和 A-02 只相差几十厘米，RSSI 变化可能小于环境噪声。&lt;/p&gt;
&lt;p&gt;所以系统最好返回：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;最可能：A-01&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;候选：A-02、A-03&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;这样可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为推荐系统提供多个备选；&lt;/li&gt;
&lt;li&gt;在可信度低时提示用户确认；&lt;/li&gt;
&lt;li&gt;让管理员查看算法混淆情况；&lt;/li&gt;
&lt;li&gt;避免系统把一个不确定结果伪装成绝对正确。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;7. WiFi 指纹能不能直接判断“人是否在座位上”&lt;a href=&quot;#7-wifi-指纹能不能直接判断人是否在座位上&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;这是项目中最容易被误解的部分。&lt;/p&gt;
&lt;p&gt;WiFi 指纹主要能判断：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;某个设备当前更可能位于哪个位置。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它不能直接证明：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;设备的主人此时正在座位上。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户把手机留在座位上，人已经离开；&lt;/li&gt;
&lt;li&gt;用户带着手机离开，但电脑仍然连接 WiFi；&lt;/li&gt;
&lt;li&gt;手机进入省电模式，暂时没有扫描；&lt;/li&gt;
&lt;li&gt;用户坐在座位旁边，信号被判定到相邻座位；&lt;/li&gt;
&lt;li&gt;多个人的设备同时影响无线环境。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，占座检测不能只依赖一次 WiFi 指纹，而应结合：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户主动开始使用；&lt;/li&gt;
&lt;li&gt;用户主动释放；&lt;/li&gt;
&lt;li&gt;连续多次定位结果；&lt;/li&gt;
&lt;li&gt;设备信号是否持续；&lt;/li&gt;
&lt;li&gt;离开持续时间；&lt;/li&gt;
&lt;li&gt;使用时长；&lt;/li&gt;
&lt;li&gt;设备是否在多个座位间快速跳转；&lt;/li&gt;
&lt;li&gt;管理员人工复核；&lt;/li&gt;
&lt;li&gt;可选的路由器连接日志。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;正确的结果应该是：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;设备疑似位于 A-01&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;→ 连续多次稳定检测&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;→ 判断 A-01 正在使用&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;→ 长时间出现异常行为&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;→ 标记为疑似占座&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;→ 管理员复核&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;不能写成：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;检测到 WiFi 设备&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;→ 直接确定有人占座&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;8. 推荐的占用状态流程&lt;a href=&quot;#8-推荐的占用状态流程&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;可以使用以下状态机：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;空闲&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; ↓ 检测到设备&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;疑似使用&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; ↓ 连续多次确认&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;使用中&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; ↓ 信号短暂消失&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;疑似离开&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; ├─ 短时间内恢复 → 使用中&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; └─ 超过离开阈值 → 空闲&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;疑似占座流程：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;使用中&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; ↓ 长时间异常&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;疑似占座&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt; ↓ 管理员复核&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;正常使用 / 空闲&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;连续两次识别到同一座位：进入“疑似使用”；&lt;/li&gt;
&lt;li&gt;连续 2 至 3 次结果稳定：进入“使用中”；&lt;/li&gt;
&lt;li&gt;信号消失 1 至 3 分钟：进入“疑似离开”；&lt;/li&gt;
&lt;li&gt;超过 10 分钟没有恢复：释放座位；&lt;/li&gt;
&lt;li&gt;设备仍存在但用户行为异常超过 30 至 60 分钟：标记“疑似占座”。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些时间只是初始参数，最终必须用现场数据调整。&lt;/p&gt;
&lt;h2&gt;9. 采集指纹时应该怎么做&lt;a href=&quot;#9-采集指纹时应该怎么做&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;每个座位不能只采集一次，建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个座位每个时段采集 5 至 10 次；&lt;/li&gt;
&lt;li&gt;至少采集早、中、晚三个时间段；&lt;/li&gt;
&lt;li&gt;覆盖工作日和周末；&lt;/li&gt;
&lt;li&gt;使用 2 至 3 种 Android 手机；&lt;/li&gt;
&lt;li&gt;记录手机型号；&lt;/li&gt;
&lt;li&gt;记录采集方向和持握高度；&lt;/li&gt;
&lt;li&gt;记录是否有人、门窗是否打开、附近是否有遮挡；&lt;/li&gt;
&lt;li&gt;采集相邻座位和通道位置作为对照。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个采集样本应包含：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;roomId&quot;: 1,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;seatId&quot;: &quot;A-01&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;deviceModel&quot;: &quot;Pixel-6&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;sampleTime&quot;: &quot;2026-10-01T09:30:00&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;wifi&quot;: [&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    {&quot;bssid&quot;: &quot;AP_001&quot;, &quot;rssi&quot;: -44, &quot;frequency&quot;: 5180},&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    {&quot;bssid&quot;: &quot;AP_002&quot;, &quot;rssi&quot;: -68, &quot;frequency&quot;: 2412}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &quot;environment&quot;: &quot;上午，人流较少&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;10. Android 端和路由器日志的区别&lt;a href=&quot;#10-android-端和路由器日志的区别&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;这里需要特别修正文档中的一个技术边界。&lt;/p&gt;
&lt;h3&gt;Android 主动扫描&lt;a href=&quot;#android-主动扫描&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Android 手机自己扫描周围 AP，得到：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;多个 BSSID + 多个 RSSI&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;这最适合做 WiFi 指纹定位，也是本项目第一版推荐的方式。&lt;/p&gt;
&lt;h3&gt;路由器日志&lt;a href=&quot;#路由器日志&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;路由器通常能提供：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;哪个设备连接了哪个 AP；&lt;/li&gt;
&lt;li&gt;设备连接和断开时间；&lt;/li&gt;
&lt;li&gt;有些设备能提供客户端 RSSI；&lt;/li&gt;
&lt;li&gt;部分企业级 AP 控制器能提供更多定位信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但普通路由器日志通常不能直接提供一组完整的“房间空间指纹”。因此：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;路由器日志适合辅助判断设备是否在线，不应默认当作完整的 WiFi 指纹定位数据。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;推荐采用混合方案：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;Android 扫描结果&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    负责座位级定位&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;路由器连接日志&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    负责辅助判断设备在线和离线&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;用户操作&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    负责建立使用意图&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;管理员复核&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    负责处理疑难情况&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;11. 最适合本项目的实际方案&lt;a href=&quot;#11-最适合本项目的实际方案&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;我建议第一版采用：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Android 采集端在每个座位建立指纹库；&lt;/li&gt;
&lt;li&gt;Android 用户端在用户明确进入使用状态后进行受控扫描；&lt;/li&gt;
&lt;li&gt;扫描结果上传后端；&lt;/li&gt;
&lt;li&gt;Python 服务使用加权 KNN 推断候选座位；&lt;/li&gt;
&lt;li&gt;Spring Boot 根据连续结果更新座位状态；&lt;/li&gt;
&lt;li&gt;路由器日志只作为辅助信号；&lt;/li&gt;
&lt;li&gt;低可信度和异常状态进入管理员复核；&lt;/li&gt;
&lt;li&gt;所有判断保留原始事件、特征摘要和模型版本。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;需要注意的是，Android 后台 WiFi 扫描受系统限制。不能假设应用被切到后台后仍然可以无限制稳定扫描，所以产品上应提供：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;前台采样服务；&lt;/li&gt;
&lt;li&gt;明确的采样状态；&lt;/li&gt;
&lt;li&gt;采样失败提示；&lt;/li&gt;
&lt;li&gt;手动刷新；&lt;/li&gt;
&lt;li&gt;网络断开重试；&lt;/li&gt;
&lt;li&gt;无法定位时的人工确认。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;12. 应该如何评价 WiFi 指纹效果&lt;a href=&quot;#12-应该如何评价-wifi-指纹效果&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;不能只说“定位准确”，需要具体测量：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Top-1 准确率：第一候选就是正确座位的比例；&lt;/li&gt;
&lt;li&gt;Top-3 准确率：前三个候选包含正确座位的比例；&lt;/li&gt;
&lt;li&gt;相邻座位混淆率；&lt;/li&gt;
&lt;li&gt;不同手机型号的准确率；&lt;/li&gt;
&lt;li&gt;不同时间段的准确率；&lt;/li&gt;
&lt;li&gt;有人和无人环境下的准确率；&lt;/li&gt;
&lt;li&gt;AP 故障时的准确率；&lt;/li&gt;
&lt;li&gt;平均状态更新时间；&lt;/li&gt;
&lt;li&gt;正常离开被误判为占座的比例；&lt;/li&gt;
&lt;li&gt;真正占座没有被发现的比例。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;数据划分不能把同一轮采样的相邻数据随机打散到训练集和测试集，否则结果可能虚高。应按日期、采集设备或采集批次划分测试数据。&lt;/p&gt;
&lt;h2&gt;13. 最重要的结论&lt;a href=&quot;#13-最重要的结论&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;WiFi 指纹在这个项目中适合解决：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“这个设备更可能位于哪个座位？”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它不适合单独解决：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“这个人是否一直坐在这个座位上？”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以完整系统应该是：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;WiFi 指纹定位&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;+ 连续时间行为&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;+ 用户使用会话&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;+ 路由器在线信息&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;+ 管理员人工复核&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;这样才能把“座位定位”和“占座检测”区分开，避免项目答辩时被质疑技术结论过度夸大。原开发文档中的算法部分基本方向正确，但“路由器日志可以直接参与完整指纹定位”这一点需要改成“Android 主动扫描负责指纹定位，路由器日志作为辅助数据”。&lt;/p&gt;</content:encoded><category>category:自习室占座系统</category><category>tag:WiFi指纹</category></item><item><title>LLM 模型</title><link>https://astro-jianyanya.pages.dev/post/llm-models</link><guid isPermaLink="false">llm-models</guid><description>学习网站:
astrbot
Goaigo
流萤双工作轨 agent: https://github.com/Jonah-Wu23/HSR_Partner_Harness
https://github.com/lobehub/lobe-vidol</description><pubDate>Tue, 29 Sep 2026 09:28:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;学习网站:&lt;/strong&gt;
astrbot
Goaigo
流萤双工作轨 agent: &lt;a href=&quot;https://github.com/Jonah-Wu23/HSR_Partner_Harness&quot;&gt;https://github.com/Jonah-Wu23/HSR_Partner_Harness&lt;/a&gt;
&lt;a href=&quot;https://github.com/lobehub/lobe-vidol&quot;&gt;https://github.com/lobehub/lobe-vidol&lt;/a&gt;
&lt;a href=&quot;https://github.com/Open-LLM-VTuber/Open-LLM-VTuber&quot;&gt;https://github.com/Open-LLM-VTuber/Open-LLM-VTuber&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;AstrBot 账户&lt;a href=&quot;#astrbot-账户&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;（账户信息已隐去）&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;/img/posts/llm-models-paste1.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;</content:encoded><category>category:复合对话Agent</category><category>tag:LLM</category></item><item><title>刷题计划书</title><link>https://astro-jianyanya.pages.dev/post/brush-website-plan</link><guid isPermaLink="false">brush-website-plan</guid><description>校队算法刷题网站实施计划书
一、项目定位
建设一个面向本校算法竞赛队伍的刷题、作业、比赛和积分管理平台。
系统重点解决：

教练统一管理队伍和队员
按队伍或全体队伍布置作业
管理每日一题、题单和比赛记录
记录队员刷题与参赛情况
建立公开、透明、可追溯的积分制度
根据个人隐私设置展示做题数据</description><pubDate>Sun, 20 Sep 2026 06:18:00 GMT</pubDate><content:encoded>&lt;h1&gt;校队算法刷题网站实施计划书&lt;a href=&quot;#校队算法刷题网站实施计划书&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2&gt;一、项目定位&lt;a href=&quot;#一项目定位&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;建设一个面向本校算法竞赛队伍的刷题、作业、比赛和积分管理平台。&lt;/p&gt;
&lt;p&gt;系统重点解决：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;教练统一管理队伍和队员&lt;/li&gt;
&lt;li&gt;按队伍或全体队伍布置作业&lt;/li&gt;
&lt;li&gt;管理每日一题、题单和比赛记录&lt;/li&gt;
&lt;li&gt;记录队员刷题与参赛情况&lt;/li&gt;
&lt;li&gt;建立公开、透明、可追溯的积分制度&lt;/li&gt;
&lt;li&gt;根据个人隐私设置展示做题数据&lt;/li&gt;
&lt;li&gt;维护个人获奖经历&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;系统不包含以下功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI 总结&lt;/li&gt;
&lt;li&gt;发现&lt;/li&gt;
&lt;li&gt;博客&lt;/li&gt;
&lt;li&gt;独立题库&lt;/li&gt;
&lt;li&gt;服务&lt;/li&gt;
&lt;li&gt;“我的组织”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中“我的组织”改为“我的队伍”。&lt;/p&gt;
&lt;p&gt;参考网站的前端布局、颜色、组件风格和交互方式可以作为主要参考，但复制源码前必须确认仓库许可证允许使用。建议优先复用视觉设计和页面结构，再根据本项目权限模型重新实现业务逻辑。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;二、用户角色&lt;a href=&quot;#二用户角色&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. 站主&lt;a href=&quot;#1-站主&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;最高权限，负责：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;管理站点基础配置&lt;/li&gt;
&lt;li&gt;管理教练账号&lt;/li&gt;
&lt;li&gt;管理所有用户、队伍和数据&lt;/li&gt;
&lt;li&gt;查看所有用户的完整资料、提交记录和代码&lt;/li&gt;
&lt;li&gt;修改积分规则&lt;/li&gt;
&lt;li&gt;处理异常数据和申诉&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 教练&lt;a href=&quot;#2-教练&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;本项目默认只有一名主教练，负责：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;创建和管理队伍&lt;/li&gt;
&lt;li&gt;设置每个队伍的唯一队长&lt;/li&gt;
&lt;li&gt;添加、移除队员&lt;/li&gt;
&lt;li&gt;布置队伍作业&lt;/li&gt;
&lt;li&gt;发布全体队伍作业&lt;/li&gt;
&lt;li&gt;设置每日一题&lt;/li&gt;
&lt;li&gt;管理比赛、积分规则和获奖记录&lt;/li&gt;
&lt;li&gt;查看所有用户信息，不受隐私设置限制&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 队长&lt;a href=&quot;#3-队长&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;负责本队日常管理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;查看本队作业和完成情况&lt;/li&gt;
&lt;li&gt;管理本队题单&lt;/li&gt;
&lt;li&gt;记录和维护比赛日志&lt;/li&gt;
&lt;li&gt;选择本队参加的比赛&lt;/li&gt;
&lt;li&gt;审核或整理队员提交的题目、题单&lt;/li&gt;
&lt;li&gt;查看本队成员的做题情况&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4. 队员&lt;a href=&quot;#4-队员&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;查看队伍作业和每日一题&lt;/li&gt;
&lt;li&gt;提交题目、题单和比赛记录&lt;/li&gt;
&lt;li&gt;记录自己的做题情况&lt;/li&gt;
&lt;li&gt;查看允许查看的个人、队伍和排行榜数据&lt;/li&gt;
&lt;li&gt;维护个人资料、隐私设置和获奖经历&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5. 游客&lt;a href=&quot;#5-游客&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;只能访问登录页或站点公开内容，不能查看受权限控制的刷题数据。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;三、主要功能模块&lt;a href=&quot;#三主要功能模块&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. 登录与账号&lt;a href=&quot;#1-登录与账号&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;技术方案：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Spring Security&lt;/li&gt;
&lt;li&gt;JWT Access Token&lt;/li&gt;
&lt;li&gt;Refresh Token&lt;/li&gt;
&lt;li&gt;Redis 保存登录状态、刷新令牌和注销令牌&lt;/li&gt;
&lt;li&gt;密码使用 BCrypt 加密&lt;/li&gt;
&lt;li&gt;登录失败次数限制&lt;/li&gt;
&lt;li&gt;关键操作记录审计日志&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;账号信息包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户名&lt;/li&gt;
&lt;li&gt;昵称&lt;/li&gt;
&lt;li&gt;头像&lt;/li&gt;
&lt;li&gt;学号或内部编号&lt;/li&gt;
&lt;li&gt;年级、专业&lt;/li&gt;
&lt;li&gt;GitHub、Codeforces 等外部账号&lt;/li&gt;
&lt;li&gt;个人简介&lt;/li&gt;
&lt;li&gt;隐私等级&lt;/li&gt;
&lt;li&gt;获奖情况&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 队伍管理&lt;a href=&quot;#2-队伍管理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;队伍信息包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;队伍名称&lt;/li&gt;
&lt;li&gt;队伍简介&lt;/li&gt;
&lt;li&gt;创建时间&lt;/li&gt;
&lt;li&gt;当前队长&lt;/li&gt;
&lt;li&gt;队员列表&lt;/li&gt;
&lt;li&gt;队伍累计积分&lt;/li&gt;
&lt;li&gt;队伍题单&lt;/li&gt;
&lt;li&gt;队伍比赛日志&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;规则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个队伍只能有一名队长&lt;/li&gt;
&lt;li&gt;队长必须是该队成员&lt;/li&gt;
&lt;li&gt;教练可以更换队长&lt;/li&gt;
&lt;li&gt;队长不能自行转让队长权限&lt;/li&gt;
&lt;li&gt;队伍成员关系必须保留变更记录&lt;/li&gt;
&lt;li&gt;建议使用多对多队伍关系，方便以后支持跨队伍训练&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 作业系统&lt;a href=&quot;#3-作业系统&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;作业分为三类：&lt;/p&gt;
&lt;h4&gt;队伍作业&lt;a href=&quot;#队伍作业&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;教练指定一个或多个队伍完成。&lt;/p&gt;
&lt;p&gt;内容可以是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单道题目&lt;/li&gt;
&lt;li&gt;一组题目&lt;/li&gt;
&lt;li&gt;指定题单&lt;/li&gt;
&lt;li&gt;比赛训练任务&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;全体作业&lt;a href=&quot;#全体作业&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;教练发布后，对所有有效队伍生效。&lt;/p&gt;
&lt;p&gt;建议在发布时生成队伍任务快照，避免之后新增队伍导致历史任务数据混乱。&lt;/p&gt;
&lt;h4&gt;每日一题&lt;a href=&quot;#每日一题&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;每日一题默认面向所有队伍，也可以扩展为指定队伍。&lt;/p&gt;
&lt;p&gt;每条任务包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;题目&lt;/li&gt;
&lt;li&gt;发布日期&lt;/li&gt;
&lt;li&gt;截止日期&lt;/li&gt;
&lt;li&gt;任务说明&lt;/li&gt;
&lt;li&gt;奖励积分&lt;/li&gt;
&lt;li&gt;完成状态&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;状态包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;未开始&lt;/li&gt;
&lt;li&gt;进行中&lt;/li&gt;
&lt;li&gt;已完成&lt;/li&gt;
&lt;li&gt;已逾期&lt;/li&gt;
&lt;li&gt;逾期完成&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;逾期状态必须由后端根据服务器时间计算，前端只负责展示。未完成且超过截止日期的任务显示红色。&lt;/p&gt;
&lt;p&gt;时间统一使用中国标准时间，数据库建议保存 UTC 或明确时区的时间戳。&lt;/p&gt;
&lt;h3&gt;4. 题目、题单和做题记录&lt;a href=&quot;#4-题目题单和做题记录&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;系统不建设独立的“题库”页面，而是把题目作为作业、题单、比赛和提交记录的基础数据。&lt;/p&gt;
&lt;p&gt;题目字段包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;题目名称&lt;/li&gt;
&lt;li&gt;来源平台&lt;/li&gt;
&lt;li&gt;题目编号&lt;/li&gt;
&lt;li&gt;题目链接&lt;/li&gt;
&lt;li&gt;难度&lt;/li&gt;
&lt;li&gt;标签&lt;/li&gt;
&lt;li&gt;备注&lt;/li&gt;
&lt;li&gt;创建人&lt;/li&gt;
&lt;li&gt;创建时间&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;题单功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;队伍题单&lt;/li&gt;
&lt;li&gt;个人题单&lt;/li&gt;
&lt;li&gt;题单描述&lt;/li&gt;
&lt;li&gt;题目排序&lt;/li&gt;
&lt;li&gt;完成进度&lt;/li&gt;
&lt;li&gt;创建者和维护者&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;队长和队员都可以提供题目或题单。建议采用“提交后进入待审核”的流程，由队长或教练确认后正式加入队伍内容，避免重复和无效数据。&lt;/p&gt;
&lt;p&gt;做题记录至少包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户&lt;/li&gt;
&lt;li&gt;题目&lt;/li&gt;
&lt;li&gt;提交平台&lt;/li&gt;
&lt;li&gt;提交链接&lt;/li&gt;
&lt;li&gt;提交时间&lt;/li&gt;
&lt;li&gt;是否通过&lt;/li&gt;
&lt;li&gt;代码内容或代码链接&lt;/li&gt;
&lt;li&gt;备注&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果没有接入在线评测平台，第一版可以采用手动记录或提交链接的方式。后续再接入 Codeforces、洛谷等平台 API 自动同步。&lt;/p&gt;
&lt;h3&gt;5. 比赛管理&lt;a href=&quot;#5-比赛管理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;比赛模块分为比赛信息、参赛选择和比赛日志。&lt;/p&gt;
&lt;p&gt;比赛信息：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;比赛名称&lt;/li&gt;
&lt;li&gt;比赛等级&lt;/li&gt;
&lt;li&gt;比赛时间&lt;/li&gt;
&lt;li&gt;比赛来源&lt;/li&gt;
&lt;li&gt;比赛链接&lt;/li&gt;
&lt;li&gt;比赛说明&lt;/li&gt;
&lt;li&gt;对应积分&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;队长功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;选择本队参加的比赛&lt;/li&gt;
&lt;li&gt;记录参赛成员&lt;/li&gt;
&lt;li&gt;填写比赛结果&lt;/li&gt;
&lt;li&gt;上传或填写比赛总结&lt;/li&gt;
&lt;li&gt;维护比赛日志&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;比赛日志包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;比赛名称&lt;/li&gt;
&lt;li&gt;比赛日期&lt;/li&gt;
&lt;li&gt;参赛队员&lt;/li&gt;
&lt;li&gt;名次或成绩&lt;/li&gt;
&lt;li&gt;通过题数&lt;/li&gt;
&lt;li&gt;比赛链接&lt;/li&gt;
&lt;li&gt;赛后总结&lt;/li&gt;
&lt;li&gt;相关题单&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6. 积分系统&lt;a href=&quot;#6-积分系统&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;积分必须采用“积分事件流水”设计，而不是只保存一个可修改的总分。&lt;/p&gt;
&lt;p&gt;每一条积分事件包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户&lt;/li&gt;
&lt;li&gt;积分类型&lt;/li&gt;
&lt;li&gt;积分数值&lt;/li&gt;
&lt;li&gt;关联对象&lt;/li&gt;
&lt;li&gt;产生原因&lt;/li&gt;
&lt;li&gt;产生时间&lt;/li&gt;
&lt;li&gt;操作人&lt;/li&gt;
&lt;li&gt;唯一幂等编号&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;建议积分规则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首次完成一道题：获得基础积分&lt;/li&gt;
&lt;li&gt;完成每日一题：获得额外积分&lt;/li&gt;
&lt;li&gt;完成作业：根据作业设置获得积分&lt;/li&gt;
&lt;li&gt;参加不同等级比赛：获得对应积分&lt;/li&gt;
&lt;li&gt;比赛取得名次：获得额外积分&lt;/li&gt;
&lt;li&gt;队伍贡献题目或题单：可以设置少量贡献积分&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;需要限制：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;同一用户同一道题默认只计算一次刷题积分&lt;/li&gt;
&lt;li&gt;同一每日任务只能获得一次奖励&lt;/li&gt;
&lt;li&gt;重复提交不能重复刷分&lt;/li&gt;
&lt;li&gt;删除或撤销记录时，通过反向积分事件修正&lt;/li&gt;
&lt;li&gt;积分规则由教练或站主配置&lt;/li&gt;
&lt;li&gt;网站正式上线时间之前的历史记录默认不计分，除非后续手动导入&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;前端可以使用 Recharts 展示：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;个人积分趋势&lt;/li&gt;
&lt;li&gt;队伍积分排行&lt;/li&gt;
&lt;li&gt;月度刷题数量&lt;/li&gt;
&lt;li&gt;不同难度题目分布&lt;/li&gt;
&lt;li&gt;比赛积分变化&lt;/li&gt;
&lt;li&gt;每日一题完成率&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;7. 个人隐私设置&lt;a href=&quot;#7-个人隐私设置&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;个人隐私等级设计为：&lt;/p&gt;
&lt;h4&gt;完全私密&lt;a href=&quot;#完全私密&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;外部用户不能查看做题情况&lt;/li&gt;
&lt;li&gt;同队伍成员可以查看必要的做题进度&lt;/li&gt;
&lt;li&gt;教练和站主可以无限制查看&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;部分私密&lt;a href=&quot;#部分私密&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;可以查看基本资料、总积分、完成题数等汇总信息&lt;/li&gt;
&lt;li&gt;不能查看详细提交记录&lt;/li&gt;
&lt;li&gt;不能查看具体代码&lt;/li&gt;
&lt;li&gt;教练和站主不受限制&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;公开&lt;a href=&quot;#公开&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;可以查看公开资料&lt;/li&gt;
&lt;li&gt;可以查看做题记录&lt;/li&gt;
&lt;li&gt;可以查看提交详情和代码，但用户可以单独关闭代码展示&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所有后端接口必须进行权限判断，不能只依靠前端隐藏页面。&lt;/p&gt;
&lt;p&gt;建议设计统一的数据脱敏层：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PRIVATE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TEAM_ONLY&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PUBLIC&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ADMIN_VISIBLE&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;排行榜、队伍统计和用户详情接口都必须按照隐私等级返回不同字段，避免通过接口间接泄露隐私。&lt;/p&gt;
&lt;h3&gt;8. 个人获奖情况&lt;a href=&quot;#8-个人获奖情况&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;个人中心增加获奖记录：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;奖项名称&lt;/li&gt;
&lt;li&gt;比赛名称&lt;/li&gt;
&lt;li&gt;获奖等级&lt;/li&gt;
&lt;li&gt;获奖时间&lt;/li&gt;
&lt;li&gt;证书图片或链接&lt;/li&gt;
&lt;li&gt;备注&lt;/li&gt;
&lt;li&gt;是否公开展示&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;队员可以提交，队长或教练审核，站主可以修改或删除。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;四、技术架构&lt;a href=&quot;#四技术架构&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;后端&lt;a href=&quot;#后端&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;采用分层架构：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Controller：接口层&lt;/li&gt;
&lt;li&gt;Service：业务层&lt;/li&gt;
&lt;li&gt;Mapper：MyBatis-Plus 数据访问层&lt;/li&gt;
&lt;li&gt;Domain/Entity：实体模型&lt;/li&gt;
&lt;li&gt;DTO/VO：请求和返回对象&lt;/li&gt;
&lt;li&gt;Security：JWT 和权限校验&lt;/li&gt;
&lt;li&gt;Scheduler：逾期任务、积分统计、数据同步&lt;/li&gt;
&lt;li&gt;Common：统一异常、返回体、分页、日志&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;主要模块：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户与认证&lt;/li&gt;
&lt;li&gt;队伍管理&lt;/li&gt;
&lt;li&gt;作业管理&lt;/li&gt;
&lt;li&gt;每日一题&lt;/li&gt;
&lt;li&gt;题目与题单&lt;/li&gt;
&lt;li&gt;比赛与日志&lt;/li&gt;
&lt;li&gt;提交记录&lt;/li&gt;
&lt;li&gt;积分系统&lt;/li&gt;
&lt;li&gt;隐私控制&lt;/li&gt;
&lt;li&gt;获奖记录&lt;/li&gt;
&lt;li&gt;管理后台&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Redis 使用场景&lt;a href=&quot;#redis-使用场景&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;JWT 刷新令牌&lt;/li&gt;
&lt;li&gt;登录状态&lt;/li&gt;
&lt;li&gt;验证码或登录限流&lt;/li&gt;
&lt;li&gt;热门排行榜缓存&lt;/li&gt;
&lt;li&gt;队伍统计缓存&lt;/li&gt;
&lt;li&gt;接口幂等控制&lt;/li&gt;
&lt;li&gt;定时任务锁&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;前端&lt;a href=&quot;#前端&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;沿用参考网站的技术和视觉方向：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;React 19&lt;/li&gt;
&lt;li&gt;Vite&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;shadcn/ui&lt;/li&gt;
&lt;li&gt;TanStack Query&lt;/li&gt;
&lt;li&gt;Recharts&lt;/li&gt;
&lt;li&gt;React Router&lt;/li&gt;
&lt;li&gt;表单校验可以使用 Zod&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;页面结构建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;登录页&lt;/li&gt;
&lt;li&gt;首页仪表盘&lt;/li&gt;
&lt;li&gt;我的队伍&lt;/li&gt;
&lt;li&gt;作业中心&lt;/li&gt;
&lt;li&gt;每日一题&lt;/li&gt;
&lt;li&gt;题单&lt;/li&gt;
&lt;li&gt;比赛&lt;/li&gt;
&lt;li&gt;积分排行&lt;/li&gt;
&lt;li&gt;个人中心&lt;/li&gt;
&lt;li&gt;管理后台&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;删除原参考网站中的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;发现&lt;/li&gt;
&lt;li&gt;博客&lt;/li&gt;
&lt;li&gt;题库&lt;/li&gt;
&lt;li&gt;服务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;导航中的“我的组织”改为“我的队伍”。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;五、核心数据库表&lt;a href=&quot;#五核心数据库表&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;建议初步设计以下表：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;user&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;role&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;team&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;team_member&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;problem&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;problem_list&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;problem_list_item&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;assignment&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;assignment_target&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;assignment_progress&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;submission_record&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;contest&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;team_contest&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;contest_log&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;score_event&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;score_rule&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;user_score_summary&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;award&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;audit_log&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关键约束：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;队伍只能有一个队长&lt;/li&gt;
&lt;li&gt;用户名和外部平台账号按需求设置唯一约束&lt;/li&gt;
&lt;li&gt;同一用户同一题目的积分事件只能生成一次&lt;/li&gt;
&lt;li&gt;同一每日任务只能产生一次完成奖励&lt;/li&gt;
&lt;li&gt;所有重要修改保留操作人和时间&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;六、开发阶段&lt;a href=&quot;#六开发阶段&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;第一阶段：需求确认与原型设计&lt;a href=&quot;#第一阶段需求确认与原型设计&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;产出：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;最终功能清单&lt;/li&gt;
&lt;li&gt;用户角色和权限矩阵&lt;/li&gt;
&lt;li&gt;页面导航结构&lt;/li&gt;
&lt;li&gt;数据库初稿&lt;/li&gt;
&lt;li&gt;积分规则初稿&lt;/li&gt;
&lt;li&gt;隐私展示规则&lt;/li&gt;
&lt;li&gt;参考网站源码许可证确认&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;第二阶段：项目基础搭建&lt;a href=&quot;#第二阶段项目基础搭建&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;完成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Spring Boot 3 项目&lt;/li&gt;
&lt;li&gt;React + Vite 项目&lt;/li&gt;
&lt;li&gt;MySQL、Redis、JWT 基础配置&lt;/li&gt;
&lt;li&gt;统一返回结构&lt;/li&gt;
&lt;li&gt;全局异常处理&lt;/li&gt;
&lt;li&gt;登录、退出、刷新令牌&lt;/li&gt;
&lt;li&gt;基础布局和主题样式&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;第三阶段：用户与队伍管理&lt;a href=&quot;#第三阶段用户与队伍管理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;完成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户资料&lt;/li&gt;
&lt;li&gt;教练账号&lt;/li&gt;
&lt;li&gt;队伍创建&lt;/li&gt;
&lt;li&gt;队员管理&lt;/li&gt;
&lt;li&gt;唯一队长&lt;/li&gt;
&lt;li&gt;队伍首页&lt;/li&gt;
&lt;li&gt;我的队伍页面&lt;/li&gt;
&lt;li&gt;权限控制&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;第四阶段：作业与每日一题&lt;a href=&quot;#第四阶段作业与每日一题&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;完成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;队伍作业&lt;/li&gt;
&lt;li&gt;全体作业&lt;/li&gt;
&lt;li&gt;每日一题&lt;/li&gt;
&lt;li&gt;截止日期&lt;/li&gt;
&lt;li&gt;逾期标红&lt;/li&gt;
&lt;li&gt;完成状态&lt;/li&gt;
&lt;li&gt;作业进度统计&lt;/li&gt;
&lt;li&gt;教练管理页面&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;第五阶段：题单、刷题和比赛&lt;a href=&quot;#第五阶段题单刷题和比赛&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;完成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;题目记录&lt;/li&gt;
&lt;li&gt;队伍题单&lt;/li&gt;
&lt;li&gt;个人题单&lt;/li&gt;
&lt;li&gt;队员贡献题目&lt;/li&gt;
&lt;li&gt;比赛选择&lt;/li&gt;
&lt;li&gt;比赛日志&lt;/li&gt;
&lt;li&gt;参赛成员&lt;/li&gt;
&lt;li&gt;比赛成绩记录&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;第六阶段：积分、排行和个人中心&lt;a href=&quot;#第六阶段积分排行和个人中心&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;完成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;积分事件&lt;/li&gt;
&lt;li&gt;积分规则&lt;/li&gt;
&lt;li&gt;个人积分&lt;/li&gt;
&lt;li&gt;队伍积分&lt;/li&gt;
&lt;li&gt;排行榜&lt;/li&gt;
&lt;li&gt;积分趋势图&lt;/li&gt;
&lt;li&gt;隐私设置&lt;/li&gt;
&lt;li&gt;获奖记录&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;第七阶段：测试与上线&lt;a href=&quot;#第七阶段测试与上线&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;完成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;权限测试&lt;/li&gt;
&lt;li&gt;隐私测试&lt;/li&gt;
&lt;li&gt;积分幂等测试&lt;/li&gt;
&lt;li&gt;队长唯一性测试&lt;/li&gt;
&lt;li&gt;作业逾期测试&lt;/li&gt;
&lt;li&gt;前后端接口测试&lt;/li&gt;
&lt;li&gt;移动端适配&lt;/li&gt;
&lt;li&gt;数据库备份&lt;/li&gt;
&lt;li&gt;HTTPS&lt;/li&gt;
&lt;li&gt;Docker 部署&lt;/li&gt;
&lt;li&gt;日志和异常监控&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;七、测试重点&lt;a href=&quot;#七测试重点&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;必须重点测试：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;普通用户无法访问教练接口&lt;/li&gt;
&lt;li&gt;队员无法修改队长&lt;/li&gt;
&lt;li&gt;一个队伍不能同时存在两个队长&lt;/li&gt;
&lt;li&gt;私密用户数据不会通过排行榜泄露&lt;/li&gt;
&lt;li&gt;教练和站主可以查看完整信息&lt;/li&gt;
&lt;li&gt;同一道题不能重复获得积分&lt;/li&gt;
&lt;li&gt;同一每日一题不能重复获得奖励&lt;/li&gt;
&lt;li&gt;截止日期跨时区时状态正确&lt;/li&gt;
&lt;li&gt;全体作业不会漏掉有效队伍&lt;/li&gt;
&lt;li&gt;删除记录后积分能够正确修正&lt;/li&gt;
&lt;li&gt;多人同时提交时不会重复生成积分&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;八、部署方案&lt;a href=&quot;#八部署方案&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;建议使用 Docker Compose 部署：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nginx&lt;/li&gt;
&lt;li&gt;Spring Boot&lt;/li&gt;
&lt;li&gt;MySQL 8&lt;/li&gt;
&lt;li&gt;Redis&lt;/li&gt;
&lt;li&gt;前端静态文件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上线前配置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTPS&lt;/li&gt;
&lt;li&gt;JWT 密钥和数据库密码使用环境变量&lt;/li&gt;
&lt;li&gt;MySQL 定时备份&lt;/li&gt;
&lt;li&gt;Redis 持久化&lt;/li&gt;
&lt;li&gt;访问日志&lt;/li&gt;
&lt;li&gt;错误日志&lt;/li&gt;
&lt;li&gt;管理操作审计&lt;/li&gt;
&lt;li&gt;文件上传大小和类型限制&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;九、推荐的第一版范围&lt;a href=&quot;#九推荐的第一版范围&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;第一版优先实现：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;登录和角色权限&lt;/li&gt;
&lt;li&gt;队伍与队长管理&lt;/li&gt;
&lt;li&gt;队伍作业和全体作业&lt;/li&gt;
&lt;li&gt;每日一题与逾期状态&lt;/li&gt;
&lt;li&gt;题目、题单和做题记录&lt;/li&gt;
&lt;li&gt;比赛日志&lt;/li&gt;
&lt;li&gt;基础积分和排行榜&lt;/li&gt;
&lt;li&gt;隐私设置&lt;/li&gt;
&lt;li&gt;个人获奖信息&lt;/li&gt;
&lt;li&gt;管理后台&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在线判题平台自动同步、复杂比赛排名、移动端独立应用、消息推送等功能放到第二阶段，避免第一版范围过大。&lt;/p&gt;
&lt;p&gt;按照这个范围，项目可以先形成一个完整可用的校内算法队伍管理平台，再逐步扩展自动同步和更复杂的数据分析功能。&lt;/p&gt;</content:encoded><category>category:刷题计划</category><category>tag:刷题</category></item><item><title>LLM 学习</title><link>https://astro-jianyanya.pages.dev/post/llm-learning</link><guid isPermaLink="false">llm-learning</guid><description>模型训练
模型部署
数据集训练
[人类对齐](modelscope-classroom/LLM-tutorial/M.人类偏好对齐训练.md at main · modelscope/modelscope-classroom)
[大模型训练与推理](Swift DOCUMENTATION —</description><pubDate>Tue, 01 Sep 2026 14:28:00 GMT</pubDate><content:encoded>&lt;h1&gt;模型训练&lt;a href=&quot;#模型训练&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2&gt;模型部署&lt;a href=&quot;#模型部署&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;数据集训练&lt;a href=&quot;#数据集训练&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;[人类对齐](&lt;a href=&quot;https://github.com/modelscope/modelscope-classroom/blob/main/LLM-tutorial/M.%E4%BA%BA%E7%B1%BB%E5%81%8F%E5%A5%BD%E5%AF%B9%E9%BD%90%E8%AE%AD%E7%BB%83.md&quot;&gt;modelscope-classroom/LLM-tutorial/M.人类偏好对齐训练.md at main · modelscope/modelscope-classroom&lt;/a&gt;)
[大模型训练与推理](&lt;a href=&quot;https://swift.readthedocs.io/zh-cn/latest/&quot;&gt;Swift DOCUMENTATION — swift 4.5.0.dev0 文档&lt;/a&gt;)&lt;/p&gt;
&lt;h1&gt;transformer&lt;a href=&quot;#transformer&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/huggingface/transformers&quot;&gt;GitHub&lt;/a&gt;
[系统学习](&lt;a href=&quot;https://www.minimind.wiki/docs/guide/systematic&quot;&gt;系统学习 (6 小时) | minimind 从零理解 llm 训练 | minimind 从零理解 llm 训练&lt;/a&gt;)
[深度掌握](&lt;a href=&quot;https://www.minimind.wiki/docs/guide/mastery&quot;&gt;深度掌握 (30+小时) | minimind 从零理解 llm 训练 | minimind 从零理解 llm 训练&lt;/a&gt;)&lt;/p&gt;
&lt;h2&gt;核心机制一：自注意力（Self-Attention）&lt;a href=&quot;#核心机制一自注意力self-attention&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;核心机制二：多头注意力（Multi-Head Attention）&lt;a href=&quot;#核心机制二多头注意力multi-head-attention&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;核心机制三：位置编码（Positional Encoding）&lt;a href=&quot;#核心机制三位置编码positional-encoding&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;核心机制四：前馈网络（Feed-Forward Network, FFN）&lt;a href=&quot;#核心机制四前馈网络feed-forward-network-ffn&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;核心机制五：残差连接与层归一化&lt;a href=&quot;#核心机制五残差连接与层归一化&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;技术论文&lt;a href=&quot;#技术论文&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://arxiv.org/abs/1706.03762&quot;&gt;奠基之作&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;三大架构变体&lt;/strong&gt;&lt;a href=&quot;#三大架构变体&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/1810.04805&quot;&gt;BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/1909.07930&quot;&gt;Language Models are Unsupervised Multitask Learners&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2005.14165&quot;&gt;&lt;strong&gt;Language Models are Few-Shot Learners&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/1910.10683&quot;&gt;&lt;strong&gt;Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;&lt;strong&gt;位置编码的演进&lt;/strong&gt;&lt;a href=&quot;#位置编码的演进&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2104.09864&quot;&gt;&lt;strong&gt;RoFormer: Enhanced Transformer with Rotary Position Embedding&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2309.00071&quot;&gt;&lt;strong&gt;YaRN: Efficient Context Window Extension of Large Language Models&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;&lt;strong&gt;FFN 与激活函数的演进&lt;/strong&gt;&lt;a href=&quot;#ffn-与激活函数的演进&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2002.05202&quot;&gt;&lt;strong&gt;GLU Variants Improve Transformer&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kexue.fm/archives/8265&quot;&gt;博采众长的旋转式位置编码&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;同时这里补充关于激活函数的理论视角&lt;a href=&quot;#同时这里补充关于激活函数的理论视角&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://arxiv.org/abs/1611.01730&quot;&gt;信号传播理论(Mean Field Theory)&lt;/a&gt;
&lt;a href=&quot;https://arxiv.org/abs/1806.07572&quot;&gt;神经正切核（NTK）理论&lt;/a&gt;
&lt;a href=&quot;https://arxiv.org/abs/1503.02406&quot;&gt;表达能力的深度-宽度权衡&lt;/a&gt;
&lt;a href=&quot;https://arxiv.org/abs/1606.05340&quot;&gt;信息瓶颈理论&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这里 ai 补充了另一种视角叫&lt;strong&gt;梯度景观与优化动力学&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这个视角最直接地解释”为什么模型能训得动”。
激活函数通过其导数形状决定了反向传播时梯度的行为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ReLU&lt;/strong&gt;：导数在正半轴恒为 1（梯度传播好），负半轴恒为 0（神经元可能永久死亡）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GELU&lt;/strong&gt;：负半轴有非零梯度，避免了死亡问题，但在 x ≈ 0 附近梯度变化剧烈，可能导致优化不稳定。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Swish&lt;/strong&gt;（x · σ(βx)）：负半轴有非零且有界的值（不会死亡），在 x ≈ 0 处光滑（优化稳定），且导数值域更宽（梯度信号更丰富）。当 β 可学习时，网络甚至可以自适应调整激活函数的”硬度”。
门控机制（GLU 系列）在此基础上叠加了&lt;strong&gt;输入相关的动态调制&lt;/strong&gt;——对于每个输入，门控分支产生不同的梯度缩放因子。这等价于让优化器在每一步都有更好的”方向指引”，降低了陷入鞍点或平坦区域的概率。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;MoE（混合专家）&lt;/strong&gt;&lt;a href=&quot;#moe混合专家&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/1701.06538&quot;&gt;&lt;strong&gt;Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2401.04088&quot;&gt;&lt;strong&gt;Mixtral of Experts&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;&lt;strong&gt;规模定律与训练范式&lt;/strong&gt;&lt;a href=&quot;#规模定律与训练范式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2001.08361&quot;&gt;&lt;strong&gt;Scaling Laws for Neural Language Models&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2203.15556&quot;&gt;&lt;strong&gt;Training Compute-Optimal Large Language Models&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;&lt;strong&gt;现代 LLaMA 系列&lt;/strong&gt;&lt;a href=&quot;#现代-llama-系列&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2302.13971&quot;&gt;&lt;strong&gt;LLaMA: Open and Efficient Foundation Language Models&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/abs/2412.19437&quot;&gt;&lt;strong&gt;DeepSeek-V3 Technical Report&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</content:encoded><category>category:复合对话Agent</category><category>tag:LLM</category></item><item><title>CF 2225 F 题解</title><link>https://astro-jianyanya.pages.dev/post/cf-2225-f</link><guid isPermaLink="false">cf-2225-f</guid><description>
题目链接

首先，我们来证明将字符串恰好分割成 k 个部分总是最优的。假设我们将其分割成 x &amp;gt; k 个部分；如果我们合并两个相邻的部分，可以证明按排序顺序排列的第 k 个部分的长度不会减少。kkk假设我们把它切成几部分。x&amp;gt;kx \gt</description><pubDate>Sun, 03 May 2026 12:27:00 GMT</pubDate><content:encoded>&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://codeforces.com/contest/2225/problem/F&quot;&gt;题目链接&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;首先，我们来证明将字符串恰好分割成 k 个部分总是最优的。假设我们将其分割成 x &amp;gt; k 个部分；如果我们合并两个相邻的部分，可以证明按排序顺序排列的第 k 个部分的长度不会减少。&lt;span&gt;&lt;span&gt;kk&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;假设我们把它切成几部分。&lt;span&gt;&lt;span&gt;x&amp;gt;kx \gt k&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;各个部分；如果我们合并两个相邻的部分，可以证明：&lt;span&gt;&lt;span&gt;kk&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;按排序顺序排列的第 1 部分不会减少。&lt;/p&gt;
&lt;p&gt;证明：某个多重集的第 k 个最小元素可以定义为满足以下条件的最小值：该多重集包含至少 k 个不大于 a 的元素。假设我们合并字符串的两个部分：&lt;span&gt;&lt;span&gt;tit_i&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;和&lt;span&gt;&lt;span&gt;ti+1t_{i+1}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;；那么合并后的部分构成的多重集中会移除元素&lt;span&gt;&lt;span&gt;t_it\_i&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;和&lt;span&gt;&lt;span&gt;ti+1t_{i+1}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，并插入一个新元素&lt;span&gt;&lt;span&gt;ti′=ti+ti+1&amp;gt;tit&apos;_i = t_i + t_{i+1} &amp;gt; t_i&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。对于任意字符串 a，不大于 a 的多重集中的元素个数不可能增加；因此，满足该多重集元素个数至少为 k 的最小值 a 不可能减少。所以，我们可以合并任意两个相邻的部分，结果都不会变差。&lt;span&gt;&lt;span&gt;kk&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;某个多重集的第个最小元素可以定义为最小值&lt;span&gt;&lt;span&gt;aa&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;使得多重集至少包含&lt;span&gt;&lt;span&gt;kk&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;元素不大于&lt;span&gt;&lt;span&gt;aa&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;假设我们将字符串的两个部分合并，&lt;span&gt;&lt;span&gt;tit_i&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;和&lt;span&gt;&lt;span&gt;ti+1t_{i+1}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;然后是元素&lt;span&gt;&lt;span&gt;tit_i&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;和&lt;span&gt;&lt;span&gt;ti+1t_{i+1}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;从结果部件的多重集中移除，并添加一个新元素。&lt;span&gt;&lt;span&gt;ti′=ti+ti+1&amp;gt;tit&apos;_i = t_i + t_{i+1} \gt t_i&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;插入。对于每个字符串&lt;span&gt;&lt;span&gt;aa&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;多重集中的元素个数不大于&lt;span&gt;&lt;span&gt;aa&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;不能增加；因此，最小值&lt;span&gt;&lt;span&gt;aa&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;其中此类元素的数量至少为&lt;span&gt;&lt;span&gt;kk&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;不能减少。因此，我们可以合并任意两个相邻的部分，结果不会变差。&lt;/p&gt;
&lt;p&gt;所以现在我们总是把字符串切成正好&lt;span&gt;&lt;span&gt;kk&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;部分。当&lt;span&gt;&lt;span&gt;k=1k=1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;时，这意味着原始字符串本身就是答案（如果它的长度至少为&lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;）；当&lt;span&gt;&lt;span&gt;k&amp;gt;1k \gt 1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;时，我们需要考虑几个可能的答案，并从中选择最佳答案。&lt;span&gt;&lt;span&gt;kk&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;部分。当&lt;span&gt;&lt;span&gt;k=1k=1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;这意味着原始字符串本身就是答案（如果它的长度至少为 1）。&lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;）; 什么时候&lt;span&gt;&lt;span&gt;k&amp;gt;1k \gt 1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;我们需要考虑几个可能的答案，并从中选择最佳答案。&lt;/p&gt;
&lt;p&gt;假设我们要检查子串 &lt;span&gt;&lt;span&gt;t=sLsL+1…sRt = s_{L} s_{L+1} \dots s_R&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;…&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 是否可能是答案。那么必须满足以下条件：&lt;span&gt;&lt;span&gt;t=sLsL+1…sRt = s_{L} s_{L+1} \dots s_R&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;…&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;这可能是答案。那么必须满足以下条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;位置 &lt;span&gt;&lt;span&gt;LL&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 之前的前缀可以切成长度至少为 &lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的字符串；&lt;span&gt;&lt;span&gt;LL&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;可以剪成至少一定长度的条状&lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;位置 &lt;span&gt;&lt;span&gt;RR&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 之后的后缀可以截断为长度至少为 &lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的字符串；&lt;span&gt;&lt;span&gt;RR&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;可以剪成至少一定长度的条状&lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;前缀和后缀可以被截断，使得它们组合在一起正好形成 &lt;span&gt;&lt;span&gt;(k−1)(k-1)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 个字符串，并且所有这些字符串在字典序上都不大于 &lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。&lt;span&gt;&lt;span&gt;(k−1)(k-1)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;字符串，并且所有这些字符串的字典序都不大于&lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第一和第二个条件很容易检查——如果前缀或后缀包含的字符数超过 &lt;span&gt;&lt;span&gt;00&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 且少于 &lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，则它不能被分割成长度至少为 &lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的部分。然而，第三个条件的检查就困难得多。我们不直接检查它，而是利用我们感兴趣的最大合适字符串 &lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的特性。这使得我们可以简化第三个条件，去掉剩余部分在字典序上不能大于 &lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的要求——如果存在一个字典序大于 &lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的字符串，那么我们也将其视为候选字符串，这意味着当前的字符串 &lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 无论如何都不可能是答案。&lt;span&gt;&lt;span&gt;00&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;且少于&lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;如果是字符，那么它至少不能被切割成若干长度的部分。&lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;然而，第三个条件更难验证。我们不直接验证它，而是利用我们感兴趣的是最大合适字符串这一事实。&lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;这样，我们就可以简化第三个条件，去掉剩余部分在字典序上不能大于某个特定值的要求。&lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;— 如果在这些部分中存在一个字符串，其字典序大于&lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;那么，我们也会将其视为候选字符串，这意味着当前字符串&lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;无论如何，这都不可能是答案。&lt;/p&gt;
&lt;p&gt;这样，我们可以将条件重新表述如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;位置 &lt;span&gt;&lt;span&gt;LL&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 之前的前缀可以切成长度至少为 &lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的字符串；&lt;span&gt;&lt;span&gt;LL&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;可以剪成至少一定长度的条状&lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;位置 &lt;span&gt;&lt;span&gt;RR&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 之后的后缀可以截断为长度至少为 &lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的字符串；&lt;span&gt;&lt;span&gt;RR&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;可以剪成至少一定长度的条状&lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;前缀和后缀可以被截断，使得它们组合在一起正好形成长度至少为 &lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的 &lt;span&gt;&lt;span&gt;(k−1)(k-1)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 个字符串。&lt;span&gt;&lt;span&gt;(k−1)(k-1)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;长度至少为&lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于单个子串，这些条件可以在 &lt;span&gt;&lt;span&gt;O(1)O(1)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 内检查，这给我们提供了 &lt;span&gt;&lt;span&gt;O(n2)O(n^2)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 个候选对象。&lt;span&gt;&lt;span&gt;O(1)O(1)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;这使我们有&lt;span&gt;&lt;span&gt;O(n2)O(n^2)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;候选人。&lt;/p&gt;
&lt;p&gt;利用从位置&lt;span&gt;&lt;span&gt;LL&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;到位置&lt;span&gt;&lt;span&gt;(R+1)(R+1)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;的子串在字典序上总是大于从位置&lt;span&gt;&lt;span&gt;LL&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;到位置&lt;span&gt;&lt;span&gt;RR&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;的子串这一事实，可以将候选子串的数量减少到&lt;span&gt;&lt;span&gt;O(n)O(n)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。因此，我们可以遍历左边界&lt;span&gt;&lt;span&gt;LL&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，并为每个左边界找到满足所有条件的最大右边界&lt;span&gt;&lt;span&gt;RR&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。这可以通过一个相当简单的计算来实现——我们需要确定前缀可以得到多少个子串，这将表明最小后缀长度是多少。&lt;span&gt;&lt;span&gt;O(n)O(n)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;利用位置子字符串这一事实&lt;span&gt;&lt;span&gt;LL&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;定位&lt;span&gt;&lt;span&gt;(R+1)(R+1)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;始终在字典序上大于位置 的子字符串。&lt;span&gt;&lt;span&gt;LL&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;定位&lt;span&gt;&lt;span&gt;RR&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;因此，我们可以遍历左边界。&lt;span&gt;&lt;span&gt;LL&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;并找到它们各自的最大右边界&lt;span&gt;&lt;span&gt;RR&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;满足所有条件。这可以通过一个相当简单的计算来实现——我们需要确定前缀可以分成多少个部分，这将表明后缀的最小长度必须是多少。&lt;/p&gt;
&lt;p&gt;现在我们有 O(n) 个字符串，每个字符串都是原字符串的子串，我们需要从中选择字典序最大的那个。遗憾的是，问题中的约束条件过于严格，无法方便地使用后缀结构（至少我们无法让后缀数组足够快速地工作）。我们提出两种解决方案：&lt;span&gt;&lt;span&gt;O(n)O(n)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;多个字符串，每个字符串都是原始字符串的子字符串。&lt;span&gt;&lt;span&gt;ss&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;其中我们需要选择字典序最大的那个。遗憾的是，问题中的约束条件过于严格，无法方便地使用后缀结构（至少我们无法让后缀数组运行得足够快）。我们提出两种解决方案：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;方法 1 — 哈希值 (FelixArg)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;为字符串的所有前缀构建多项式哈希，并预先计算哈希基的所有幂（以及可能的模逆——尽管这不是必需的）。这使我们能够在&lt;span&gt;&lt;span&gt;O(1)O(1)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;中检查两个子串是否相等。&lt;span&gt;&lt;span&gt;O(1)O(1)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;但仅仅比较相等性是不够的；我们需要确定两个子串哪个更大，哪个更小。我们可以使用二分查找法，在 O(log n) 的时间复杂度内计算出两个子串的最长公共前缀。最长公共前缀之后的下一个字符就告诉我们哪个子串更大。一旦我们能够在 O(log n) 的时间复杂度内比较两个子串，我们就可以轻松地在 O(n log n) 的时间复杂度内找到其中的最大值。&lt;span&gt;&lt;span&gt;O(log⁡n)O(\log n)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;lo&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;使用二分查找法比较子串的长度。最长公共前缀之后的下一个字符可以告诉我们哪个子串更长。一旦我们能够比较两个子串的长度，&lt;span&gt;&lt;span&gt;O(log⁡n)O(\log n)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;lo&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;我们可以很容易地找到其中的最大值。&lt;span&gt;&lt;span&gt;O(nlog⁡n)O(n \log n)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;lo&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;为避免碰撞问题，我们建议使用双基/模哈希。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;方法 2 — z 函数 (BledDest)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;取候选答案 &lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，构建字符串 &lt;span&gt;&lt;span&gt;t+d+st + d + s&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的 z 函数，其中 &lt;span&gt;&lt;span&gt;dd&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 为分隔符。z 函数将显示 &lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 与其他每个候选答案的最长公共前缀的长度。这使我们能够将 &lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 与其他候选答案进行比较，从而将它们分成三组：&lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;并为该字符串构建 z 函数&lt;span&gt;&lt;span&gt;t+d+st + d + s&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;， 在哪里&lt;span&gt;&lt;span&gt;dd&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;是某种分隔符。z 函数将显示最长公共前缀的长度&lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;以及其他每位候选人的答案。这使我们能够进行比较。&lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;与其他候选人一起，因此将他们分成三组：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;小于 &lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;;&lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;等于 &lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;;&lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;；&lt;/li&gt;
&lt;li&gt;大于 &lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。&lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果第三个集合为空，那么&lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;就是问题的答案，因为它是最大值。否则，我们只对第三个集合感兴趣，可以继续分析它，而无需分析所有候选集合。&lt;span&gt;&lt;span&gt;tt&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;由于它是最大值，因此是问题的答案。否则，我们只对第三组感兴趣，可以继续分析它，而无需分析所有候选集。&lt;/p&gt;
&lt;p&gt;如果我们随机选择候选答案，平均需要处理 &lt;span&gt;&lt;span&gt;O(log⁡n)O(\log n)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;lo&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 个候选答案（这可以用与随机快速排序的递归深度或随机笛卡尔树的深度大致相同的方式证明）。每个候选答案的检查时间为 &lt;span&gt;&lt;span&gt;O(n)O(n)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，因此总复杂度为 &lt;span&gt;&lt;span&gt;O(nlog⁡n)O(n \log n)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;lo&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。&lt;span&gt;&lt;span&gt;O(log⁡n)O(\log n)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;lo&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;候选答案的平均值为（这可以用与随机快速排序的递归深度或随机笛卡尔树的深度大致相同的方式证明）。每个候选答案都会被检查。&lt;span&gt;&lt;span&gt;O(n)O(n)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，总复杂度为&lt;span&gt;&lt;span&gt;O(nlog⁡n)O(n \log n)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;O&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;lo&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。&lt;/p&gt;</content:encoded><category>category:题解</category><category>tag:Codeforces</category></item><item><title>洛谷 P1495 曹冲养猪 题解</title><link>https://astro-jianyanya.pages.dev/post/luogu-p1495</link><guid isPermaLink="false">luogu-p1495</guid><description>题意
试求如下同余方程组的最小非负整数解：
{x≡a1( mod b1)x≡a2( mod b2)⋯x≡an( mod bn)\left\{\begin{array}{l}x \equiv a_{1}\left(\bmod b_{1}\right) \\x \equiv</description><pubDate>Sun, 19 Apr 2026 07:43:00 GMT</pubDate><content:encoded>&lt;h2&gt;题意&lt;a href=&quot;#题意&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;试求如下同余方程组的最小非负整数解：&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;{x≡a1( mod b1)x≡a2( mod b2)⋯x≡an( mod bn)\left\{\begin{array}{l}x \equiv a_{1}\left(\bmod b_{1}\right) \\x \equiv a_{2}\left(\bmod b_{2}\right) \\\cdots \\x \equiv a_{n}\left(\bmod b_{n}\right)\end{array}\right.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎩&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎨&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎧&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⋯&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;其中，&lt;span&gt;&lt;span&gt;bib_i&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;​ 两两互质。&lt;/p&gt;
&lt;h2&gt;思路&lt;a href=&quot;#思路&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;首先，由余数的可加性可知，若可以求得以下 n 个方程的解，那便可以求出原方程的解：&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;{x≡a1( mod b1)x≡0( mod b2)⋯x≡0( mod bn)\left\{\begin{array}{l}x \equiv a_{1}\left(\bmod b_{1}\right) \\x \equiv 0\left(\bmod b_{2}\right) \\\cdots \\x \equiv 0\left(\bmod b_{n}\right)\end{array}\right.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎩&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎨&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎧&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⋯&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;  &lt;span&gt;&lt;span&gt;{x≡0( mod b1)x≡a2( mod b2)⋯x≡0( mod bn)\left\{\begin{array}{l}x \equiv 0\left(\bmod b_{1}\right) \\x \equiv a_{2}\left(\bmod b_{2}\right) \\\cdots \\x \equiv 0\left(\bmod b_{n}\right)\end{array}\right.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎩&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎨&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎧&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⋯&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;  &lt;span&gt;&lt;span&gt;{x≡0( mod b1)x≡0( mod b2)⋯x≡an( mod bn)\left\{\begin{array}{l}x \equiv 0\left(\bmod b_{1}\right) \\x \equiv 0\left(\bmod b_{2}\right) \\\cdots \\x \equiv a_{n}\left(\bmod b_{n}\right)\end{array}\right.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎩&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎨&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎧&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⋯&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;此时，便有原方程的解 &lt;span&gt;&lt;span&gt;x=x1​+x2​+⋯+xnx=x_1​+x_2​+⋯+x_n&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;⋯&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;​。&lt;/p&gt;
&lt;p&gt;现在，考虑将每一个方程组拿出来单独求解。我拿第一个方程组讲解：&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;{x≡a1( mod b1)x≡0( mod b2)⋯x≡0( mod bn)\left\{\begin{array}{l}x \equiv a_{1}\left(\bmod b_{1}\right) \\x \equiv 0\left(\bmod b_{2}\right) \\\cdots \\x \equiv 0\left(\bmod b_{n}\right)\end{array}\right.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎩&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎨&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎧&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⋯&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;要求出如上这个方程的解，其实可以再做一步转换，先求出以下这个方程的解：&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;{y≡a1( mod b1)y≡0( mod b2)⋯y≡0( mod bn)\left\{\begin{array}{l}y \equiv a_{1}\left(\bmod b_{1}\right) \\y \equiv 0\left(\bmod b_{2}\right) \\\cdots \\y \equiv 0\left(\bmod b_{n}\right)\end{array}\right.&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎩&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎨&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⎧&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;⋯&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;由余数的可乘性得：&lt;span&gt;&lt;span&gt;x1=y1×a1x_{1}=y_{1} \times a_{1}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;​。同时，观察方程组可知 &lt;span&gt;&lt;span&gt;y1y_1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;​ 一定是 &lt;span&gt;&lt;span&gt;∏i=2nbi\prod_{i=2}^{n} b_{i}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;∏&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的倍数。设&lt;span&gt;&lt;span&gt;∏i=2nbi\prod_{i=2}^{n} b_{i}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;∏&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 为 &lt;span&gt;&lt;span&gt;m1m_1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;​，则有 &lt;span&gt;&lt;span&gt;y1=m1×k1y_{1}=m_{1} \times k_{1}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;​。因为 &lt;span&gt;&lt;span&gt;y1y_1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;​ 还要满足第一个同余方程，所以此时得到：&lt;span&gt;&lt;span&gt;m1×k1≡1( mod b1)m_{1} \times k_{1} \equiv 1 \left(\bmod b_{1}\right)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≡&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。于是，求 &lt;span&gt;&lt;span&gt;y1y_1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;​ 的问题就转换成了求 &lt;span&gt;&lt;span&gt;m1 mod b1m_{1} \bmod b_{1}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;​ 的逆元的问题，可以用扩展欧几里得算法求解。&lt;/p&gt;
&lt;p&gt;于是便可以按这种方法，求出上面的 n 个方程组的解，然后便得到了原方程的&lt;strong&gt;整数解&lt;/strong&gt;。不过还要再进行对所有的数的乘积的取模，因为要求&lt;strong&gt;最小非负整数解&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;所以，设所有的数的乘积为 k，则最终答案用式子表达便是：&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;x=∑i=1nki×ai×mi( mod k)x = \sum_{i=1}^{n}k_i\times a_i \times m_i (\bmod k)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;∑&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;#include&lt;/span&gt;&lt;span&gt;&amp;lt;bits/stdc++.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; namespace&lt;/span&gt;&lt;span&gt; std&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;typedef&lt;/span&gt;&lt;span&gt; long&lt;/span&gt;&lt;span&gt; long&lt;/span&gt;&lt;span&gt; ll&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt; myul&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt; mod&lt;/span&gt;&lt;span&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ll ans &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    while&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        if&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; ans &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;ans &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        a &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;mod&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        b &lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; ans&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt; exgcd&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt; A&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt; B&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        x &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;y &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        return&lt;/span&gt;&lt;span&gt; A&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ll d &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; exgcd&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ll t &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    x &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;y &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; t &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; A&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; d&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt; lcm&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt; A&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt; B&lt;/span&gt;&lt;span&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ll x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ll g &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; exgcd&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; main&lt;/span&gt;&lt;span&gt;(){&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    int&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;cin&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    vector&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;ll&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    for&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;&amp;lt;=&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; cin&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ll x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ll m &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;span&gt;ans &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    for&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;&amp;lt;=&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        ll A &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; m&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;B &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        ll c &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt; ans&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;B &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; B&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        ll g &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; exgcd&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        if&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; return&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        x &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; myul&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        ans &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        m &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; lcm&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        ans &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;ans&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;m &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; m&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    cout&lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt;ans&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded><category>category:题解</category><category>tag:洛谷</category><category>tag:中国剩余定理</category></item><item><title>2025-12-24 学习日记</title><link>https://astro-jianyanya.pages.dev/post/diary-2025-12-24</link><guid isPermaLink="false">diary-2025-12-24</guid><description>前言
好多题不能再让我有进步了,我记录的也少了,还是说尽可能的记录我感想多的题目
今日学习记录
1. P14826 踩踩标 - 洛谷
关键词：数学
问题分析：
根据a∗b+c=n,y=a+b+k∗ca*b+c=n,y=a+b+k*ca∗b+c=n,y=a+b+k∗c计算 y 的最小值,给定 n 和</description><pubDate>Wed, 24 Dec 2025 04:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;前言&lt;a href=&quot;#前言&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;好多题不能再让我有进步了,我记录的也少了,还是说尽可能的记录我感想多的题目&lt;/p&gt;
&lt;h2&gt;今日学习记录&lt;a href=&quot;#今日学习记录&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. &lt;a href=&quot;https://www.luogu.com.cn/problem/P14826?contestId=276342&quot;&gt;P14826 踩踩标 - 洛谷&lt;/a&gt;&lt;a href=&quot;#1-p14826-踩踩标---洛谷&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;关键词&lt;/strong&gt;：&lt;code&gt;数学&lt;/code&gt;
&lt;strong&gt;问题分析&lt;/strong&gt;：
根据&lt;span&gt;&lt;span&gt;a∗b+c=n,y=a+b+k∗ca*b+c=n,y=a+b+k*c&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∗&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∗&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;计算 y 的最小值,给定 n 和 k,其中&lt;span&gt;&lt;span&gt;c&amp;gt;=0c&amp;gt;=0&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&amp;gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心思路&lt;/strong&gt;:
这里很重要,要讲一个思维性的突破
我们在做这种数学的时候,比如蓝桥杯那样的数学填空题时,并不是真的让你算完了再填答案,而是真正的使用计算机去算,但是怎么使用计算机就是主要问题,这里详细说明
先点明主题,使用计算机就是使用他的强大的计算能力,我们学算法的都知道,我们先使用暴力模拟,再想办法设计合适的算法进行优化,所以回归本质就是枚举暴力,那么这里就是这样的
那么在实际思考数学题目的时候,我们该怎么想,比如当前这道题目
我们可以看到,有三个变量,两个式子,那么可以化简一个式子,使其中一个变量用其他变量表达
于是,只剩下两个变量了,那么我们开始使用枚举思想,都要枚举了,自然就假设我们已经知道枚举的那个数字,这样就直接思考后面的式子是否能成立,假设知道 x,y 能不能算出来
当然,我们不能无脑的去枚举(计算机的优势就在这里,因为我们要使用的是数学计算,时间复杂度在 O(n)左右,所以程序几乎可以跑 1~1e9 的数据,可以枚举的范围算是大的),我们要通过式子和题目的背景对变量进行范围约束,看这个变量的范围能否找到,优先考虑枚举范围明确的变量,这样要简单多,性能要好很多
这题我们可以看出,c&amp;gt;=0,所以&lt;span&gt;&lt;span&gt;n&amp;gt;=a∗bn&amp;gt;=a*b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&amp;gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∗&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,这里有个极值问题,当 a=b 的时候&lt;span&gt;&lt;span&gt;a∗ba*b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∗&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;有最大值,所以可以取 a=b,得到&lt;span&gt;&lt;span&gt;a&amp;lt;=根号下的ca&amp;lt;=根号下的c&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;根号下的&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,a 又大于 0,所以 a 的范围明确了,&lt;span&gt;&lt;span&gt;c=n−a∗b,b=n/ac=n-a*b,b=n/a&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∗&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 这样所以的未知数都知道了,直接记录 y 的最小值就行了&lt;/p&gt;
&lt;p&gt;**最终代码：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;#include&lt;/span&gt;&lt;span&gt; &amp;lt;bits/stdc++.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; namespace&lt;/span&gt;&lt;span&gt; std&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#define&lt;/span&gt;&lt;span&gt; ve&lt;/span&gt;&lt;span&gt; vector&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; ll&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; long&lt;/span&gt;&lt;span&gt; long&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; ull&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; unsigned&lt;/span&gt;&lt;span&gt; long&lt;/span&gt;&lt;span&gt; long&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; sr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; db&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; double&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; dll&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; double&lt;/span&gt;&lt;span&gt; long&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; int&lt;/span&gt;&lt;span&gt; MOD&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;998244353&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; ll INF&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;18&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; int&lt;/span&gt;&lt;span&gt; DIR&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;][&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {{&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;},{&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;},{&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;},{&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;}};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; T&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; solve&lt;/span&gt;&lt;span&gt;(){&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ll n&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; k&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        cin&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt;k&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        if&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;k &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            cout&lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt;endl&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        ll  ans &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; k &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        ll sqrt_n &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; sqrt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        for&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ll a &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;a &lt;/span&gt;&lt;span&gt;&amp;lt;=&lt;/span&gt;&lt;span&gt; sqrt_n&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            ll b &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; n &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            ll c &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; n &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            ll val &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; b &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; k &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            if&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; ans&lt;/span&gt;&lt;span&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                ans &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; val&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        cout&lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt;ans&lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt;endl&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;signed&lt;/span&gt;&lt;span&gt; main&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ios_base&lt;/span&gt;&lt;span&gt;::&lt;/span&gt;&lt;span&gt;sync_with_stdio&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    cin&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;tie&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;nullptr&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    cin&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    while&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;--&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; solve&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;学到的点&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;如何看待计算机中的数学题&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;</content:encoded><category>category:笔记</category><category>tag:学习日记</category><category>tag:数学</category></item><item><title>2025-12-17 学习日记</title><link>https://astro-jianyanya.pages.dev/post/diary-2025-12-17</link><guid isPermaLink="false">diary-2025-12-17</guid><description>今日学习记录
1. https://codeforces.com/problemset/problem/1850/H
关键词：
问题分析：
核心思路:
**最终代码：
学到的点：
1.
</description><pubDate>Wed, 17 Dec 2025 04:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;今日学习记录&lt;a href=&quot;#今日学习记录&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. &lt;a href=&quot;https://codeforces.com/problemset/problem/1850/H&quot;&gt;https://codeforces.com/problemset/problem/1850/H&lt;/a&gt;&lt;a href=&quot;#1-httpscodeforcescomproblemsetproblem1850h&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;关键词&lt;/strong&gt;：
&lt;strong&gt;问题分析&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心思路&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;**最终代码：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;学到的点&lt;/strong&gt;：
1.&lt;/p&gt;
&lt;hr /&gt;</content:encoded><category>category:笔记</category><category>tag:学习日记</category><category>tag:并查集</category></item><item><title>2025-12-14 学习日记</title><link>https://astro-jianyanya.pages.dev/post/diary-2025-12-14</link><guid isPermaLink="false">diary-2025-12-14</guid><description>给定一棵二叉搜索树的先序遍历序列，要求你找出任意两结点的最近公共祖先结点（简称 LCA）。
输入格式
输入的第一行给出两个正整数：待查询的结点对数 M（≤ 1 000）和二叉搜索树中结点个数 N（≤ 10 000）。随后一行给出 N 个不同的整数，为二叉搜索树的先序遍历序列。最后 M</description><pubDate>Sun, 14 Dec 2025 04:00:00 GMT</pubDate><content:encoded>&lt;p&gt;给定一棵二叉搜索树的先序遍历序列，要求你找出任意两结点的最近公共祖先结点（简称 LCA）。&lt;/p&gt;
&lt;h3&gt;输入格式&lt;a href=&quot;#输入格式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;输入的第一行给出两个正整数：待查询的结点对数 M（≤ 1 000）和二叉搜索树中结点个数 N（≤ 10 000）。随后一行给出 N 个不同的整数，为二叉搜索树的先序遍历序列。最后 M 行，每行给出一对整数键值 U 和 V。所有键值都在整型&lt;strong&gt;int&lt;/strong&gt;范围内。&lt;/p&gt;
&lt;h3&gt;输出格式&lt;a href=&quot;#输出格式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;对每一对给定的 U 和 V，如果找到 &lt;code&gt;A&lt;/code&gt; 是它们的最近公共祖先结点的键值，则在一行中输出 &lt;code&gt;LCA of U and V is A.&lt;/code&gt;。但如果 U 和 V 中的一个结点是另一个结点的祖先，则在一行中输出 &lt;code&gt;X is an ancestor of Y.&lt;/code&gt;，其中 &lt;code&gt;X&lt;/code&gt; 是那个祖先结点的键值，&lt;code&gt;Y&lt;/code&gt; 是另一个键值。如果 二叉搜索树中找不到以 U 或 V 为键值的结点，则输出 &lt;code&gt;ERROR: U is not found.&lt;/code&gt; 或者 &lt;code&gt;ERROR: V is not found.&lt;/code&gt;，或者 &lt;code&gt;ERROR: U and V are not found.&lt;/code&gt;。&lt;/p&gt;</content:encoded><category>category:笔记</category><category>tag:学习日记</category></item><item><title>2025-12-09 学习日记</title><link>https://astro-jianyanya.pages.dev/post/diary-2025-12-09</link><guid isPermaLink="false">diary-2025-12-09</guid><description>今日学习记录
1. 3583. 统计特殊三元组
关键词：数组 哈希表
问题分析：
找到数组中 0&amp;lt;i&amp;lt;j&amp;lt;k,且nums[i]==nums[j]*2==nums[k]的数量
核心思路:
枚举</description><pubDate>Tue, 09 Dec 2025 04:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;今日学习记录&lt;a href=&quot;#今日学习记录&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. &lt;a href=&quot;https://leetcode.cn/problems/count-special-triplets/&quot;&gt;3583. 统计特殊三元组&lt;/a&gt;&lt;a href=&quot;#1-3583-统计特殊三元组&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;关键词&lt;/strong&gt;：&lt;code&gt;数组&lt;/code&gt; &lt;code&gt;哈希表&lt;/code&gt;
&lt;strong&gt;问题分析&lt;/strong&gt;：
找到数组中 0&amp;lt;i&amp;lt;j&amp;lt;k,且&lt;code&gt;nums[i]==nums[j]*2==nums[k]&lt;/code&gt;的数量&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心思路&lt;/strong&gt;:&lt;/p&gt;
&lt;h4&gt;枚举&lt;a href=&quot;#枚举&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;先预处理所有数字的出现次数,采取枚举中间的数的做法,同时记录左端数组中数字的出现次数,预处理的 map 就右边的数量,每次枚举时,左端数量增多,右边减少,ans += &lt;code&gt;l*r&lt;/code&gt;;&lt;/p&gt;
&lt;h4&gt;一次遍历(枚举右,维护左)&lt;a href=&quot;#一次遍历枚举右维护左&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;思考,我们不仅可以枚举中间,我们可以枚举右边,要找到&lt;code&gt;mp[x]和mp[x/2]&lt;/code&gt;,当右端为 x 时,就是要加上前面所有的 x 的数量,但是怎么确定中间出现过 x/2,我们在每次遍历到 x/2 的时候加上 x 的次数就行了
**最终代码：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; int&lt;/span&gt;&lt;span&gt; MOD &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;9&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;7&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    int&lt;/span&gt;&lt;span&gt; specialTriplets&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;vector&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt; nums&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        int&lt;/span&gt;&lt;span&gt; n &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;nums&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;size&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        unordered_map&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;long&lt;/span&gt;&lt;span&gt; long&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; cnt1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;cnt2&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        long&lt;/span&gt;&lt;span&gt; long&lt;/span&gt;&lt;span&gt; ans &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        for&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; x&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;nums&lt;/span&gt;&lt;span&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            if&lt;/span&gt;&lt;span&gt;((&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; ans &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;ans&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;cnt1&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;MOD&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            cnt1&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; +=&lt;/span&gt;&lt;span&gt; cnt2&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            cnt2&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        return&lt;/span&gt;&lt;span&gt; ans&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;MOD&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;学到的点&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;枚举右维护左&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;</content:encoded><category>category:笔记</category><category>tag:学习日记</category><category>tag:哈希表</category></item><item><title>2025-12-08 学习日记</title><link>https://astro-jianyanya.pages.dev/post/diary-2025-12-08</link><guid isPermaLink="false">diary-2025-12-08</guid><description>今日学习记录
1. P14665 [KenOI 2025] 序列题 - 洛谷
关键词：二分答案
问题分析：
给出一个序列,可对其进行区间上的加减一操作,求在进行 m 次操作之后序列的最大值和最小值的极差,要使极差最小
核心思路:
二分答案
我们并不知道最小的极差具体是多少,但是我们知道极差的范围是</description><pubDate>Mon, 08 Dec 2025 04:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;今日学习记录&lt;a href=&quot;#今日学习记录&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. &lt;a href=&quot;https://www.luogu.com.cn/problem/P14665&quot;&gt;P14665 [KenOI 2025] 序列题 - 洛谷&lt;/a&gt;&lt;a href=&quot;#1-p14665-kenoi-2025-序列题---洛谷&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;关键词&lt;/strong&gt;：&lt;code&gt;二分答案&lt;/code&gt;
&lt;strong&gt;问题分析&lt;/strong&gt;：
给出一个序列,可对其进行区间上的加减一操作,求在进行 m 次操作之后序列的最大值和最小值的极差,要使极差最小&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心思路&lt;/strong&gt;:&lt;/p&gt;
&lt;h4&gt;二分答案&lt;a href=&quot;#二分答案&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;我们并不知道最小的极差具体是多少,但是我们知道极差的范围是 0~(max-min),先考虑枚举极差,这样效率贼低,极差是单调的,所以可以使用二分搜索来进行查找该极差,于是二分答案的第一步就迈出了
接下来就是贪心部分,这里也不好解决,在我们已知极差是多少的前提下,我们也无法判断到底加减到哪里,怎么统计次数
我们知道的极差就是最大值和最小值的差值,我们要知道数组中数据之间的差值,就要使用差分数组
还是考虑山峰模型
原数组: 1,2,3,4,5, 4, 3, 2, 2,3,4,5,  4, 3,  2, 1
差分后: 1,1,1,1,1,-1,-1,-1,0,1,1,1,-1,-1,-1,-1
遍历一遍累加的值就是该区间内的最大值和最小值的差值,那么接下来讨论怎么计数,当计数大于 m 就返回 false
可能有人纠结于怎么对数组进行实际的操作,这样的话根本无法下手,所以当差值大于给定极差时,我们之间记录超出的部分就行,我们分加减两个操作进行讨论,记录最大值(进行减操作)和最小值(进行加操作),这里最小值记录的是数组中减的部分,是负值,定义两个 ans1,ans2;因为一次操作实际上能同时完成一个加和减的操作,所以求这两个的之间的最大值
当最大值大于极差的时候,ans1 加上超出部分,最大值赋值为极差,同时这边减了,最小值也要减(作出了与加相反的操作)
当最小值(绝对值,看的是数大小)大于极差的时候,ans2 加上超出部分,赋值为极差,最大值也加
最后返回 max(ans1,ans2)&amp;lt;=m 就行了&lt;/p&gt;
&lt;p&gt;**最终代码：&lt;/p&gt;
&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;#include&lt;/span&gt;&lt;span&gt; &amp;lt;bits/stdc++.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; namespace&lt;/span&gt;&lt;span&gt; std&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#define&lt;/span&gt;&lt;span&gt; ve&lt;/span&gt;&lt;span&gt; vector&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; ll&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; long&lt;/span&gt;&lt;span&gt; long&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; ull&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; unsigned&lt;/span&gt;&lt;span&gt; long&lt;/span&gt;&lt;span&gt; long&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; sr&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; string&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; db&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; double&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; int&lt;/span&gt;&lt;span&gt; MOD&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;998244353&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; ll INF&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;18&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; int&lt;/span&gt;&lt;span&gt; DIR&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;][&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; {{&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;},{&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;},{&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;},{&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;}};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; T&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; solve&lt;/span&gt;&lt;span&gt;(){&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    int&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;cin&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ve&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span&gt;cur&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    int&lt;/span&gt;&lt;span&gt; mx &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;mn &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; INT_MAX&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    for&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;&amp;lt;=&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        cin&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt;arr&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        cur&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt; arr&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        mx &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; max&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;arr&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;span&gt;mx&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        mn &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; min&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;arr&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;span&gt;mn&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    auto&lt;/span&gt;&lt;span&gt; check &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;](&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; mid&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; -&amp;gt;&lt;/span&gt;&lt;span&gt; bool&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        int&lt;/span&gt;&lt;span&gt; nmx &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;nmn &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;ans1 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;ans2 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        for&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;&amp;lt;=&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            nmx &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; max&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;cur&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;span&gt;nmx&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;cur&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            nmn &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; min&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;cur&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;span&gt;nmn&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;cur&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            if&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;nmx&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;mid&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; ans1 &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; nmx &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; mid&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;nmn &lt;/span&gt;&lt;span&gt;-=&lt;/span&gt;&lt;span&gt; nmx &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; mid&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;nmx &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; mid&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            if&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;nmn&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;mid&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; ans2 &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt;nmn &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; mid&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;nmx &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt;nmn &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; mid&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;nmn &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt;mid&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        return&lt;/span&gt;&lt;span&gt; max&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ans1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;ans2&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&amp;lt;=&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    int&lt;/span&gt;&lt;span&gt; l &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;r &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; mx &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; mn&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    while&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt;){&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        int&lt;/span&gt;&lt;span&gt; mid &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; l&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        if&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;check&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;mid&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span&gt; r &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; mid&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        else&lt;/span&gt;&lt;span&gt; l &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; mid &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    cout&lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;signed&lt;/span&gt;&lt;span&gt; main&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ios_base&lt;/span&gt;&lt;span&gt;::&lt;/span&gt;&lt;span&gt;sync_with_stdio&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    cin&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;tie&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;nullptr&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    T &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    while&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span&gt;--&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; solve&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;学到的点&lt;/strong&gt;：
1.&lt;/p&gt;
&lt;hr /&gt;</content:encoded><category>category:笔记</category><category>tag:学习日记</category><category>tag:二分答案</category></item></channel></rss>