随笔杂谈 | 2025 新春快乐
依旧是不知不觉间,博客已经过去了千天的四分之三。在去年里博客总共更新了十七篇文章,收获了许许多多的互动,还是相当满意的。
2025 年,予我而言是人生迄今为止最为重要的一年,我也正在努力着,期待今年六月的结果如何。
每个人的一年里真的会发生很多很多事情,时间滋润着成长,不管是我还是这篇博客,亦或者我在元旦之日种下的六株向日葵。
但无论如何,祝各位新的一年巳巳如意、生活美满;多喜乐,长安宁。
健康、幸福、进步。
依旧是不知不觉间,博客已经过去了千天的四分之三。在去年里博客总共更新了十七篇文章,收获了许许多多的互动,还是相当满意的。
2025 年,予我而言是人生迄今为止最为重要的一年,我也正在努力着,期待今年六月的结果如何。
每个人的一年里真的会发生很多很多事情,时间滋润着成长,不管是我还是这篇博客,亦或者我在元旦之日种下的六株向日葵。
但无论如何,祝各位新的一年巳巳如意、生活美满;多喜乐,长安宁。
健康、幸福、进步。
作为一个高三半 AFO 选手,这次 NOIP 意味着彻底的 AFO 和全面的 whk。
中午开始停课。
教练安排我和另外一位同学在明后两天组两场模拟赛,我的题倒是提前组好了,不过感觉 A 题放了绿题会难过头,所以临时换了一题黄题。(然而 NOIP A 题蓝,哈哈)
下午帮同学证明代码正确性,然后在讨论区看到野题拉同学想了两小时,结果那个帖子被删掉了。后面在讨论区看到了你画我猜,第一次见到信息竞赛词库,挺好奇的,进去看了一下,结果一不小心玩了快两个小时,哈哈,太好玩了。
顺便也靠这个重新回忆起了许多算法,原来我三年来已经学了或者了解了这么多,十分感慨。
晚上在机房组了一场模板手速赛,基本十分顺利的写出来了。除了树状数组不小心把 $m$ 打成 $n$ 以及第一次写 $O(n)$ 建树,还有字典树的映射写挂,其他模板都一次过了。不过手速不够所以一些图论高级算法的模板没打到。
上午验了模拟赛的 C,中午开始考。然后经典赛时开始造大样例,以及赛时才验 D(本来几乎一次过的,结果因为不小心把 min 写成 max 调了好久)。
晚上给机房讲题,讲到喉咙冒烟。组比赛真的比打比赛累多了。
上午有点摸鱼,下午打同学组的模拟赛。A 因为差点没开 long long 差点见祖宗,B 是我推荐给他的题所以原了,C 是缩点板子所以二次原,D 是万恶的小木棍。
通过洛谷帖子保存站,发现前天那个帖子删之前有人回答了,并且做法大致和我想得一样。然后找到了那个你画我猜的帖子,但房间已经没了所以自己创建了一个。
和机房同学试了几个词库之后回到了 OI 词库,然后人一下子变多了起来,好玩。后面有点累了,想着等再轮到我画一次就退。结果中间有个人画了矩阵快速幂,所有人都答出来了只剩我,然后我猜了各种“矩阵优化dp”“矩阵加速递推”直到有人提示我“矩阵什么也没优化”才压着时间线答出了正确答案,他们甚至发起投票踢我,然而我是房主,乐。(伏笔)
晚上对着题解把小木棍调出来了,并且成功快速理解了那两个优化。后续接着打图论模板,除了欧拉路径有点模糊以外都很顺利的打出来了。
放学前半小时在机房里扬言要挑战 15min 敲树剖板子,结果因为太久没打所以手疏导致实际用了一倍的时常。打完之后成功过了样例,提交发现最后一个点没过。可恶,差点一次性过掉了树剖。
后面看讨论区才知道最后一个点是 hack 没对输入取模的,长记性了。
顺利起床,吃完早餐后坐校车前往考点。
在考场门外面基了某位神犇数秒,大致流程是:突然被手机贴脸->递东西->消失。
进考场,发现挡板不太行,能够清楚看到斜对角两位选手的屏幕,但看得出来主办方已经尽力遮挡了。
我们学校和另一强校交替着坐,感觉压力很大。而且复赛时候的咬笔哥这次来到了我的左侧,并且我依旧不知道他是否有第二支笔。
签字,话说今年居然不用填“我选择在 Windows 系统”,以及经典提前三分钟发密码提前三分钟收卷,到底有什么必要嘞,还导致我们开始前三分钟不能建文件夹。
看到这解压密码,感觉有点东西。莫名有点应景(指 AFO 前最后一战)
开 A,感觉有点难办。来来回回只能往贪心上想,去年的这个时候已经写完 A 了。
记得最开始写了一版贪心,但是后面发现假了,但是改一改就真了。一个半小时才敲完了,是现在主流的统计区间个数然后双指针的做法,我以为很对,结果大样例第 7 个和最后一个过不去,莫名其妙多了一点。
对着代码找不出错,想过写对拍但发现我不会暴力做法,于是只好硬着头皮去看大样例,但好在 7 是特殊性质,比较简单。
分析了 7 后手动模拟发现手算出来的就是那个错误的答案,很绝望,这可能说明我贪心假了,此时已经两个小时了,去年这时候我马上就要调出来 B 了。
想着至少能过好多个点,先去看 B 了。读完 B 感觉,完了,B 也不会,甚至不知道读没读懂。一开始以为是推出式子快速幂算就好,仔细读题之后分析了一下发现不是简单的相乘,要分情况递推。
因为感觉最后肯定是想办法压缩不确定的一段的方案计算,于是就先对 $n$ 写了个 dp。
可能是由于昨天你画我猜里矩阵快速幂给我印象很深刻,写完之后定睛一看,发现这状态转移式子长得很递推啊我啪的一下就改成了矩阵。卧槽那这不快速幂秒了吗,喜滋滋写完之后稍微一挑就过掉了大样例,芜湖。
还剩一个半小时,打算把后面两题暴力和特殊性质拼了再回去调 A。
C 题想了一会写出来一个式子,感觉是换根 dp 但我不太会,所以想着写个树形 dp 的暴力,结果写了四十分钟发现假了,只写了个链,然后菊花图的式子也假了,绷。
D 题很优雅,但是不会,看特殊性质火速打了链,但是是 $O(qn^2)$ 的暴力取 min 和 max,哈哈,炸裂。而且大样例不知道为什么会卡死,运行不了。
最后二十分钟调 A,然后这时候我终于想出来了错在没有考虑相交区间长度的限制,但是我以为这里要做决策来决定怎么分配 0 和 1 的比例,所以以为贪心假了。但是十来分钟也改不了什么了,所以写了个数学里的分层抽样一样按比例的神秘决策,结果过掉了大样例。
最后十分钟检查代码的,找到了 D 应该是导致卡死的原因,改了编译了但没测样例。最后三分钟想把 A 的 memset 改成 for 来初始化,最后勉强卡着时间改完了,能过编但是也没测。
出考场之后才回想起来 $T\le 10$,memset 根本不慢,后悔改了。然后这时候悟到了提前收卷的意义,因为这样哪怕结束后才保存的话也不会判时间无效。
考完后听到很多人说很高分,压力。在考场外地板上发现了野生零食,乐。车上吃了好多零食,得知机房其他人考的也很炸裂,悲。
晚上过掉了 B 题的自测,舒服了。
后面证出来了 A 的那个决策不重要,不影响答案,怎么选都行,于是乎就连最神秘的我的按比例选也能过掉,哈哈。
中午过掉了 A 的自测,舒服了。C 的链原来只有 4 分,好吧,合理。D 的暴力仔细一想好像其实估计没有分,悲。
最终成绩 $100+100+4+0=204\text{pts}$。
实际上在上面的内容是去年十二月初写在洛谷的,但时隔很久(次年年初)才发布。不过并不是因为不接受成绩或者 AFO 伤感之类的,只是单纯没有机会转移到博客上来。
“没有机会”指的不是没有时间,尽管我确实更多忙于文化课。也不是懒,好吧感觉确实更贴近懒。
学习 OI 三年,不长不短,按理说 AFO 之后应该需要写一篇 OI 生涯总结,也许不久就会开始写吧,虽然已经 AFO 有点久了。甚至现在的时间点,比起 AFO,可能离我高考后回归 OI 的日子还要更近。
虽然 AFO 且时隔久远,还是多多少少复盘一下。首先这次最大的失利就是我在第一题上花的时间不太合理,并且我认为其中一个细节其实是很难想清楚的,导致我考场上不能肯定我的贪心是错的。我总觉得不太签到,但毕竟竞赛不是小孩玩的游戏,有选拔的目的在的。然后第二题能够写出来,真的很有运气的因素(详见 day -1 的伏笔),否则我真的没有信心能够在考场上想出正确的做法。第三第四题一如既往地不善于写部分分导致错失一等,不过大学比赛就不需要写部分分了,哈哈。
虽然认为没有以一等作收尾有些遗憾,但是也完全能接受。三年 OI 最终至少给我带来了相当于保送中大计算机系的机会,所以也算是减少了一些心理上的压力。尽管如此,我也还想尝试一下靠文化课能否达到更高的高度,所以仍然在加油的路上。
尚有星光伴前路,心向远方更前行,以此作结。
本文原载于 reincarnatey.net,遵循 CC BY-NC-SA 4.0 协议,复制请保留原文出处。
退役前的最后一场 CSP-S。听说 kkk 今年可能不会提前公开选手代码,坏。
白天忙着组了一场模拟赛,晚上自己复习知识点。
重新理解了一下三种联通分量,然后熬夜到了两点。
组模板手速赛但是只有我打,大部分都打的很顺利。
LCA 写挂了,发现是忘记初始化 $dep_s=1$。之前也在这里挂过,当时没理解原因,这次好好想了一下发现是因为 $dep_0=0$,如果 $s$ 深度不设成 $1$ 的话就和 $0$ 点区分不开,跳的时候会跳错到 $0$。
线段树 2 写挂了,以为是懒标记的问题,调了半天,最后发现是把 add()
复制出来改成 mult()
时忘记修改函数内递归的函数名了,我说怎么退化成区间加了。其他部分都没问题,很好。
KMP 几乎不记得了,坏。重新看代码理解了一下,发现很好理解。
出发去考场。路上重新复习了一下三种联通分量和对应的 Tarjan 算法,看了一眼 Nim 游戏结论。最后就在复习数位 dp,然而直到进入考场都没完全理解。
由于准考证和行李之类的问题在考点大门和考场来回跑。
今年还是不让带零食。还有五分钟时进了考场。
位置还是在角落,斜对角就是一位特别强的学弟。
提前三分钟发卷,压缩包和 pdf 密码都一次性打对了,rp++。
敲了代码缺省,开 T1。前五分钟想复杂了,思路有些乱,想上数据结构。重新读题发现就这,很快就会了排序贪心的做法,决定先过掉 A 再开后面题。开写的时候注意到值域可以直接桶排,14:41 的时候过了所有样例。
开 T2,怎么是物理?发现超速区间很好推,显然转化成区间覆盖问题。第一问可以离线下来用前缀和来求区间内是否有摄像头,线性。第二问读完就想到了种树,给我一种按端点排序贪心很对的感觉,但是不太敢写。
想了二十分钟,第二问还是不知道怎么做,遂跳至 T3。读完题很有思路,马上就想到了 $dp_i$ 可以分成 $dp_{lst_i}$ 和 $[lst_i+1,i-1]$,后者用前缀和很可以维护,但唯独 $lst_i+1$ 这个点的贡献到处飞,很难搞。
想了一会不会搞这个点,但是觉得只要搞出来就可以 dp,开 T4 一眼不会,遂回到 T2。
虽然一开始贪心思路记反了,按左端点排序但是取了最右,过掉了小样例,遂开写,发现过不了第二个样例。
对样例调了一下发现贪心错了,想了一会想不到别的贪心,但发现如果按右端点排序两个样例都能过,遂改。改完之后过掉了所有样例,但发现 T 了。
于是优化掉了 vector,然后其他地方卡常了一下,同时确认了清空和边界之类的细节,大样例 1.7s 过了。此时 16:43,也就是花了两个小时。
回到 T3,然后思考了很久 $lst_i+1$ 这个点要怎么搞,甚至想过退化成记搜或者上个数据结构,想了大概半小时后灵光一闪发现了 $dp_i$ 和 $dp_{lst_i+1}$ 的结构是一样的,给状态加个不影响的条件就可以直接从 $dp_{lst_i+1}$ 转移了。
这样的话就很好写了,码码码,发现第二个样例没过,对着调了一会发现对 $dp_{i-1}$ 取 max 就能过,虽然当时不理解要如何解释,不过写上之后过掉了所有样例,此时 17:40,剩余不到 1h。
后面就很坐牢了,完全把题读懂花了一些时间,甚至不会朴素暴力,只会一个 $O(n^2logn)$ 的树上大模拟,加点时从叶子向上 vector 合并。感觉应该有很多分,遂开写。由于建树的时候写了类似动态开点线段树的写法,所以被如何计算是第几场比赛难住了好久。
最后五分钟的时候放弃了,无奈 puts("1")
。最后两分钟检查了所有文操、注释、函数返回值(高一省选的时候就因为把 void
打成了 int
又没有返回值导致那题 CE 100->0)。
最后开了 checker 确认了一遍文件名和准考证号,铃响结束。
本次比赛遇到三位莫名其妙像熟人一样跟我搭话的,以及对面的大哥全程嘴里叼着笔,也许他不止一只,以及右边的大哥总感觉经常瞅我进度,也许被我压力到了(
过程中经常观察学弟的表情,看起来很轻松,以为被单调队列了。
出去后吃了点零食重启一下脑子,回去路上晕车但是刷洛谷讨论区。貌似机房其他人没有会 C 的,希望他们也能 1= 吧,rp++。
发现全机房只有我一个人考完就返校,其他人都回去睡觉了,愤愤。
先回机房吃了点面包和酸奶垫垫肚子,发现自测快开了,然后开始默写代码和写题解。默写的过程中发现我 T2 虽然已经很小心但还是有地方没处理好边界,最后效果相当于默认 $0$ 处有摄像头,一旦有车在 $0$ 位置超速而 $0$ 位置没有摄像头,答案就错了,寄。
当晚自测结果前三题都没挂,甚至第四题出民间数据之前在洛谷上还排到了 rk3,激动。
后续在多个平台自测均为 $300\text{pts}$,第二题也过掉除了我以外的所有 hack 数据。也许是因为卡掉我的情况算非常 corner case,所以非刻意构造的话很难出现,希望 CCF 也不要卡我。
中午敲了 $400$ 下电子木鱼,结果 CCF 连续诈骗两次,然后下午一赶到机房就听到了同学的祝贺。
$100+100+100+0=300\text{pts}$,达成三年 CSP-S 都没有挂分的成就。
虽然省排有些烂,但分数还不错,第四题还是黑题,还是很满意了。
希望 NOIP 可以继续发挥好,rp++。
update:今年 GD 高中生分数线居然要 $100\text{pts}$,并且刚好 $100\text{pts}$ 的还要求初赛 $\ge 61\text{pts}$,放以前想都不敢想。虽然我的初复赛都超线很多,但是机房同学好多卡线然后因为初赛被筛掉退役了的,好可惜。
本文原载于 reincarnatey.net,遵循 CC BY-NC-SA 4.0 协议,复制请保留原文出处。
近期读了一位大佬的文章:谈谈独立博客友链 | 瓦解的生活记事,颇有感悟。
随即大改友链页面,以实现收藏和推荐的作用,你也可以访问 失迹の博客 - 链接
主要的改动点在于:
下面我会给出我的代码,并简单讲解作用。
由于我只针对我的博客,所以不保证能在其他地方使用,但思路必然可以参考。
assets\scss\custom.scss
:
//链接页面
@media (min-width: 1024px) {
.article-list--compact.links {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
background: none;
box-shadow: none;
article {
background: var(--card-background);
border: none;
box-shadow: var(--shadow-l2);
margin-bottom: 8px;
border-radius: 10px;
&:not(:nth-child(3n)) {
margin-right: 8px;
}
}
}
}
.article-list--compact.links {
margin-top: 10px;
margin-bottom: 40px;
article {
position: relative;
.badge {
position: absolute;
width: 40px;
height: 40px;
line-height: 40px;
border-radius: 100%;
bottom: 10px;
right: 10px;
padding: 0 !important;
display: block !important;
text-align: center;
font-size: 20px;
background-color: var(--card-background);
box-shadow: var(--shadow-l2);
}
}
}
.article-list--title {
color: var(--accent-color);
font-weight: 700;
font-size: 1.6rem;
margin-left: 10px;
}
具体而言,针对电脑端我们开启了三栏显示,同时增加了我们新增元素的相关样式。
当然,我们需要补充更多的数据且格式有所变化。
data\links.json
:
[
{
"title": "失迹的网站",
"links": [
{
"title": "失迹の博客",
"website": "https://blog.reincarnatey.net/",
"image": "korita.png",
"description": "猫与茶与代码与你:一位 编程 / 设计 / ACGN 爱好者的博客。"
},
...
]
}, {
"title": "博客聚合网站",
"links": [
{
"title": "开往 Travellings",
"website": "https://www.travellings.cn/",
"image": "travelling-light.png",
"description": "「开往 Travellings」是一个友链接力项目,旨在通过网络跳转的方式将流量引入那些鲜为人知的独立站点,从而推动网络的开放性和多元性。",
"badge": {
"icon": "🚇",
"link": "https://www.travellings.cn/go.html",
"description": "跳转到随机博客"
}
},{
"title": "中文独立博客列表",
"website": "https://github.com/timqian/chinese-independent-blogs",
"image": "",
"description": ""
},
...
]
},
...
]
layouts\page\links.html
:
{{ range $i, $category := $.Site.Data.links }}
<span class="article-list--title">{{ $category.title }}</span>
<div class="article-list--compact links">
{{ $siteResources := resources }}
{{ range $i, $link := $category.links }}
<article>
<a href="{{ $link.website }}" target="_blank" rel="noopener">
<div class="article-details">
<h2 class="article-title">
{{- $link.title -}}
</h2>
<footer class="article-time">
{{ with $link.description }}
{{ . }}
{{ else }}
{{ $link.website }}
{{ end }}
</footer>
</div>
{{ if $link.image }}
{{ $image := $siteResources.Get (delimit (slice "link-img/" $link.image) "") | resources.Fingerprint "md5" }}
{{ $imageResized := $image.Resize "120x120" }}
<div class="article-image">
<img src="{{ $imageResized.RelPermalink }}" width="{{ $imageResized.Width }}" height="{{ $imageResized.Height }}"
loading="lazy" data-key="links-{{ $link.website }}" data-hash="{{ $image.Data.Integrity }}">
</div>
{{ end }}
</a>
{{ if $link.badge }}
<a href="{{ $link.badge.link }}" target="_blank" title="{{ $link.badge.description}}" rel="noopener" class="badge">{{ $link.badge.icon }}</a>
{{ end }}
</article>
{{ end }}
</div>
{{ end }}
由于这一部分改动略大,所以直接一整段放上来了。
大致上就是改成了对应的布局。
本人 css 不好,多次请教了 ChatGLM
一些有关 css 的教程或文档
本文原载于 reincarnatey.net,遵循 CC BY-NC-SA 4.0 协议,复制请保留原文出处。
尽管官方提供的功能已经很足,但总有人会产生新的需求。
像我,这里需要使 Cloudflare 邮箱收到邮件时同时转发到数个邮箱。
官方并不提供这个功能,因此我们需要使用电子邮箱 Worker 实现。
在”电子邮件路由“页面创建一个电子邮件 Worker,写入以下代码:
export default {
async email(message, env, ctx) {
await message.forward("email@example.com");
await message.forward("email2@example2.com");
}
}
当然你还可以继续添加更多个,但理论上来说转发到的邮箱都需要在“目标地址”中经过验证。
然后在“路由规则”中添加到 Catch-all 或者某个自定义地址。
之后可以给自己发送一封邮件进行测试,可以看到邮件成功被转发到了多个邮箱。
本文原载于 reincarnatey.net,遵循 CC BY-NC-SA 4.0 协议,复制请保留原文出处。
网页成功被 Bing 搜索引擎收录,但图标却没有被收录。在 Bing 中搜索自己的网页,在网站的左侧无法显示图标,而是显示一个灰色小地球,别人的网站左侧却可以正常显示图标。
问题的原因在于,Bing 没有收录你的网站的图标。
想要 Bing 收录你的图标,首先你的网站应该有一个图标,并具备特定程度的资质。
本文章分享了我所使用并成功的方法,但我无法保证本方法是正确的收录图标的方法,也不保证本方法在未来依旧有效。
但目前除此方法之外,据说只能等待资质达到标准后 Bing 主动抓取收录图标。
这一点具体标准并不明确,可以确定的是显然你的网站需要被 Bing 收录,但若你的网站被收录的时间较长,内容较多且质量较高,相对来说我认为收录的概率会大一些。
这里放上我申请时的资质:
收录时间超过一年
超过二十篇原创文章
Bing 近半年点击次数 1.6k
由于具体标准未知,所以大家都可以尝试,欢迎在评论区分享你的资质与结果,为他人提供参考!
正确的标准依旧未知,但显然你至少需要用某种方式添加你的图标:
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico">
推荐将图标文件放置在网站根目录。
在 Bing Webmaster Tools 中点击右上角的问号,点击"必应网站管理员支持"。
进入支持页面后,点击页面下方蓝色按钮 “Raise support request”。
填写表格,网站选择你申请收录的网站,问题类型选择 “Crawling issue”,再选择 “Other”,并描述你的问题(可以按照我申请时写的 “Bing didn’t crawl my site’s icon”),最后填写验证码,点击蓝色按钮 “Get Help”。
完成提交后,你会立即收到两封邮件,分别是你提交的信息以及官方收到你的提交。
关注邮箱等待回复即可。
这里我在申请后的第三天便收到了回复:
I would like to inform you that the favicon has been updated from our end and it will take 7-8 days to reflect on the Bing search results.
表示已经成功更新我的网站图标,大约在一周后便可以在搜索引擎中看到。
然而实际上当天就已经可以在搜索引擎中看到图标了,详见 随笔杂谈 | 博客二三事。
实际需要的时间也并不确定,例如:我申请的那一天是周五,收到的那天是周一,我等待三天可能与跨了一个周末有关。目前根据评论的反馈,最快的貌似一天就收录了。
你需要的时间可能更短也可能更长,欢迎尝试后在评论区分享你收到回复的用时以供参考。
没想到困扰我这么久的方法这么轻松就解决了,以前怎么就没找到这么个入口呢,网上也搜索不到相关内容。
另外,如果你跟着我的文章进行了尝试,无论结果如何,欢迎在评论区分享你的相关情况(例如资质、用时、结果)以供更多人参考!
本文原载于 reincarnatey.net,遵循 CC BY-NC-SA 4.0 协议,复制请保留原文出处。
删除文件夹时,发现其中存在一个顽固文件,不管怎么删除都会提示”找不到该项目“,无法删除。
根据网络所见,貌似文件夹也存在这种情况。
我这里存在的问题推测是因为文件名末尾多带了一个 .
,即类似于 example.file.txt.
,正常操作是无法创建这样的文件的,貌似我这里是由于旧版本 adb 的 bug 所产生。
该文件并非无拓展名,具体肯定是属于异常情况,但这里不深究。
据说文件夹也存在这样的异常。
这里提供我试验过后的成功方法。
创建一个 del.bat
:
del /f /a /q \\?\%1
rd /s /q \\?\%1
然后将要删除的东西拖到这个批处理文件上即可。
我这里直接拖入顽固文件不起作用,但是将顽固文件所在的文件夹直接拖入就删除成功了。
如果连正常文件都无法起作用,重新创建批处理文件并将编码修改为 ANSI。
右键,选择 Winrar 的添加到压缩文件,并勾选删除源文件(或者叫”压缩后删除原来的文件“)。
我这里直接对顽固文件进行操作未能成功,没有对所在文件夹尝试过,一些网友说有用,故也记录下来。
本文原载于 reincarnatey.net,遵循 CC BY-NC-SA 4.0 协议,复制请保留原文出处。
今天是我的博客建站 555 天。近来不止博客,我的网站均发生了许多的变化以及事件,以这篇文章作简述。
这段时间里,我的博客是变化与事件最多的,其中最大的事件莫过于解决了此前博客在大陆访问一直不通畅的问题,我从 Netlify 迁移到了 Vercel。
令人感慨。
剩余的变化与事件,简而言之:
除此之外,失迹云也历经数次更新,虽然看上去变化不大,但是修复了一些较为严重的 bug。
同时,尽管我的个人主页原本在大陆的访问较为通常,不过我依旧选择从 Netlify 迁移到了 Vercel。
同时也类似于我的博客,尽力优化了 SEO,更换了 Github 链接,新增了 Robots.txt,也顺带解决了网站图标的事。
接下来一段时间内不会有新文章更新,也不会有较大的改动,大约半个月后会进行一次较集中的更新。
此后内容更新会变得较为缓慢,字数可能不长,内容可能简单,但质量不会下降(我认为的)。
按时间顺序排序。
关于第三方 Cookie 弃用(aka. 3PCD)
谷歌,你先看看自家 Analytics。
你们要不吵一架?根据官方仓库下的 issue,目前该问题谷歌内部正在商讨解决方案。
在 Cloudflare 配置里看到一个有意思的选项。
我承认我的笑点很奇怪,但是本质上为关和 I’m under attack 真的很好笑。
等博客更新以后我要写在那篇文章最开头。
困扰了我许久的网站图标不收录问题,提了个工单四天就解决了。
考虑到之前在网络上搜索不到可以参考的解决方案,之后或许会单独发一篇博客来分享我的解决方法。
写完这篇文章之后已经到第二天了,所以本文的第一句话就存在问题。
本文原载于 reincarnatey.net,遵循 CC BY-NC-SA 4.0 协议,复制请保留原文出处。
近期为我的网站进行了一次整体的升级,修复了个人主页和云盘的诸多 bug,新增了更多功能。其中包括优化 Waline 的使用,在这里记录下来以供他人参考。
这里我使用的是 Hugo 以及 stack 主题,使用其他方式的可以更多的参考 waline 的官方文档。
由于 stack 模板中所接入的 waline 版本为 V2,或者像我一样从更远古的版本就开始魔改的话引入的是 V1,因此这里我们先来迁移到 V3 版本。
直接按照官方文档中的引入方式修改代码即可,这里贴上我将 stack 模板修改后的代码。
layouts\partials\comments\provider\waline.html
:
<link rel="stylesheet" href="https://unpkg.com/@waline/client@v3/dist/waline.css"/>
<div id="waline" class="waline-container"></div>
<style>
.waline-container {
background-color: var(--card-background);
border-radius: var(--card-border-radius);
box-shadow: var(--shadow-l1);
padding: var(--card-padding);
--waline-font-size: var(--article-font-size);
}
.waline-container .wl-count {
color: var(--card-text-color-main);
}
</style>
{{- $showReaction := (default true .Params.reaction) -}}
{{- with .Site.Params.comments.waline -}}
{{- $config := dict "el" "#waline" "dark" `html[data-scheme="dark"]` -}}
{{- $replaceKeys := dict "serverurl" "serverURL" "requiredmeta" "requiredMeta" "wordlimit" "wordLimit" "pagesize" "pageSize" "imageuploader" "imageUploader" "texrenderer" "texRenderer" "commentsorting" "commentSorting" "recaptchav3key" "recaptchaV3Key" "turnstilekey" "turnstileKey" -}}
{{- $replaceLocaleKeys := dict "reactiontitle" "reactionTitle" "gifsearchplaceholder" "gifSearchPlaceholder" "nickerror" "nickError" "mailerror" "mailError" "wordhint" "wordHint" "cancellike" "cancelLike" "cancelreply" "cancelReply" "uploadimage" "uploadImage" -}}
{{- range $key, $val := . -}}
{{- if ne $val nil -}}
{{- $replaceKey := index $replaceKeys $key -}}
{{- $k := default $key $replaceKey -}}
{{- if eq $k "locale" -}}
{{- $locale := dict -}}
{{- range $lkey, $lval := $val -}}
{{- if ne $lval nil -}}
{{- $replaceLKey := index $replaceLocaleKeys $lkey -}}
{{- $lk := default $lkey $replaceLKey -}}
{{- $locale = merge $locale (dict $lk $lval) -}}
{{- end -}}
{{- end -}}
{{- $config = merge $config (dict $k $locale) -}}
{{- else if eq $k "reaction" -}}
{{- $config = merge $config (dict $k (cond $showReaction $val false)) -}}
{{- else -}}
{{- $config = merge $config (dict $k $val) -}}
{{- end -}}
{{- end -}}
{{- end -}}
<script type="module">
import { init } from 'https://unpkg.com/@waline/client@v3/dist/waline.js';
init({{ $config | jsonify | safeJS }});
</script>
{{- end -}}
这里我使用的 VSCode 虽然安装了 Hugo Language and Syntax Support 插件,但依旧无法正确判断 Hugo 语言语法,倒数第三行会报错,只要能正常运行即可。
另外,除了引入 V3 以外,这里也包括了 locale
大小写的修复,后文会提到,以及在 FrontMatter 中新增了一个自定义属性 reaction
,用以开关文章反应,默认为 true
。
刷新网页,如果发现评论系统右下角变成了 Powered by Waline v3.3.0 就说明升级成功了。
如果你曾经已经接入 Waline 的更多功能例如统计,那么你可能需要注意按照官方的迁移指南修改你的代码。
由于数据库与服务端分开部署,所以升级服务端理所当然无需担心会丢失数据。
在管理端 UI 界面最上方可以看到当前最新版本为 @waline/vercel@1.32.0
。
官方给的方式是将自己的 waline github 库中的 package.json
中的 @waline/vercel
版本修改为最新的即可。当然理论上来说,我们这里用的是 latest
,直接在 Vercel 控制台中重部署即可。
我这里版本差的有点多,所以选择将自己的库 pull 下来,然后替换成官方的 waline/example at main · walinejs/waline · GitHub 再 push 回去。
接着回到 Vercel 控制台,看到已经重新部署了,打开管理端也可以看到上方不再显示版本更新提示。
这里顺带一提,污染会导致墙内无法访问,进而墙内无法加载 Waline。
解决方法:自定义域名,并且 CNAME 换成 cname-china.vercel-dns.com
。
本身访问速度已经较快了,建议关掉自定义域名 Cloudflare 代理,不然会出现 Cloudflare 的代理 ip 地址。
本步骤需要修改较多的环境变量,你可以在这里查看相关的服务端环境变量配置的详细信息:服务端环境变量 | Waline。
首先需要对谷歌邮箱账号进行一些设置。
在邮箱设置的转发和 POP/IMAP 中启用 IMAP。
然后在这里生成谷歌账号的应用专用密码,复制下来一会用。
随后按照官方指南 评论通知 | Waline 配置 Vercel 上的环境变量即可:
SMTP_SERVICE
:填 Gmail
SMTP_USER
:填谷歌邮箱
SMTP_PASS
:填刚刚获取的应用专用密码,有 16 位,记得删除空格
SITE_NAME
:填博客的名字
SITE_URL
:要带 https://
,不带最后一个斜杠,例如 https://blog.reincarnatey.net
AUTHOR_EMAIL
:填自己常用的邮箱,用来接受评论通知
当然直接用谷歌邮箱发还是过于粗糙,这里希望再套上自己的 Cloudflare 邮箱实现更好的效果。这里的操作就类似于创建 Cloudflare 邮箱然后绑定到谷歌邮箱的别名上,详细可以在网络上搜索相关博客,这里只简单记录一下步骤。
在 Cloudflare 电子邮件路由设置中创建邮箱地址,需要这一步是因为待会要收一个验证邮件(当然可以像我一样设置 Catch-All 就不用这一步)
谷歌账号需要开启一些设置(例如开启双重验证)
像刚刚一样再创建一个应用专用密码
在谷歌邮箱账号设置中在账号与导入页面选择添加其他电子邮件地址
第一步名称和电子邮件地址填写你要导入的名称和电子邮件地址,例如 失迹の博客
和 noreply@reincarnatey.net
,勾选作为别名
SMTP服务器
:填 smtp.gmail.com
用户名
:填你的谷歌邮箱
密码
:填刚刚获取的应用专用密码,记得删空格
别名电子邮件会收到一封邮件,完成验证
添加 Vercel 的环境变量为新的邮箱信息,与在谷歌那边填的一致即可
SENDER_NAME
:自定义发件人名字,如 失迹の博客
SENDER_EMAIL
:自定义发件地址,如 noreply@reincarnatey.net
这样就完成别名的设置了,如果要精致一点还可以为这个邮箱设置一个 gravatar。
我们发送一个回复,可以看到收到的邮件的发件人信息已经设置好了。
这里我使用的模板修改自 SaraKale’s blog,非常感谢。
效果展示:
MAIL_SUBJECT
:{{parent.nick | safe}},您在 『{{site.name | safe}}』 上的评论收到了回复
MAIL_TEMPLATE
:
<div
style="background: url(https://tva3.sinaimg.cn/large/c56b8822ly1h62npb7s1ej201y01y0lh.jpg);padding:40px 0px 20px;margin:0px;background-color:#FFCDCE;width:100%;">
<style type="text/css">
@media screen and (max-width:600px) {
.afterimg,
.beforeimg {
display: none !important
}
}
</style>
<div
style="border-radius: 10px 10px 10px 10px;font-size:14px;color: #555555;width: 530px;font-family:'Century Gothic','Trebuchet MS','Hiragino Sans GB',微软雅黑,'Microsoft Yahei',Tahoma,Helvetica,Arial,'SimSun',sans-serif;margin:50px auto;max-width:100%;background: ##ffffff;">
<img class="beforeimg" style="width:530px;height:317px;z-index:-100;pointer-events:none"
src="https://npm.elemecdn.com/hexo-butterfly-envelope/lib/before.png">
<img src="https://npm.elemecdn.com/hexo-butterfly-envelope/lib/violet.jpg"
style="width:100%;overflow:hidden;pointer-events:none;margin-top: -120px;">
<div
style="width:100%;background:#f8d1ce;color:#9d2850;background-image: -moz-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));height: 66px;background: url(https://tva2.sinaimg.cn/large/c56b8822ly1h61tb7tagcj20ii01u3yc.jpg) left top no-repeat;display: flex;justify-content: center;flex-direction: column;">
<p style="font-size:16px;font-weight: bold;text-align:center;word-break:break-all;margin:0;">
您在<a style="text-decoration:none;color: #9d2850;" href="{{site.url}}">『{{site.name |
safe}}』</a>上的留言收到一条回复</p>
</div>
<div class="formmain"
style="background:#fff;width:100%;max-width:800px;margin:auto auto;overflow:hidden;margin-bottom: -155px;">
<div style="margin:40px auto;width:90%;">
<p>😊Hi,{{parent.nick}},您曾发表的评论:</p>
<div
style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:15px;color:#555555;">
{{parent.comment | safe}}</div>
<p><strong>{{self.nick}}</strong> 回复您:</p>
<div
style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:15px;color:#555555;">
{{self.comment | safe}}</div>
<p><a style="text-decoration:none; color:#cf5c83" href="{{site.postUrl}}" target="_blank"> 查看回复的完整內容
</a>,欢迎再次访问<a style="text-decoration:none; color:#cf5c83" href="{{site.url}}" target="_blank">
{{site.name}} </a>。
<hr />
<p style="font-size:14px;color:#b7adad;text-align:center;position: relative;z-index: 99;">
本邮件为系统自动发送,请勿直接回复邮件哦,可到博文内容回复。<br />{{site.url}}</p>
</p>
<img src="https://npm.elemecdn.com/hexo-butterfly-envelope/lib/line.png"
style="width:100%;margin:25px auto 5px auto;display:block;pointer-events:none">
<p class="bottomhr" style="font-size:12px;text-align:center;color:#999">© 失迹の博客</p>
</div>
</div>
<img class="afterimg" style="width:535px;height:317px;z-index:100;margin-left: -3px;"
src="https://npm.elemecdn.com/hexo-butterfly-envelope/lib/after.png">
</div>
</div>
MAIL_SUBJECT_ADMIN
:您有一条新的评论
MAIL_TEMPLATE_ADMIN
:
<div
style="background: url(https://tva3.sinaimg.cn/large/c56b8822ly1h62npb7s1ej201y01y0lh.jpg);padding:40px 0px 20px;margin:0px;background-color:#FFCDCE; width:100%;">
<style type="text/css">
@media screen and (max-width:600px) {
.afterimg,
.beforeimg {
display: none !important
}
}
</style>
<div
style="border-radius: 10px 10px 10px 10px;font-size:14px;color:#555555;width: 530px;font-family:'Century Gothic','Trebuchet MS','Hiragino Sans GB',微软雅黑,'Microsoft Yahei',Tahoma,Helvetica,Arial,'SimSun',sans-serif;margin:50px auto;max-width:100%;background: ##ffffff;">
<img class="beforeimg" style="width:530px;height:317px;pointer-events:none"
src="https://npm.elemecdn.com/hexo-butterfly-envelope/lib/before.png">
<img src="https://npm.elemecdn.com/hexo-butterfly-envelope/lib/violet.jpg"
style="width:100%;overflow:hidden;pointer-events:none;margin-top: -120px;">
<div
style="width:100%;background:#f8d1ce;color:#9d2850;background-image: -moz-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));height: 66px;background: url(https://tva2.sinaimg.cn/large/c56b8822ly1h61tb7tagcj20ii01u3yc.jpg) left top no-repeat;display: flex;justify-content: center;flex-direction: column;">
<p style="font-size:16px;font-weight: bold;text-align:center;word-break:break-all;margin:0;">
您在 <a style="text-decoration:none;color:#9d2850;" href="{{site.url}}" target="_blank">{{site.name}}</a>
上的文章有了新的评论</p>
</div>
<div class="formmain"
style="background:#fff;width:100%;max-width:800px;margin:auto auto;overflow:hidden;margin-bottom:-155px;z-index:100;">
<div style="margin:40px auto;width:90%;">
<p><strong>{{self.nick}}</strong> 发表了评论:</p>
<div
style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:15px;color:#555555;">
{{self.comment | safe}}</div>
<p style="text-align:center;position: relative;z-index: 99;"><a
style="text-decoration:none;color:#cf5c83" href="{{site.postUrl}}" target="_blank">查看回复的完整內容</a>
</p>
<img src="https://npm.elemecdn.com/hexo-butterfly-envelope/lib/line.png"
style="width:100%;margin:25px auto 5px auto;display:block;pointer-events:none">
<p class="bottomhr" style="font-size:12px;text-align:center;color:#999">© 失迹の博客</p>
</div>
</div>
<img class="afterimg" style="width:535px;height:317px;margin-left:-3px;"
src="https://npm.elemecdn.com/hexo-butterfly-envelope/lib/after.png">
</div>
</div>
直接在 Vercel 设置环境变量即可,大胆复制进去。注意如果选择压行的话会丢掉一部分空格,需要手动补上否则不美观。
可以在官方文档 组件属性 | Waline 中查看。
放上这里我的配置:
waline:
serverURL: https://waline.reincarnatey.net/
lang: zh-CN
search: false
pageview: true
comment: true
emoji:
- https://npm.elemecdn.com/@waline/emojis@1.1.0/bmoji
- https://npm.elemecdn.com/@waline/emojis@1.1.0/bilibili
- https://npm.elemecdn.com/@waline/emojis@1.1.0/weibo
reaction:
- https://npm.elemecdn.com/@waline/emojis@1.1.0/bilibili/bb_heart_eyes.png
- https://npm.elemecdn.com/@waline/emojis@1.1.0/bilibili/bb_thumbsup.png
- https://npm.elemecdn.com/@waline/emojis@1.1.0/bilibili/bb_zhoumei.png
- https://npm.elemecdn.com/@waline/emojis@1.1.0/bilibili/bb_grievance.png
- https://npm.elemecdn.com/@waline/emojis@1.1.0/bilibili/bb_dizzy_face.png
- https://npm.elemecdn.com/@waline/emojis@1.1.0/bilibili/bb_slap.png
requiredMeta:
- nick
locale:
admin: 站长
sofa: 还没有人评论哦!快来抢沙发吧~
placeholder: 欢迎留下宝贵的评论!请留下正确的邮箱以便有回复时进行邮箱提醒,请勿发布任何与本文章无关的内容。
reactionTitle: 这篇文章对你有帮助吗?
reaction0: 非常有用
reaction1: 有帮助
reaction2: 一般
reaction3: 无帮助
reaction4: 看不懂
reaction5: 有错误
需要注意的是由于 yaml
读取为统一小写,而 Waline 的配置又大小写敏感,所以需要专门的步骤将大小写转换。
我在前文提供的 layouts\partials\comments\provider\waline.html
已包含了基本配置以及 locale
配置的大小写修复,其他配置同理。同时也包含新增了一个文章 FrontMatter 属性用以控制是否显示文章反应:reaction: true
。
在 config.yaml
的 waline
配置中将 pageview
与 comment
都设置为 true
。
并且修改 layouts\partials\article\components\details.html
,将末尾的 <footer>
中的内容修改为:
<footer class="article-time">
{{ if not .Date.IsZero }}
<div>
{{ partial "helper/icon" "date" }}
<time class="article-time--published">
{{- .Date.Format (or .Site.Params.dateFormat.published "Jan 02, 2006") -}}
</time>
</div>
{{ end }}
{{ if .Site.Params.article.readingTime }}
<div>
{{ partial "helper/icon" "clock" }}
<time class="article-words">
{{ $fixedWordCount := add .WordCount 224}}
约{{ div $fixedWordCount 225 }}分钟,共{{ .WordCount }}字
</time>
</div>
{{ end }}
<div>
{{ partial "helper/icon" "view" }}
<time class="article-pageview">
<span class="waline-pageview-count" data-path="{{.RelPermalink}}">0</span> 次浏览
</time>
</div>
<div>
{{ partial "helper/icon" "comment" }}
<time class="article-comment">
<span class="waline-comment-count" data-path="{{.RelPermalink}}">0</span> 条评论
</time>
</div>
</footer>
另外虽然有提供 .ReadingTime
变量以供估算阅读时长,但官方设置的速度或许是基于英文的,个人感觉误差较大。所以这里根据网络上的数据,成人每分钟阅读约 200-250 字进行向上取整估算。
至于图标,按照这里所使用的方式下载对应的图标 view.svg
和 comment.svg
,并修改成适配暗黑模式后,扔到 \assets\icons
下即可。
由于文章页会直接引入完整的 Waline,所以不需要额外的引入了。可以看到在文章页面已经可以正常显示修改的内容了。
这里希望在所有页面的页脚展示主页的浏览量。
由于除了文章以外的页面不会引入浏览量统计,所以这里需要额外引入,在 layouts\partials\footer\footer.html
的 <footer>
内添加:
<script type="module">
import { pageviewCount } from 'https://unpkg.com/@waline/client@v3/dist/pageview.js';
pageviewCount({
serverURL: "{{.Site.Params.comments.waline.serverURL}}"
});
</script>
然后在页脚相关代码中,你需要展示的地方添加上显示的 span
即可,例如在某个地方添加:
共 <span class="waline-pageview-count" data-path="/">0</span> 次浏览
可以看到各页面都可以成功显示首页浏览量,同时这里悄悄解决了首页中浏览量显示的问题。
这里也可以测试,首页浏览量:0
首页浏览量:<span class="waline-pageview-count" data-path="/">0</span>
由于首页不开启评论功能,而页脚中只引入了浏览量统计,所以首页文章列表中显示不了评论数。我们希望能够显示出文章列表中各文章的评论数,需要额外的方式进行引入。
在 layouts\index.html
中 </section>
后面加上:
<script type="module">
import { commentCount } from 'https://unpkg.com/@waline/client@v3/dist/comment.js';
commentCount({
serverURL: "{{.Site.Params.comments.waline.serverURL}}"
});
</script>
可以看到主页文章列表中,浏览量与回复数统计数据已经正常填充。
可以在 客户端 API | Waline 页面查看这个挂件的 API。
这里我们以侧边栏组件的形式引入这个挂件,并设计成只有首页会出现。
在 assets\scss\partials\widgets.scss
的最下方添加:
/* Recent Comment widget */
.widget.recentComment {
.recent-comment-list {
border-radius: var(--card-border-radius);
box-shadow: var(--shadow-l1);
background-color: var(--card-background);
}
.recent-comment-list-item {
display: flex;
padding: 0 1.25em;
align-items: center;
&:not(:last-of-type) {
border-bottom: 1.4px solid var(--card-separator-color);
}
}
.recent-comment-card {
flex: 1;
width: 0;
padding: 20px 10px !important;
p {
font-size: .8em;
margin-top: 3px;
margin-bottom: 0px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: var(--card-text-color-secondary);
}
}
.recent-comment-avatar {
width: 3rem;
border-radius: 50%;
}
.recent-comment-nick {
font-size: .875em;
color: var(--card-text-color-main);
}
.recent-comment-time {
font-size: .75em;
color: var(--card-text-color-tertiary);
}
.vemoji,
.wl-emoji {
height: 1.25em;
margin: -0.2em .1em;
}
}
创建文件 layouts\partials\widget\recent-comment.html
:
{{ if .IsHome }}
<section class="widget recentComment" hidden>
<div class="widget-icon">
{{ partial "helper/icon" "comment" }}
</div>
<h2 class="widget-title section-title">最新评论</h2>
<div class="recent-comment-list"></div>
</section>
<script type="module">
import { RecentComments } from 'https://unpkg.com/@waline/client@v3/dist/waline.js';
RecentComments({
serverURL: "{{.Site.Params.comments.waline.serverURL}}",
count: 5,
}).then((comments) => {
if (comments.comments.data.length) {
document.getElementsByClassName('recentComment')[0].removeAttribute("hidden");
document.getElementsByClassName('recent-comment-list')[0].innerHTML = comments.comments.data.map((comment) =>
`<a class="recent-comment-list-item" href="${comment.url}" target="_blank">
<img class="recent-comment-avatar" src="${comment.avatar}"/>
<div class="recent-comment-card">
<div>
<span class="recent-comment-nick">${comment.nick}</span>
<span class="recent-comment-time">${new Date(comment.time).toISOString().split('T')[0]}</span>
</div>
<p>${comment.comment.replaceAll("<br>", " ").replaceAll("\n", " ").replace(/<\/?a.*?>/g, "")}</p>
</div>
</a>`
).join('');
}
});
</script>
{{ end }}
当然我们还需要在 config.yaml
中开启这个组件:
params:
widgets:
enabled:
- recent-comment # 加上这一条
最外面那一个 if
就是用来限制只在首页出现的。这里设定成获取到数据后再显示,以及将评论内容中的链接全部去掉了,设定成展示最近的 5 条评论。
由于官方样式令人堪忧,所以这里是获取数据后自定义。关于 comment
的属性,可以在 API | Waline 中查看关于 BaseWalineResponseComment
的接口,这里简单介绍几个比较有用的:
属性 | 类型 | 含义 | 说明 |
---|---|---|---|
avatar | string | 头像链接 | |
comment | string | 评论内容 | 渲染成 html 后的 |
like | number | 评论喜欢数 | |
link | string | 用户地址 | 用户自己填写的,不建议用,避免出现乱七八糟的 backlink 和影响 SEO |
nick | string | 用户昵称 | 用户自己填写的 |
orig | string | 原始评论 | |
time | number | 评论时间 | 时间戳,单位毫秒 |
url | string | 原文章地址 |
当然,这里没有考虑到国际化的需求以及更多的可扩展性,欢迎有想法的朋友实现更高拓展性和更美观的侧边栏组件。
后续计划再更新一次,添加显示评论所在的原文章,会在之后关于侧边栏的文章中再次提及。
除此之外 Waline 还有一个 UserList 挂件,我这里并不需要,要接入的话也是类似的。
至此,我们已经捣鼓完了 Waline 大部分功能。你可以在官方手册中了解到更多的配置项以及我未提及的插件系统。
很遗憾此前我曾对模板进行过一次较大的改动,实现了例如独立出来的 Solutions 题解区以及 Algorithms 算法标签等,由于过于久远已经不记得调整内容无法写成文章,同时也因为放弃了拓展性的修改,无法合适地将我修改过后的主题开源。
当然,对博客主题的改造还远不止于此。后续的改造我也会保持记录,并发布文章,欢迎在评论区插眼或是订阅 RSS 以便关注后续更新。
有不足之处请见谅,有错误欢迎指正,也欢迎大家交换友链或是在评论区玩耍~
本文原载于 reincarnatey.net,遵循 CC BY-NC-SA 4.0 协议,复制请保留原文出处。
不知道你是否存在该问题:开启伪静态后,访问文件时若目录或文件名带有空格则无法浏览和下载。
如果我们手动加上 /?/
则可以正确访问,那么显然这是伪静态的锅。然而以我的正则水平完全看不出我的伪静态为何有问题,遂求助网络,发现只有这篇博文中提供的伪静态文件可以解决以上问题:
AddDefaultCharset utf-8
Options +FollowSymLinks
IndexIgnore */*
RewriteEngine on
# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward it to index.php
RewriteRule . index.php
很神奇,以我的正则水平实在看不懂为何这是有效的,但正所谓能跑就行。
最近我的盘又出问题了,发现输出了一堆错误,所以这里总结了一下自从升级到 PHP8.2 后遇到的错误时能参考的博客:
总而言之,不需要改动过多代码,只需要在报错的地方删除或者加上一些 isset
即可。但尤其需要注意部分 if
中 isset
的逻辑,避免产生漏洞。
本文原载于 reincarnatey.net,遵循 CC BY-NC-SA 4.0 协议,复制请保留原文出处。
相信各位一定搜到过许多方法,什么移动到 Win32 、修改 apache 加载、手动安装 curl 什么的。
由于我并非专业后端开发,只是想跑一跑代码,因此并没有安装 apache,这时候如何为 PHP 开启 curl 拓展呢。
首先修改 php.ini
,将 extension=curl
前面的分号去掉。
但是在 cmd 中输入 php -i
还是看不到开启了 curl 扩展,运行代码还会有以下报错信息:
Warning: PHP Startup: Unable to load dynamic library 'curl' (tried: C:\php\ext\curl (找不到指定的模块。), C:\php\ext\php_curl.dll (找不到指定的模块。)) in Unknown on line 0
注意到报错信息里的拓展位置不对,我这里 PHP 根目录明明是在 D:\PHP8.2
,因而找到解决办法。
修改 php.ini
的这一条配置:
extension_dir = "D:\PHP8.2\ext"
再次查看 phpinfo,可以看到成功开启 curl 拓展,正常运行。
网上搜了一堆,甚至问过 Copilot,没一个有用的。
本文原载于 reincarnatey.net,遵循 CC BY-NC-SA 4.0 协议,复制请保留原文出处。
已将研究成果整合至文档: QQDecrypt:QQ 聊天数据库解密。
不管是出于希望将聊天记录保存到本地,还是需要导出和将聊天记录用于语言模型训练等用途,都需要导出 QQ 聊天记录这一步。
近期发现 QQNT 也存在导出聊天记录的方法,遂进行尝试和记录,感谢各位前辈的探索和作出的贡献。
我的环境是 Windows10,QQNT 9.9.11-24568,Python 3.10.6。
需要任意一款反编译软件,以及用于查看数据库的 DB Browser for SQLite(安装包来自网络,可从参考文献第一条中获取链接)。
操作的所有文件建议在操作前进行备份。
由于本人不会逆向,是按照参考文献第一条中的记录进行操作,故在此不重复记录。
需要注意的是附加到的进程是从上往下的第一个,与参考博客中的描述并不一致,也许不同设备会有不同。
如果进程选择正确,在附加后需要一定时间加载,且过程中有弹出窗口,并在 F9 继续运行之前无法使用 QQ,并在登录后触发断点。如果进程选择错误则以上会有不同,关掉 QQ 重新附加即可。
依旧按照参考文献第一条中的记录进行操作,不重复记录。
其中 nt_msg.header.txt
使用文本编辑器打开后可以在文件开头看到 SQLite header 3
以及 QQ_NT DB
、HMAC_SHA1
等字样。亲测使用笔记本打开会显示乱码,而使用 VS Code 打开没有问题。
在 DB Browser for SQLite 中,打开菜单->工具->设置加密,不输入密码直接点击 OK 以解除数据库加密。
以私聊数据表 c2c_msg_table
为例,这里介绍一部分关键数据。
列名 | 类型 | 含义 | 说明 |
---|---|---|---|
40050 | int | 发送时间 | 单位为秒的时间戳 |
40058 | int | 发送时间 | 单位为秒的时间戳,精确到天 |
40030 | int | 私聊对象 | 对方 QQ 号(无论是对方还是自己发送的消息) |
40033 | int | 消息发送者 | 发送者的 QQ 号 |
40093 | str | 消息发送者 | QQ 昵称或是备注名 |
40800 | protobuf | 消息内容 | 格式较为复杂,可使用 CyberChef 工具进行解析 |
关于 40800 的解析,由于较复杂所以不展开。
至此,已可以使用 sql 命令或编写程序导出数据。
本文原载于 reincarnatey.net,遵循 CC BY-NC-SA 4.0 协议,复制请保留原文出处。
题目太面向对象了,打了一坨。
复赛题面就是一坨,题也是一坨,打了一坨。
你说得对,A 题是小学奥数题,但是我已经是高中生了,所以卡了半个多小时才想出来样例二。没想出来的时候写了个 dfs 验证一下,想出来之后感觉不会写索性就先交 dfs 后面再回来推逻辑了。但是没给数据范围,什么情况。
开 B,一眼 next_permutation 暴力,仔细算了算复杂度发现暴力变成正解了,随便写写就过掉了。
开 C,读题目挺简单的,一看样例发现看不懂,这和题目说的是一道题吗?遂不可以总司令跳过。
开 D,前面一堆废话,其实最后一句话就把题目说完了。刚准备开敲快速幂,一琢磨数据规模发现原来是高精度,遂转 py 打表。写了个 py 计算答案,再写了个 cpp 用快读的方式读入答案并把长度与前一百位打成表,于是本题 $O(1)$。然而悲催的是由于开题比较晚所以打表比较晚,数据范围是三万但是我 py 跑到一万九就差不多速度很慢了,然后我抽了一不小心关掉了输出没保存,于是重跑打表,只来得及跑到三千,遂只打了三千的表,亏爆。
赛后发现 B 题原来给的那个数字就是 $n$,服了,没说清楚,而且经同学暴力检验发现只要 $n\gt3$ 那么答案就只有 $4$ 和 $9$,$n\le3$ 就输出 $0$,不可以总司令在本题输给了输出样例。
唯一值得夸奖的比赛体验就是居家比赛,自家电脑上的 IDE 随便用。
结果:66 分(换算成 400 分制就是 264 分),喜提一等。
8 月 2 号的时候想看证书发现晋级了,啊?思考了一会要不要去,毕竟又远又耽误课还不报销。
没想到就我这么烂的成绩也能进决赛,感慨。虽然深圳到乌镇有点远,但毕竟是全国的,难得有机会,所以还是报名了,也顺便去杭州和乌镇玩一玩。
关于旅游的部分,在这篇文章可以看到一些记录以及照片,本文章只记录有关比赛的内容。
中午从宝安机场起飞,下午到萧山机场。然后坐了两个小时车到乌镇,等到了民宿之后已经是晚上了,所以在附近吃了个饭,然后在附近逛了逛,今天就结束了。
其实原定是一早起飞,然后下午到了还能去签到的,但临时有事所以改到中午了。
签到。
但由于原定昨天签到改成了今天,忘了签到地点有不同,因此一开始走错了地,看到那边大场馆已经在比赛了,还以为我们这项也是像 NOI 一样一大群人在大场馆比。
签到时使用的是二维码,然后发了一个包,包里有手册、比赛衣服以及参赛证之类的,除了手册以外都有纪念意义,还是很不错的。听负责签到的人说参赛时要穿着衣服然后带参赛证。
顺带一提,由于来这边比赛的人特别特别多,而且由于大部分赛项都是面向小学生初中生的因此还会拖家带口,所以基本到哪都能看见来参加比赛的人,甚至周边的出租车司机和店家之类的全都知道比赛的事情,很神奇。
当天下午稍晚一点到了考场,距离检录结束还有十多分钟。
跟随现场志愿者前往考场,中途差点进到初中组考场,后续爬了四楼到了高中组考场。进考场发现居然只有二十个人左右,并且我是最后一个进考场的,大概是跑远路参加决赛的不多。
随便找了一个座位坐下,发现其他选手已经开始敲键盘。显示屏极其古老,是很旧的方形的那种。印象中系统貌似装的是 win10,键盘还行。
需要打开官网登录账号,遂登录,输了很多遍密码都登录失败,诧异,遂打开记事本输入好后粘贴入框,发现这个机子的键盘绑键是错位的,我按 W 会打出来 Q,按 T 会打出来 R,但数字键盘是正常的,因此输入手机号时没有发现,但密码输入框是隐藏的,因此输入密码里的字母时就错了。
诧异,遂换机位,发现这一台的键盘莫得 F12,诧异,遂换机位,成功登录。
由于不是 NOI 系列比赛,不知道文件夹规则,因此没办法提前建好文件。编译器貌似只有比较经典的 dev cpp 和 vim 那些的,因此启动 dev cpp,还是英文版的,调了一些设置,然后敲了文件缺省,等开赛。
提前五分钟告知了比赛密码,在官网进入比赛并下载试卷。读题。
A 题读完之后第一个联想到的是 K Smallest Sums,虽然实际上关联不大,但也因此马上想到了一个重要性质,给出的最小的数字一定是由最小的两个加来的,因此这里可以作为一个枚举点,确定好前两个数之后就可以根据给出的第二小的数直接确定第三个数,然后一直递推下去,有多种可能只需要搜索一下。
此时认为会做 A,于是接着读 B,读完就会了。建一个表达式树然后 dp 一下即可,极其简单。成功切题,美滋滋。遂读 C,发现见过原题,但那道原题我不会做,悲。
此时比赛正式开始,两个小时敲两个会的题和两道暴力应该问题不大吧?
问题大得很。开始写之后才发现 A 的搜索难写的离谱。想不出来如何实现,然后浪费了一个小时。没错,比赛一半的时间完完全全浪费掉了。但是 A 题还是要写的,后面又花了半小时写了降一档的 next_permutation 暴力。
还剩半个小时,本来以为 B 已经会了还是能打的出来的,但很快发现了新问题:嘶,表达式树怎么建来着?哈哈,完蛋。想了整整二十分钟,只记得和笛卡尔树差不多,要用到栈什么的,半天写不出来。
还剩不到十分钟的时候放弃,输出样例了。然后 C 写了个 map 暴力,结果样例过不去,试着调暴力也没调出来,不理解,最后改成了 set 但是没测样例。D 输出样例。
最后一分钟极速删无关文件打包改文件名然后回官网提交,巨惊险,出现提交成功的页面的时候发现时钟已经 40 分,刷新一下就显示比赛结束了。
出考场之后,天很快就黑了。
进来时来不及拍照留念,出来的时候拍了许多。然后有一位老师一直在关心“孩子都出来没有”“找到家长了没有”哈哈哈。
对自己的表现不太满意,完全没有任何发挥,甚至都不确定代码有没有提交上去。
虽然是不太重要的比赛,但毕竟全国级的赛事只打出了这样的水平,还是很丢人的。
当天晚上在酒店通过在官网上抓包,从一些请求的返回数据里面看到了自己提交的文件信息,这才确认代码成功卡着时间提交上去了,惊险,看来至少没有爆零。
以及查到了 C 的原题是可见的点,原来正解是欧拉筛求欧拉函数,幽默数论,不会。
毕竟第二天就是闭幕式和颁奖,所以理所当然第二天就出分了,具体分数很难看就不说了,总之打了一个 3=,突然有种打铜不如打铁的意味了,但丢人归丢人,但比起比赛其实这次体验更多的是出远门玩了好久,比赛带给我的遗憾情绪连那天晚上都没撑到就无影无踪了。
不过,接下来的时间会越来越快,越来越不够用,自然是不允许我再这样玩了,这篇游记也是我半周里每天的空隙敲出来的。不过我并没有感到遗憾,毕竟我一直对高考之后的事情有所期待。
我相信时机到了的时候,自然而然就该来到该有的状态,就像这篇文章就该于此停笔。
本文原载于 reincarnatey.net,遵循 CC BY-NC-SA 4.0 协议,复制请保留原文出处。
实际上已经半 AFO 三个月了,再来参加这场比赛也没什么好说的,尽力而为吧,也无需过于在意。
这段时间洛谷上做题寥寥无几,只有偶尔会出一些题,比方说给学校高一集训出题和组题,或是给区里的竞赛(貌似是给初中生考的?)供题。
更多的还是回到 whk 上了。
初赛还是比较简单的,就不细讲了,补全代码都很好懂,不过阅读题有一篇只看出来树上背包,不知道合并的什么玩意儿,另外单选貌似也有选错的。
最后出分虽然是机房第一,但还是比我预想的八九十分要低一点点。另外这次高一学弟也晋级了三个,也有几个差了一点点,相比往年我们学校的情况感觉好多,但相比这届竞赛班人数又感觉有点少。
喜提一个市1=,虽然感觉作用不大。
总的来说,抛开题目不看,这次复赛是所有比赛中最舒服的一次。不管是比赛场地、设备、比赛系统、IDE、赛时安排之类的,都是体验最好的一次。
整理了一下官网给出的考试范围和对应的模版题。居然有网络流?而且复杂树和复杂图论里面也不知道有什么…数据结构也没说清楚。
这一天光整理题单去了,好像没做题。
敲了一些图论板子,只剩下欧拉回路和联通性相关的那些没敲了。
花了好多时间把三种联通分量和对应缩点、割点割边都重新复习和理解了一遍。也许我第一次学的时候没有理解清楚,一直有点模糊,这次终于区分清楚了。然后欧拉回路也重新理解了一遍。
发现这次重写模板题,又多了好几个优化代码减少码长的地方,学 OI 两年了技术也就这样,倒是压行和偷懒越来越会了。
网络流应该不考?不看了。数据结构还挺熟练的,不看了。字符串大纲说只考基础,不看了。
因为这天本来学校需要补高考假,所以是从学校出发。考点在广州的广技师,从深圳过去需要大概两个小时。
六点起床,大概 6:20 左右一边吃着面包一边赶到了门口。高一有两个学弟没在线请假,校门口刷脸没有开门权限,走人工通道要打电话跟教练确认,搞了有一会。高二另一位同学(之前一起打 THUPC 和省选的)不知道是起晚了还是怎么,来的有点晚,打电话催了一会。六点半多一点出发了。
洛谷运势大凶。在车上看一些骗分和防挂分的博客。
到了考场之后以为不用着急进去,上个厕所回来发现人都进去了,有人提醒我们这场比赛需要签到和登录?于是赶紧进考场了。
进来发现比赛场地环境好舒服,签完到之后找到自己座位坐下,发现比赛设备居然是笔记本电脑,而且提供的 IDE 除了常见的 devC 和 VSCode 以外居然还有小熊猫!震惊。听说要登录,不知所措,遂举手询问工作人员,原来要打开桌面某个程序登录。发现居然是 java 写的,会定时发卷和自动同步文件,我去这也太牛了。
发现周围的同学可以动电脑,遂启动小熊猫开始配置,调了一下编译选项和缺省模版之类的。在桌面上发现了样例文件夹,打开来看了一眼,发现输入都好少,而且看起来没有图论和数据结构题,啊?
看大屏幕系统终端发现有同学已经同步了四题的 cpp,于是我也先把样例复制到考试文件夹,然后把四题的源代码文件和文操先弄好了。
开考前一分钟发现已经发卷了,遂打开看题面。
啊?七选五…我开的是英语卷子?
看了一会发现这不就是错排列 plus,应该可以一样的去推,遂推柿子。桌面空间有点小,草稿纸写起来不舒服,以及只给了一个小样例,离谱。
按错排列的思路推了半天发现行不通,因为递推到 $n+1$ 的时候不知道对应正确答案是否被前面选过,好像加一个状态也不行,加限制也不太行。
没什么思路,跑去看一眼其他题…发现都好难的样子,然后火速回来。推了一个 $O(n^2)$ 的式子,感觉没问题,把里面的组合数展开然后消了一下阶乘,发现如果换一个主元的话就可以把分母提出来,这样只需要算一次逆元,遂推推推。
1h 过去,推到后面想出了一个基于错排列的 $O(n)$ 式子,刚写一部分就发现不对,然后再回去看原来的式子发现也不对。遂难绷,1.5h 打完暴力,测了几个错排列的样例没问题就过了。
开 B,一开始感觉要拆位后面发现不太对。想了一会之后认定操作二是没用的,因为或运算只会把 $0$ 变成 $1$,而与运算需要的是 $0$,异或运算需要的是相同。首先显然可以异或自己,也可以把数字的任意 $0$ 取出变成 $1$ 其他变成 $0$,这样一做与运算也可以一次性变成零。然后想错了,误以为先异或任意数字再与上同一个数字一定会清零,所以发现只需要找到每个函数的最小值或零点去尝试即可。所以答案只可能是 $\min{x,f_i(x),k,f_i(k),2min,2f_i(min)}$,读入每个函数的时候检验一下就好了。
后来发现不对,先异或再与也不一定会变成零。但是发现答案不超过 $2$,因为要么直接与 $1$ 可以变成 $0$,要么先异或再与也可以变成 $0$,因此答案最大为 $2$,所以只需要考虑一下什么情况可能会取到更小的答案就好了。
如果函数 $\Delta\ge0$,那么最小值才有可能可以取到 $0$,否则由于 $a,b,c$ 都是整数,所以该函数的每个整数坐标点都是经过格点的,那么就最低会取到 $1$。
所以这里继续猜测,答案只会从取最小值和取 $1$ 中选?于是火速开写,过掉了所有样例,但是没有任何证明,也没有对拍。但是只有十多分钟了,后面的暴力有些紧张。
火速看完 C 然后开码暴力,谢谢你 next permutation
。
最后五分钟开 D,读题好像是 KMP,坏了,暴力都写不出来。虽然可以暴力真的拼好之后用 find
计数,不过来不及了,遂输出样例跑路。
最后一分钟检查了一下四份代码,遗憾退场。
发现大家都考的挺炸裂,不过高一成绩都比我想的要好吗,感觉他们其实剩下打满暴力的话分应该比我高。
赛后在校门口找了一家沙县小吃吃了午饭,然后想了一下发现 D 是不是跑两次 KMP 就可以了。然而给的考试范围里面没提会有字符串高级算法,所以没复习 KMP,虽然原理很理解,但细节不太熟悉,感觉就算时间充裕也没办法裸写出来,就是有点可惜暴力分,无所谓了。
ABC 出场后也没有思路,C 的话具体应该要看给的那个函数来贪心或者 dp?
洛谷的大凶说的确实没错,可恶。
本文原载于 reincarnatey.net,遵循 CC BY-NC-SA 4.0 协议,复制请保留原文出处。
最近想要在某个视频查找一些 2020 年的弹幕,发现在 2024 的当今通过官方弹幕列表查询最早只能到 2021 年的了。
然而测试了一下拉取弹幕数据的 api,2021 年以前的弹幕都还有保存,也可以拉取到数据,因此只需要前端绕开时间限制即可。
在 b 站对应视频页面点击”展开弹幕列表“,点击下方的”查看历史弹幕“,在日历中翻到一个亮着的可以点的日期。
接着 F12 打开开发者工具,找到那个日期对应的按钮的 html 代码,其 data-timestamp
这个属性里的值就是对应的时间戳(单位为秒),换成自己要查询的时间戳,然后点击修改后的日期即可。
本文原载于 reincarnatey.net,遵循 CC BY-NC-SA 4.0 协议,复制请保留原文出处。
闲来无事,注意到了七八年前使用过的旧手机,希望查看上面曾经的 QQ 聊天记录。
然而手机十分老,QQ 版本也很老。手机上的 QQ 因版本过久无法打开,但更新到最新版也因为手机版本过低无法安装。总而言之,这个手机不可能打得开 QQ 了。
网上聊天记录导出方法有许多种,然而我这旧手机不能 ROOT,自带的备份软件备份不了 QQ,会提示权限错误。捣鼓了半天没有可行方法,可谓是山重水复疑无路。
所幸找到了这篇文章,其中提到的第四种方法,尝试过后成功导出记录。
但有必要事先说明:不清楚是我的设备的问题还是方法本身的问题,总之虽然成功导出但只有一部分,并没有达成符合预期的效果,但至少看到了以前的部分聊天记录还是颇为欣慰,毕竟也只剩下这一个办法了。
当然其实后面又想到了别的方法,可能会有更好的效果,后文会提到。
手机 Android 版本为 4.3,内存空间寥寥无几,系统过旧无法安装新版 QQ,未解锁 OEM,无法 ROOT,可以开启开发者模式使用 adb 调试。手机上安装有远古版本 QQ,也无法使用。手机自带备份软件,但无法备份 QQ,会显示权限错误。
由于资源比较难找,这里我将导出过程中我所使用的工具打包分享,均来自于网络,不一定适合所有情况。
旧版(非 QQNT 版本)QQ 的聊天记录相关文件主要存储于
/data/data/com.tencent.mobileqq/
下的 databases/<QQ号>.db
,databases/slowtable_<QQ号>.db
以及 files/kc
,只需要获取到这三个文件我们就可以导出基本的聊天消息文字记录,更多的图片、语音等也在该目录下可导出。
获取该文件一般需要 ROOT,因此这里我们只能使用别的方式,我们可以利用 adb 的备份功能将该文件提出出来。
首先手机开启开发者模式,允许 usb 调试,然后连接 adb。
在 AndroidManifest.xml
中有一个参数为 allowBackup
,表示该软件是否允许使用 adb 备份。尽管我手机上已经是七八年前的版本,但该属性已设置为 false
,但好在发现 QQ 更远古的版本中该属性还是 true
,因此这里我们需要保留数据卸载并安装允许备份的版本。
保留数据卸载:
adb uninstall -k com.tencent.mobileqq
安装允许备份的旧版后,进行备份:
adb backup com.tencent.mobileqq
备份时需要在手机上点击同意,备份可能需要一些时间,会在当前目录下生成一个扩展名为 .ab
的备份文件。
如果备份文件只有 1kb 那就是失败了,可能是软件版本不对或 adb 与设备 Android 版本不对应。旧版 Android 不兼容高版本 adb,我这里 4.3 使用 1.0.32 版本的 adb 是可以的。
提取出数据后,我们这里使用 android-backup-extractor 从.ab
中提取文件:
java -jar abe.jar unpack backup.ab backup.tar
之后直接解压即可。
这里使用的是 QQ-History-Backup 这个库。
在导出的文件夹里找出我们需要的文件之后,放入对应的文件夹内,接着按照教程使用该工具导出即可。
在备份完之后,.ab
文件其实也可以使用 adb 将其恢复到其他设备上(例如模拟器)。
我们可以选择在新设备上将 QQ 更新到最新版尝试打开,也可以从可以 root 的新设备上更方便的直接拿到我们需要的文件。
这两种方法我都没有试过,或许效果比我更好。
GitHub - QQBackup/QQ-History-Backup: 【停更】QQ/TIM 聊天记录导出为 HTML,支持图片、语音,可 GUI 与 非 GUI 操作 (Python)
GitHub - nelenkov/android-backup-extractor: Android backup extractor
本文原载于 reincarnatey.net,遵循 CC BY-NC-SA 4.0 协议,复制请保留原文出处。
第二次省选了,这次的心态又与去年有所不同。
一来是因为,NOIP 成绩并不优秀,不抱希望,也就没有压力。二来是因为,很久没有碰 OI 了,自 THUPC 后还是会来机房,但是来机房基本只是找机会跟女朋友聊天和看着和她的聊天记录发呆,顺便补补文化课。
毕竟实力就在这个地方了。如果我 NOIP 后继续停课到现在,进队的概率或许还能看得见,但我最好最好也就是打个 Ag 潦草收场,然后去跟本来就能裸分的大佬抢清北羟基。什么啊。
去年参加省选时也没多大希望,高一嘛来试试水,本来想着还是高二冲队,谁知道 NOIP 后半场一败涂地直接退役。
但不管怎么说,这次比赛也宣告了我本赛季的结束,姑且是写了游记。下一次重新面对 OI,应该是年底了,届时是真的退役赛了。
另外,其实去年参加时也写了游记,但并未公开,本次一并附在附录中。
考前一周才想起来三月初要打省选。
谁爱打谁打。
什么,还要占我一个周末?去你的吧。
什么,可以提前一天回家?我马上来。
本来打算 day0 早上回家,但是 day-1 是我可爱的女朋友的生日,所以特意提前到 day-1 晚上就回去了,码了好久的字然后定时发到空间了嘿嘿。
当然这一周也不是什么事都没干。day-4 vp 了 YDOI R1,打了 220 跑路了。day-3 vp 了 HBOI day1,赛时 T1 死活不知道哪里错了,只得了 50 pts,而且对的还是后半部分的点,诧异,day-1 的时候发现是最后扫一遍统计答案的时候忘记判 inf 了,改了之后一发过掉。应该算签到成功了吧。
上午没学 OI,但是和她断断续续地聊了一些。
中午吃完饭没多久就出发去考点学校了,去年在广州,有些远;今年在东莞,近了许多。先去了酒店放了行李,楼层很高,拍了很多照片。然后去了考点学校报道,领了牌子和赠品。今年怎么有赠品?去年怎么没有?去的时候考点学校的学生还在上课,哈哈。
试机的时候打了个不带懒标记的线段树,测了小数据一次过了,非常好。
之后回酒店点了晚餐,之后开始打模版手速赛。十三道模版题,前十道一路打过去基本都是一次过,最后三道是三种联通分量,忘干净了,边双点双强联通的代码全记混了,打崩溃了,遂跑路。
最后成功比室友多打了一倍的模板,拿下手速赛第一名。赛后看了以前的边双代码,把边双改出来了。点双和强联通一点都不想打,跑路。
本来想着姑且尊重一下比赛要早点睡的,没忍住,和她聊到了一点多。
早上起来还算精神。
吃了早餐,提前大概半小时赶到了考点学校。打不到车,最后加了钱才打到的。
开考提前三分钟给了解压密码,先看了数据点只看得出来有一题图论。后面发现 pdf 没密码可以直接打开,火速看题。
T1 读题:我题目背景呢?怎么全是公式?好不容易读明白题,想了一会感觉好复杂,后面套回题目背景上之后好理解多了,有了一些头绪。
毫无疑问,先翻转坐标系把目标位置整到第一象限,然后接下来大力讨论,然后写着写着发现讨论不明白。
注意到风吹和移动的顺序不重要,以及具体行动路线也不重要,在某些情况下只关心吹完风之后的位置到目标位置的曼哈顿距离,但存在特殊情况。
自然而然想到,先计算一整轮风吹下来后的情况,枚举最后一次吹风,再讨论出前面轮数,然后总天数取最小值即是答案。
对于一整轮风的情况,贪心的尽可能往目标点走,所以将所有向负方向吹的风尽可能抵消,得到了一轮下来的位移以及可以自由安排的移动距离,接下来只需要枚举后讨论。
写的时候发现讨论不出来,但可以用来 check,遂退一步,枚举后二分出总轮数。
过掉小样例,然后在第二个样例发现寄了;修修改改过掉了第二个样例,然后在大样例发现假了。遂开摆。好想她。
T2 有一些思路,感觉这个博弈是假的,二进制拆位去贪心就好了。但发现这个定向加强很不好做,遂开摆,只打了最低一档暴力和做 $m=0$ 的特殊性质分,特殊性质写了半天 01 Trie 过不去,最后全都上了暴力。好想她。
T3 不可以,总司令。检查了所有代码。好想她。
结束了,四个半小时纯坐牢。出校门的时候风很大,衣服没帽子,耳朵冻没知觉了,打到了车但是要十分钟才到,冷死我了。
缓过来之后突然发现她不对劲,还以为在学校出事了,吓死我了。终于回到酒店,本来想出去吃的,被风冻怕了不敢出门,还好酒店里全天开着暖气,这才活过来。
下午摊着了,迷迷糊糊的和她聊天,等消息的时候好像睡着了一会。中间点了个肠粉当晚餐,之后和她聊了五个多小时,这个周末最美好的一段时间。
早上六点多起来了一次,发现室友通宵了。又躺回去,好像没睡着,一直到了七点才起床。
和她聊天的中途赶到了考场,提前十五分钟进了考场等开考。
我一点都不想比赛,为什么要比这么久,好想继续和她说话。
开题。
T1 这个博弈有点意思,很显然有一个最基本的贪心。最开始的思路是,从确保 $1$ 不被选开始,尽可能让 $2,3,\cdots$ 也选不上,通过这个找到要唤醒的结点,最后搜一遍出答案。
小样例过掉,第二个样例就寄了。
好想她,我为什么在这里做题。
突然注意到题目一个要求是必须走完所有子树才能回到根节点,所以发现前面思路单纯按数字大小来贪是不对的,应该按当前能走到的最小值来贪。
想到思路了,大改特改。有点分治的想法在里面,维护了结点子树中能够到达的最小结点,然后 solve 会在当前子树中进行贪心,然后会根据决策,进入到不同的子树中去 solve。
写完之后我很满意,debug 了流程很符合我的想法,简直神来之代码。结果还是一样,只过掉了第一个样例。
好想她,我不想做题了。她今天放假,我想找她说话。
手模了第三个样例中的一个数据就发现,问题出在选取要唤醒的结点的地方。试着换了别的贪心方法也过不去,估计这个地方不是贪心而是某种规划。。寄!
我在这里比赛不如拿这个时间和她聊天多好。
最后改成了自己认为正确率比较高的决策方法后就润去写剩下两题暴力了。
T2 发现是我最不擅长的概率与期望之类的题目,虽然我觉得这个概率好像是假的。不管怎么样,我发现当 $n+k\le 10$ 的时候还是可以用 next_permutation 水过去的,于是火速开写。
这暴力都不简单。check 是按照约束对整块碎片建 DAG,然后跑拓扑排序来 check。然后写了个 gcd 和 qpow 完成了有理数取模。中间还记错逆元的次数了,一直写成了 $mod-1$ 次方,我说怎么 qpow 跑出来一直是 $1$。
最后是过掉了范围内的样例,剩下的部分就不可以总司令了,我相信总是会出现一个的(
好想她,为什么不能打完暴力提前交卷。
T3 逆天题面,给我看傻了。后半部分题目不是很懂,索性 puts("1")
了。
还剩下十几分钟,好无聊,好想她。
最后一次完全检查了代码没有出现去年的错误,于是开始玩起了电脑。启动了虚拟机看看,发现 vs code 不会配置,于是在终端用 gcc 编译,结果编译出来的程序无法运行。退出来研究了一下别的 ide。
终于结束了,什么都结束了。耶,终于可以和她说话啦。
比完赛马上就回去吃午饭,吃完之后收拾了东西,酒店退了房,然后就离开东莞回家了。路上因为给她发消息看手机,晕车很严重,差点没撑住。到家之后继续聊天,真好。
Day1 蓝黑黑,Day2 紫黑黑,真有你的省选联考。
没想到今年也签到失败了,太菜了,day0 打的模板一个没考到,不过无所谓。感觉最重要的是和她聊了好多,但我觉得还不够,要是假期就好了。
不过接下来还是专心 whk,恋爱脑也得收收。老婆和学校哪个重要我还是掂的清的,不能因为学习耽搁了恋爱(?)。
注:以下是去年写的,格式不好,也没用 Latex。而且当时也不敢提到女朋友的事,就单纯写了游记。现在看着蛮难受的,但总之就是一起放出来了。
虽然初三暑假才开始学的算法,但我对自己还是挺有信心的,基本上算法我是不会写错的(但是题目会不会做就是另一码事了),所以一上午在学校机房里就只是简单的看了下各种数据结构的代码后就继续学新东西。看了b站上关于计算几何的一些视频,向量、凸包、旋转卡壳、最近点对、随机增量之类的,除了随机增量以外基本都很简单很好理解。下午就坐了两个半钟的车到省会,先去酒店放好行李然后就去考点了。
结果走错门了,门口一大群家长,然而当时我还没发现,因为看到了好几个学生,估计他们也是打车打错了。好在当时周五下午,等了一会正好考点学校放学,学校大门开了,我就随着那些家长一起进去了。虽然因为走错门所以完全看不懂地图,不过看路标还是找到了报到的地方。因为弱校校队只有我有省选资格,所以教练也没跟着来,于是报到处的老师直接把整个文件袋都给我了,里面除了我的胸牌还有教练的胸牌和文件之类的,打算回学校后拿给他。听到对其他学生说有饭票,考完可以在考点学校的食堂吃,发现自己没有,或许是需要学校提前订吧,感到有些悲哀。
然后就回酒店了,复习主要是看了一下比较容易混淆的一群Tarjan算法还有突然想不起来和spfa有啥差别的dijkstra。然后就学了一下新的东西,比如爬山和模拟退火,还有一些乱搞(骗分但不完全骗分)。
昨晚没睡好,悲。但还好比较精神,可能我本来在学校就天天凌晨睡,所以没太在意。早上吃完早餐就直接去考点了,结果走到昨天那个门这时候才发现走错了,不过时间很充裕,后面又坐车坐到了正确的门。在考场门口又看了下昨晚的模拟退火,总感觉能用上。进去后就看注意事项然后等开考,旁边的哥们在趴下休息,我由于第一次参加省选,格外的精神。想着D1能不能切一题暴俩题拿个200。输完神奇的压缩包密码和pdf密码后,一看目录感觉T3名字眼熟,多半是图论。
T1看完之后有点不是很明白,就看了看T2,一眼DCC,但是对于是边双还是点双有点不确定,但是能确定最后缩完应该是棵树。一看对大数取模就知道这题凉了,因为我对于这种树上dp+大方案+容斥很不会,虽然前不久才做过一道,于是就赶紧回T1了。第一眼觉得跟差分有关,但是试了试没推出来结论,所以最后选了线段树维护并查集。写+调一直到了十一点,不过由于已经放弃T2了,所以压力不是很大。最后大样例跑的飞快,写出来的那一刻还是挺高兴的。之后T2再看一眼发现还是不会于是赶紧跳T3,想着剩下差不多两个小时打个暴力四十分,D1就算圆满收官。一看题目,发现挺像之前做过的一道模拟费用流,但是又感觉很不一样。题目看到一半的时候想到刚学的模拟退火,感觉很能做,每次随机让某位员工往下走,结果往后一看发现居然是动态的,心里偷偷竖中指。于是只好敲暴力,结果发现数组开不了那么大,无奈只能放弃66666的点,最后小样例跑的飞快,大样例直接爆数组RE,D1到此结束。
中午吃过饭后就一直待在酒店里看电脑,翻了翻wiki感觉没啥想学的,会的懒得看,不会的看不懂,于是就一直在洛谷讨论区里翻来翻去看大家“关于省选”。然后发现了好多和自己做法一样的,发现T1正解居然只是道贪心,估计我最近数据结构写多了,后来发现确实有差分的做法但很容易挂。然后下午就出代码了,发现我竟然手误给几个没有返回值的方法写了返回类型,寄,T1爆零了估计。没有拿noilinux虚拟机编译一次,不然估计不会有这个问题,确实可惜,但我确实怎么也想不到居然我真的会写出这种低级错误,还是在考场上,幸好我本来就是来试试水,没打算冲队,压力没那么大。
晚上突然在b站刷到了用DQN训练只狼AI的视频,点进去就出不来了。估计因为我学AI的时间是我学OI的时间的好几倍吧,我感觉炼丹才更像是我的主业,OI只是感兴趣?不过前几年就在书的尾页中看到过DQN的介绍,对这一种直接输入屏幕图像的训练方式特别感兴趣,当时还跟朋友说打算用DQN训练某个我很喜欢玩的小众游戏的AI,结果后面找了发现DQN的资料实在太少,而且网上实现的DQN玩的基本都是叫A什么的某种很古早的只有几百个像素的电子游戏,所以最后放弃了,结果这时候突然发现有大佬用DQN实现玩现代游戏,还开源了出了教程,真的很震惊,于是就乐呼呼的看到了晚上都没碰OI。
D1理想分,100+0+48,实际估分0+0+40左右(T1其实洛谷能编译而且打了90,但CCF测评机应该是会CE的),目前民间0+0+30左右。虽然我会说没爆零就是胜利,但实际上我估计会等官方数据出来以后在洛谷交一次T1,再把T1分加回去当做我的非官方成绩,毕竟不是很在意官方排名,只是想看看自己能打成啥样。
昨晚睡得还不错,而且这次没走错门。来到考场门口听见有同学说D2肯定有计算几何,我心里偷偷一笑然后赶紧复习计算几何,顺便看了眼模拟退火,然而结果没有考到。进了考场以后隔壁的哥们又在趴下休息,我还是格外的精神。开考念密码,跟昨天的反过来,哈哈。
一看目录,看到game就感觉要来博弈论了,但是我不急,先看T1,发现好像又是大模拟博弈论,寄。当时感觉有点像启发式搜索,但又想不出来怎么写启发函数,考虑他一个网格地图感觉会跟曼哈顿距离有点联系,一看样例又看不懂了,我手推都不知道样例答案怎么来的,想不明白为什么另一颗被困住的红棋也会移动(还没看题解,不过此时写这篇游记的时候我突然有点想法,感觉黑方的启发函数应该是棋子到第一行的距离+两颗红方棋子到黑方的曼哈顿距离, 红方可能是棋子到黑方的曼哈顿距离的相反数?这么一来确实能解决我那个疑惑。显然不是IDA*,那么肯定是A*,并且可以用记忆化搜索标记一下状态来判平局,欸卧槽好像感觉突然会了)。看到输入里面有数据编号就感觉有好事,火速看数据范围,嘶……显然,像我这种考场上没想出的正解的蒟蒻,肯定是针对每一种数据去写暴力啦,看到特殊性质A送分,我就直接跳到T2去了,打算最后一小时再回来写T1。
看到T2,果然是博弈论(至少当时我是真的以为是博弈论)。一上来先输入的时候判断一下能不能满足B互不相同,然后提前计算一部分已经确定的答案然后剔除出去。那么就剩下最后一部分了,都是B有俩选择的,这时候就感觉有点像动态规划,但是想了半天,不会表示状态。好吧,老实暴力。然后,直接敲了个2^n的dfs+回溯和剪枝出答案,测第一个样例过了,测第二个发现直接就寄了。然后死活想不明白为什么暴力都写错了,一直调一直改,差不多到十点的时候我就怀疑是我关于A的部分有问题,于是就转而投靠刚学几天的模拟退火,在A的有的选的部分中随机一个换,然后再对B暴力求答案,结果调半天还是错(现在看来,感觉是前面那一段剔除确定部分的地方出了问题。。),直到快十二点,赶紧看眼T3看看能不能骗分,发现样例好多1而且只对第一问也有分,就写了个输出1和一个随机数,然后回到T1写暴力。发现暴力不会写,只有性质A比较稳,后面的BCD好像都有乱写的成分在的,然后D2到此结束,我的第一次省选也结束了。
看洛谷有大佬评价说D2确实很难,而且T2好像不是博弈论,性质A是匈牙利、C是费用流,但我考场上确实没看出来,而且暴力也写挂了,只能说D2不爆零就是胜利。
D2理想分30+5+0,实际估分20+0+0,目前民间10+0+1(T3没想到骗到了一分hhh)
总的来说,感觉确实很难,但又好像比我想象中的简单(或许是因为我压根不去考虑正解吧),这次官方分数估计就是40左右,至少对我来说已经很不错了,毕竟我才学了不到一年。不过D1T1果然还是略有点遗憾,不过当时忘记随机化了,所以不能指望官方数据全随机,可能确实会T几个点吧;D1T2这类题感觉很难但我可以掌握,再学一年的话应该能做出来,毕竟感觉这一类题都思路很明显,缩成树后dp+容斥嘛;D1T3,明年的我写的暴力估计会更优吧;D2T1出考场才想到思路,D2T2和T3相信明年的我能写出暴力。但值得庆幸的是,虽然我这次犯了很多问题,但我都找到了可以改进和避免的方法,至少下次应该不会错在同一个地方了,而我没有下下次,所以,这次确实攒下了很好的经验,值了!
最终官方成绩没到40,太难看就不说了,不过挺可惜的是后面把D1T1考场代码里手误写的的几个没有return的函数的返回值改成void之后官方数据AC了,然而实际上虽然没有CE和RE但是也没有分。
最后的最后,鼓励一下自己,顺便立个志向:数据删除(注:搬过来的时候这一段我还是删了,实际考的远达不到这个,就不放出来丢人了)
我去年写的别的游记。
本文原载于 reincarnatey.net,遵循 CC BY-NC-SA 4.0 协议,复制请保留原文出处。
因为经常需要输入英文或者关闭输入法,所以一直习惯在 Windows 里添加两种语言,然后用 Alt+Shift 切换语言,就可以很方便的打开和关闭输入法了。
当然,这里的关闭输入法实质上是切换到英文输入法。
不知道我电脑发生了什么(或许是一次自动更新),某一次开机之后我就发现我无法使用 Alt+Shift 快捷键切换语言了,而且右下角托盘的输入法设置里也无法切换成英文输入法、
我的电脑系统是 Windows 11 家庭中文版,其他的版本貌似没有出现过这个问题。
最初我发现,打开系统语言设置后将两种语言的顺序调换一下就可以恢复正常。但是开机后会被重置,需要重新进行一遍操作,而且有概率失败,需要重启电脑再试一次。
最开始我也是不厌其烦的这样做了,毕竟不能切换语言更加难受,但最近发现这样的方法失效了,按网上说着试了也不行,最后自己捣鼓出来了一个解决方法:
在系统语言设置中删除英语,然后重新安装。
成功的标志是,在系统托盘的输入法设置中,可以选择 “英语(美国) - 美式键盘” 这一项。
我使用了这个解决方法,目前没有出现问题。
网上没一个管用的,无法参考。
本文原载于 reincarnatey.net,遵循 CC BY-NC-SA 4.0 协议,复制请保留原文出处。
不知不觉间这个博客过了一年多了,迎来了第二个新年,年份归档中也终于能见到第二项。
忙于学业和 OI,这一年里我写和研究的项目越来越少,所学习的事物也越来越少。博客也更新的不多,绝大部分字数还是我的游记,中间网站甚至瘫痪了不知多久。
在这一年里,我也变化了许多,About 中记载的许多内容不再切实甚至不再有必要写下。另外我也从今年开始将按照中文符号使用规范编写文章,博客中还有很多地方使用错误或不准确(如中英文之间未加空格)的地方,会在看到的时候将其修补。
许多想法放弃的同时,也有许多新的想法出现。我会将其记录于 Plans 中,等待未来有机会将其实现。
不知道博客究竟有多少人来看过,但每次收到评论,或是出现新的 backlinks 的时候都会十分欣喜。
值得一提的是,一月初的时候给本博客抢了一个还算不错的萌备号。另外其实年初一的时候因为设备原因写不了文章,但其实文章的时间是可以修改的,是不是当天也无所谓,所以本文章其实是在初七补写的。
这个博客仍然很新,但已经有所成长。期待在新的一年里,变得更新欣欣向“龙”。
目前 MuMu 模拟器官方已在 MuMu 模拟器常见问题页面中更新了关于 MuMu12 抓包的官方教程,本文不再适用。
最近需要对软件进行抓包,但是 HttpCanary 的证书无法正常安装。按照教程点击安装,但是却弹出”未安装该证书“。这是官方的说法:
部分用户在使用MuMu模拟器X版本的过程中需要进行抓包一类的操作,但发现无法安装导入证书,无法正常抓包,这是因Android7.0之后新版本系统的安全限制导致(Android7.0 之后默认不信任用户添加到系统的CA证书)
官方给出了使用 adb 安装的方法,网络上也有一些相关博文,然而都是使用其他抓包工具,没有使用 HttpCanary 的,所以自己记录一下。
我的 MuMu 模拟器 12 的版本是 V3.6.11(2438)。
由于我过程中没有截图,所以这里只简单用文字描述一下过程,如果有疑惑的话可以查看参考文献中的相同步骤的截图。
用 adb 直接把证书移到系统证书位置 /etc/security/cacerts/
里。
打开 MuMu 模拟器设置界面。
在“磁盘”中将“磁盘共享”改为“可写系统盘”。
在“其他”中将“开启手机Root权限”选中。
当然,在完成安装流程后这些都是可以改回去的。
在 HttpCanary 设置界面中,进入"SSL 证书设置",点击“导出HttpCanary根证书”,选择“System Trusted(.0)”格式,导出证书默认就在 /HttpCanary/cert/
下,我的文件名是 87bc3517.0
。
参考文献里其他的抓包工具只能导出 .pem 格式,需要用 OpenSSL 重新签发为 .0 格式,而 HttpCanary 直接为我们提供了 .0 格式的导出,很方便,减少了很多步骤。
如果不了解或者没有 adb,可以先在其他博客中自行学习一下。
首先连接到 MuMu 模拟器并申请权限:
adb connect 127.0.0.1:7555
adb root
adb shell
其中第二步运行后,模拟器会有一个弹窗,显示“Shell 正在请求超级用户访问权限“,选择“仅此次”,点击允许。
第三步运行后,提示符会发生变化,这时候就进入 Android 的 shell 了。
将证书文件放入系统位置:
mv /sdcard/HttpCanary/cert/87bc3517.0 /etc/security/cacerts/
可以检查一下是否成功移动文件:
cd /etc/security/cacerts/
ls 87bc3517.0
确认后证书就安装完毕了,可以输入 exit
按下回车退出 shell。
这时候启动 HttpCanary 开始抓包,软件可能仍然会显示提示条,不要紧,打开软件试试,如果能抓到 Https 请求就代表证书安装成功了,可以正常抓包了。
当然,有些软件会有 root 检查,启动会闪退,你可以把 MuMu 模拟器设置修改回去,没有影响。
然而有些软件同时还有证书验证,可能开始抓包后会无法联网(没错,说的就是你,森空岛。),难绷。
写完上面一大堆之后,不知道在写博客的时候是哪里捣鼓坏了,我的抓包又变成之前那样没法抓了,但是当时刚搞完确实是可以抓的。
后面又按照 这篇博客 整了一下,效果也只持续了一下,重启模拟器之后就也不能抓了,不知道是什么鬼。
本文原载于reincarnatey.net,遵循CC BY-NC-SA 4.0协议,复制请保留原文出处。