diff --git a/404.html b/404.html new file mode 100644 index 0000000000..30219f4180 --- /dev/null +++ b/404.html @@ -0,0 +1,4195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 404 Not Found - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ +
+
+ + +

JustPureH2O

+ + +

深水里摸大鱼

+ +
+ +
+ +
+ + + + + +
+ +
+
+ +
+
+ + + + + + + + + + + + +
+
+ +

QWQ 迷路了~

+

网络的尽头 虚无之地

+

[飞回母星](https://justpureh2o.cn/)

+ + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/CNAME b/CNAME new file mode 100644 index 0000000000..2ba7cb3591 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +justpureh2o.cn \ No newline at end of file diff --git a/about/index.html b/about/index.html new file mode 100644 index 0000000000..f6f1894ba8 --- /dev/null +++ b/about/index.html @@ -0,0 +1,4128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 关于我 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/archives/2023/07/index.html b/archives/2023/07/index.html new file mode 100644 index 0000000000..633bfd09ea --- /dev/null +++ b/archives/2023/07/index.html @@ -0,0 +1,4381 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档:2023/7 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ +
+
+ + +

JustPureH2O

+ + +

深水里摸大鱼

+ +
+ +
+ +
+ + + + + +
+ +
+
+ +
+ + +
+ + + + + + + + + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 本文转载自:【F444 +の 光荣历史•其二】人物传记·FRC +作者:Lucas2011 +一、简介 +曾就读于东辰「教学8班·行政11班」与我同班(两个都是哦),是我初中阶段最好的朋友。现就读于七林9班,在高中数学竞赛的道路上越走越远。喜好有Minecraft、原和一些神奇的卡牌游戏。有批判性思维,不从众,但是对自己的观点有强烈的自信,不拿出证据证明他是错的的话他绝对不会善罢甘休(但是在学校里证... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+ + + + + + +
+ + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/archives/2023/10/index.html b/archives/2023/10/index.html new file mode 100644 index 0000000000..2e478b1978 --- /dev/null +++ b/archives/2023/10/index.html @@ -0,0 +1,4523 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档:2023/10 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ +
+
+ + +

JustPureH2O

+ + +

深水里摸大鱼

+ +
+ +
+ +
+ + + + + +
+ +
+
+ +
+ + +
+ + + + + + + + + + + + + + +
+
+ + + + + + +
+ + 常用算法模板 + +
+ + + +

+ +

+ +
+ + + 1. Trie树(字典树) +123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051#include <bits/stdc++.h>#define N 10010using namespace std;int son[N][70], idx = 0, ... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 国祯文集 + +
+ + + +

+ +

+ +
+ + + 曾茂华到底有多六 +——By 国祯 +曾茂华是中国当代著名的科学家和教育家,他以“慈父”、“良师”、“学者”等称号闻名于世。 +1:曾茂华的蠢行为 +曾茂华的蠢行为: +他在大学期间参加了一个乐队,并担任主唱。然而,不幸的是,由于自己的疏忽,他犯下了一件愚蠢的事情——用刀砍掉了对方的手指头。这件事让他成了学校里的头号人物之一。从那以后,他再也不敢做任何愚蠢的事情了。这是因为他害怕自己会被开除出乐队或者... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + CSP-J 2023 游记 + +
+ + + +

+ +

+ +
+ + + 又名:《第一次考就被小学生薄纱的一集》 +本次考场:绵阳东辰国际学校 +第一节    赛前准备 +       插一句:CSP-J +2023没有设置赛前试机环节(包括CSP-S,成都绵阳都这样),个人推测可能是由于开放自选Windows和Linux系统带来的结果。如果你听见诸如:不要操作电脑,违者将作作弊处理 +的话时,请将你按捺不住的双手安稳的放在双腿上,避免出现意料之外的事来。 +       然... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+ + + + + + +
+ + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/archives/2023/11/index.html b/archives/2023/11/index.html new file mode 100644 index 0000000000..6536314626 --- /dev/null +++ b/archives/2023/11/index.html @@ -0,0 +1,4682 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档:2023/11 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ +
+
+ + +

JustPureH2O

+ + +

深水里摸大鱼

+ +
+ +
+ +
+ + + + + +
+ +
+
+ +
+ + +
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + +引入 +如果说数论是数学体系中专门用来研究数字性质的一个分支,那么初等数论则是对整数的性质进行系统性的探讨与研究。千万不要因为其中的“初等”二字小瞧这初等数论尽管名称和学习难度上都没有高等数论那么有逼格,就像初等数学之于高数,数论的所有内容均筑基于此。其中欧几里得证明的算数基本定理(一切合数都可被分解为有限个质数的乘积)在质数筛、GCD(以及LCA)计算、无理数证明等问题上均有用武之地。可以... + + +
+ +
+
+ + + + + + + + + oi算法 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 一命已出,前来还愿 + +
+ + + +

+ +

+ +
+ + + + +2023.11.11 21:10 + + + + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + Part1. 运算符 +Div1. 基本运算 +加号:,键盘上有 +减号:,键盘上有 +乘号(叉乘): \times +乘号(数量积/点乘): +\cdot +除号: \div +开方/N次方根: +\sqrt[N]{ABC} +乘方/N次幂: +A^N +下标: A_N +分数: +\frac{A}{B} +等于号:,键盘上有 +约等号: +\approx 加粗 +\thickapprox +不等号: +\neq +恒等号/定... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + DC Doujin 2023 EP1 先行预告 + +
+ + + +

+ +

+ +
+ + + DC Doujin +2023,点击访问。 +DC Doujin将在11月带来他的第一部视频作品“一触即发 A Cusp Before It +Rings”。这个视频,对日常学校干饭的情景进行真实再现。其中由木稿比你铁饰演的受伤学生受到热烈关注,其原型是初中部的一位学生,我们将其镜头化,力求最真实地表现出其强烈的反差感。 +禁止用于商业用途,转载请注明出处 DC +Doujin。 +Copyright ... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 《原神》枫丹语言考究 + +
+ + + +

+ +

+ +
+ + + 起因 +这天月假,当我正为即将到来的水神池子疯狂做任务屯原石时,在列表里看到了一个悬赏整整30原石的世界任务。本着不放过任何一个给原石的任务的宗旨,我来到了秋分山西侧,白淞镇东北方向的海边房屋处。只见一位男子全身掩埋在海沙之下、动弹不得,面前摆放着一只散发香味的甜甜花酿鸡。我看他精神失常,满嘴都是“新型美容方式”的胡话又哭又闹,呜呜呜呜,好可怜呀。于是我决定帮他一把……找出了幕后黑手,此时他举... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+ + + + + + +
+ + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/archives/2023/12/index.html b/archives/2023/12/index.html new file mode 100644 index 0000000000..4ea0f10d18 --- /dev/null +++ b/archives/2023/12/index.html @@ -0,0 +1,4452 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档:2023/12 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ +
+
+ + +

JustPureH2O

+ + +

深水里摸大鱼

+ +
+ +
+ +
+ + + + + +
+ +
+
+ +
+ + +
+ + + + + + + + + + + + +
+
+ + + + + + +
+ + 2023年度总结——机房管理软件的破解经验 + +
+ + + +

+ +

+ +
+ + + +文中提到的核心程序代码及食用方法在文章末尾处,或者访问我的云剪贴板来复制代码 +更新条目的链接 +极域——世界上最弱小最单纯的机房软件 +注意,极域由C/C++语言开发。对于极域的反编译工作可以基本认定为徒劳且耗费大量时间的。 +开始的开始,我的脱控方式还仅限于最原始的taskkill和ntsd。这种做法不仅有时会失效,而且一旦老师发现你的机子的监控屏幕是纯黑一片、且无法控制,他就会气急败坏地冲向... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + DC Doujin 2023 EP1 一触即发正式发布 + +
+ + + +

+ +

+ +
+ + + + + + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+ + + + + + +
+ + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/archives/2023/index.html b/archives/2023/index.html new file mode 100644 index 0000000000..582f32752f --- /dev/null +++ b/archives/2023/index.html @@ -0,0 +1,5046 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档:2023 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ +
+
+ + +

JustPureH2O

+ + +

深水里摸大鱼

+ +
+ +
+ +
+ + + + + +
+ +
+
+ +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ + 2023年度总结——机房管理软件的破解经验 + +
+ + + +

+ +

+ +
+ + + +文中提到的核心程序代码及食用方法在文章末尾处,或者访问我的云剪贴板来复制代码 +更新条目的链接 +极域——世界上最弱小最单纯的机房软件 +注意,极域由C/C++语言开发。对于极域的反编译工作可以基本认定为徒劳且耗费大量时间的。 +开始的开始,我的脱控方式还仅限于最原始的taskkill和ntsd。这种做法不仅有时会失效,而且一旦老师发现你的机子的监控屏幕是纯黑一片、且无法控制,他就会气急败坏地冲向... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + DC Doujin 2023 EP1 一触即发正式发布 + +
+ + + +

+ +

+ +
+ + + + + + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + +引入 +如果说数论是数学体系中专门用来研究数字性质的一个分支,那么初等数论则是对整数的性质进行系统性的探讨与研究。千万不要因为其中的“初等”二字小瞧这初等数论尽管名称和学习难度上都没有高等数论那么有逼格,就像初等数学之于高数,数论的所有内容均筑基于此。其中欧几里得证明的算数基本定理(一切合数都可被分解为有限个质数的乘积)在质数筛、GCD(以及LCA)计算、无理数证明等问题上均有用武之地。可以... + + +
+ +
+
+ + + + + + + + + oi算法 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 一命已出,前来还愿 + +
+ + + +

+ +

+ +
+ + + + +2023.11.11 21:10 + + + + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + Part1. 运算符 +Div1. 基本运算 +加号:,键盘上有 +减号:,键盘上有 +乘号(叉乘): \times +乘号(数量积/点乘): +\cdot +除号: \div +开方/N次方根: +\sqrt[N]{ABC} +乘方/N次幂: +A^N +下标: A_N +分数: +\frac{A}{B} +等于号:,键盘上有 +约等号: +\approx 加粗 +\thickapprox +不等号: +\neq +恒等号/定... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + DC Doujin 2023 EP1 先行预告 + +
+ + + +

+ +

+ +
+ + + DC Doujin +2023,点击访问。 +DC Doujin将在11月带来他的第一部视频作品“一触即发 A Cusp Before It +Rings”。这个视频,对日常学校干饭的情景进行真实再现。其中由木稿比你铁饰演的受伤学生受到热烈关注,其原型是初中部的一位学生,我们将其镜头化,力求最真实地表现出其强烈的反差感。 +禁止用于商业用途,转载请注明出处 DC +Doujin。 +Copyright ... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 《原神》枫丹语言考究 + +
+ + + +

+ +

+ +
+ + + 起因 +这天月假,当我正为即将到来的水神池子疯狂做任务屯原石时,在列表里看到了一个悬赏整整30原石的世界任务。本着不放过任何一个给原石的任务的宗旨,我来到了秋分山西侧,白淞镇东北方向的海边房屋处。只见一位男子全身掩埋在海沙之下、动弹不得,面前摆放着一只散发香味的甜甜花酿鸡。我看他精神失常,满嘴都是“新型美容方式”的胡话又哭又闹,呜呜呜呜,好可怜呀。于是我决定帮他一把……找出了幕后黑手,此时他举... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 常用算法模板 + +
+ + + +

+ +

+ +
+ + + 1. Trie树(字典树) +123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051#include <bits/stdc++.h>#define N 10010using namespace std;int son[N][70], idx = 0, ... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 国祯文集 + +
+ + + +

+ +

+ +
+ + + 曾茂华到底有多六 +——By 国祯 +曾茂华是中国当代著名的科学家和教育家,他以“慈父”、“良师”、“学者”等称号闻名于世。 +1:曾茂华的蠢行为 +曾茂华的蠢行为: +他在大学期间参加了一个乐队,并担任主唱。然而,不幸的是,由于自己的疏忽,他犯下了一件愚蠢的事情——用刀砍掉了对方的手指头。这件事让他成了学校里的头号人物之一。从那以后,他再也不敢做任何愚蠢的事情了。这是因为他害怕自己会被开除出乐队或者... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + CSP-J 2023 游记 + +
+ + + +

+ +

+ +
+ + + 又名:《第一次考就被小学生薄纱的一集》 +本次考场:绵阳东辰国际学校 +第一节    赛前准备 +       插一句:CSP-J +2023没有设置赛前试机环节(包括CSP-S,成都绵阳都这样),个人推测可能是由于开放自选Windows和Linux系统带来的结果。如果你听见诸如:不要操作电脑,违者将作作弊处理 +的话时,请将你按捺不住的双手安稳的放在双腿上,避免出现意料之外的事来。 +       然... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+ + +
+
+ +

+ 1 / 2 +

+ + + +
+ + + + + +
+ + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/archives/2023/page/2/index.html b/archives/2023/page/2/index.html new file mode 100644 index 0000000000..8582fbf8da --- /dev/null +++ b/archives/2023/page/2/index.html @@ -0,0 +1,4390 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档:2023 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ +
+
+ + +

JustPureH2O

+ + +

深水里摸大鱼

+ +
+ +
+ +
+ + + + + +
+ +
+
+ +
+ + +
+ + + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 本文转载自:【F444 +の 光荣历史•其二】人物传记·FRC +作者:Lucas2011 +一、简介 +曾就读于东辰「教学8班·行政11班」与我同班(两个都是哦),是我初中阶段最好的朋友。现就读于七林9班,在高中数学竞赛的道路上越走越远。喜好有Minecraft、原和一些神奇的卡牌游戏。有批判性思维,不从众,但是对自己的观点有强烈的自信,不拿出证据证明他是错的的话他绝对不会善罢甘休(但是在学校里证... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+ + +
+
+ + + +

+ 2 / 2 +

+ +
+ + + + + +
+ + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/archives/2024/01/index.html b/archives/2024/01/index.html new file mode 100644 index 0000000000..14e9a71ce2 --- /dev/null +++ b/archives/2024/01/index.html @@ -0,0 +1,4396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档:2024/1 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ +
+
+ + +

JustPureH2O

+ + +

深水里摸大鱼

+ +
+ +
+ +
+ + + + + +
+ +
+
+ +
+ + +
+ + + + + + + + + + +
+
+ + + + + + +
+ + 线性代数 简明教程 一 + +
+ + + +

+ +

+ +
+ + + +线性代数 简明教程 +前言 + + + 前言正文 + + + + 我个人认为我自己与线性代数的渊源是极深的。差不多整一年之前,初三上册的寒假,我在启动某二字二次元风格开放世界游戏时偶然做到了一个世界解谜。与平常无脑过的难度不同,这次的解谜可谓是充满血和汗水的教训——看攻略前千万要搞清楚站位和朝向……于是一步错步步错,耗费了整整半个小时才碰巧还原到原始的... + + +
+ +
+
+ + + + + + + + + 自学的数学 + + + + +
+ + + +
+ +
+ +
+ + + +
+ + + + + + +
+ + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/archives/2024/02/index.html b/archives/2024/02/index.html new file mode 100644 index 0000000000..fa6255daf9 --- /dev/null +++ b/archives/2024/02/index.html @@ -0,0 +1,5008 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档:2024/2 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ +
+
+ + +

JustPureH2O

+ + +

深水里摸大鱼

+ +
+ +
+ +
+ + + + + +
+ +
+
+ +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 在此记录我个人对博客的一些个性化改造 +本博客使用的Volantis(版本 6.0.0 alpha +1)改造版主题已Fork原主题: + +原主题仓库 +Fork + + +前端类 +刷新式Banner +对视差滚动插件进行改造,将原先的定时更换变为了刷新更换,以减少窗口重获焦点后重复加载图片的问题。 +在这里查看本网站的Banner信息 +OJ网站题目标签 +添加了常用OJ网站(洛谷、AcWing)的题目难度标签... + + +
+ +
+
+ + + + + + + + + 博客搭建开发记录 + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 闫氏DP 学习笔记 + +
+ + + +

+ +

+ +
+ + + 说在前面 +本博客中“闫氏DP”指的是2011年NOI金牌保送北京大学计算机系的算法选手闫学灿(yxc/y总)在教授动态规划时提出的“从集合角度分析DP问题的思维方式”。并非指代某类动态规划题型、也不是某种求解动态规划的固定算法。该文章仅作“闫氏DP”的学习笔记,一并附上例题的个人理解。为了使文章生动有趣,后文使用“yxc”或“y总”指代闫学灿本人。 +代码均经过本人实际测试AC后才给出,代码总... + + +
+ +
+
+ + + + + + + + + oi算法 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 题目传送门:P10178 +受到了题面的启发,我才想起那个早已死去的算法——SPFA +题面总结成一句话就是:最短路只能有一条。 +那么我们用最短路算法:如果有最短路,先选择最短路。如果在更新最短值时出现了冲突——即某两种方案路径长度相等时,让后来者考虑加上一个 + +范围内的值,使它变长、不再是最短路(退出奖牌争夺)就好了。 +对于加上的正整数值,不妨从 +开始加。不够就加上 ,还不够就加上 +,以... + + +
+ +
+
+ + + + + + + + + 题解 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 何为分块 +分块,正如其名,将一个整区间分为若干小区间进行操作。分块拥有比线段树更强的泛用性,但是时间复杂度略输一筹;分块代码更加直观、减少理解难度,但是时间复杂度稍逊风骚;分块的代码比线段树更短,但是时间复杂度惜败后者……线段树所上下传递的操作计算必须满足结合律,区间平均数、方差还行,像计算区间众数、中位数这样的问题,线段树就只能被薄纱了…… +考虑到树状数组理解难度较大、较难调试,一般都选用... + + +
+ +
+
+ + + + + + + + + oi算法 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 开发初衷 +Phigros玩得太烂了(确信) +啊作为一名中学生最重要的还得是学习!学习为重是吧。想着开发一个C#窗口程序练练手,顺便涉足一下OpenGL图像渲染的领域。挺重要的一点是感觉自己还是太闲了,再加上PC端音游实在太少喽。就萌生了这个想法。 +图形环境 +整体基于C#的.NET窗体程序,搭配OpenGL进行图形渲染和绘制。OpenGL本身调用起来比较麻烦,涉及很多底层操作(类似于C/C++... + + +
+ +
+
+ + + + + + + + + 开发记录 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + Hexo云后台——Qexo搭建教程 + +
+ + + +

+ +

+ +
+ + + 在开始之前,首先你需要有一个自己的域名(github.io不算在内,你必须能够亲自更改DNS解析设置),并在博客仓库设置的Pages选项卡中绑定自己的域名。 +部署Qexo环境 +官方提供了四种方式来部署Qexo环境,其中一种允许你在本地进行部署,另外三种各自使用了不同网站提供的免费数据库服务。综合考虑操作便捷性和成功率,这里选用Vercel提供的免费PostgreSQL服务进行部署。 +首先点击... + + +
+ +
+
+ + + + + + + + + 博客搭建 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + +诗曰: +“高数第一杀手,考试一考就寄。复数知识一用,算成正一。朴素演算善后,死磕公式何必?考场信心十足,全错当场暴毙。” + +前置知识:复数、位运算 +Part1. 快速傅里叶变换 +Div1. 世界上最优雅的算法 +FFT起源 +FFT的前身是DFT,可以简单看作是一堆OIer争先恐后对DFT算法进行优化的结果。美苏冷战期间,双方都对自己的核实力有所隐瞒,就等着某一天用自己的核导弹打对方个措手不及... + + +
+ +
+
+ + + + + + + + + oi算法 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 线性代数 简明教程 二 + +
+ + + +

+ +

+ +
+ + + pandoc测试自动部署 + + + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 约瑟夫环——春晚魔术表演原理解析 + +
+ + + +

+ +

+ +
+ + + +(操作没成功の尴尬,图片来自知乎) +前言 +这篇文章从数学方面推导刘谦2024年央视春晚上表演的第二个魔术的秘密、分析尼格买提错误之处,并在已知信息的加持下尝试推测尼格买提手上所剩的两张半面扑克牌的牌型。有一说一撒贝宁是真的会测假 +对应魔术节目:《守岁共此时》的回看请戳这里,在一小时十分整处。 +魔术步骤 + +四张牌面向下,并打乱。 +对折四张牌,并沿折痕撕开,得到两批半牌,每批四个共八个半牌 +(... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+ + + + + + +
+ + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/archives/2024/index.html b/archives/2024/index.html new file mode 100644 index 0000000000..435d0e722e --- /dev/null +++ b/archives/2024/index.html @@ -0,0 +1,5091 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档:2024 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ +
+
+ + +

JustPureH2O

+ + +

深水里摸大鱼

+ +
+ +
+ +
+ + + + + +
+ +
+
+ +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 在此记录我个人对博客的一些个性化改造 +本博客使用的Volantis(版本 6.0.0 alpha +1)改造版主题已Fork原主题: + +原主题仓库 +Fork + + +前端类 +刷新式Banner +对视差滚动插件进行改造,将原先的定时更换变为了刷新更换,以减少窗口重获焦点后重复加载图片的问题。 +在这里查看本网站的Banner信息 +OJ网站题目标签 +添加了常用OJ网站(洛谷、AcWing)的题目难度标签... + + +
+ +
+
+ + + + + + + + + 博客搭建开发记录 + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 闫氏DP 学习笔记 + +
+ + + +

+ +

+ +
+ + + 说在前面 +本博客中“闫氏DP”指的是2011年NOI金牌保送北京大学计算机系的算法选手闫学灿(yxc/y总)在教授动态规划时提出的“从集合角度分析DP问题的思维方式”。并非指代某类动态规划题型、也不是某种求解动态规划的固定算法。该文章仅作“闫氏DP”的学习笔记,一并附上例题的个人理解。为了使文章生动有趣,后文使用“yxc”或“y总”指代闫学灿本人。 +代码均经过本人实际测试AC后才给出,代码总... + + +
+ +
+
+ + + + + + + + + oi算法 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 题目传送门:P10178 +受到了题面的启发,我才想起那个早已死去的算法——SPFA +题面总结成一句话就是:最短路只能有一条。 +那么我们用最短路算法:如果有最短路,先选择最短路。如果在更新最短值时出现了冲突——即某两种方案路径长度相等时,让后来者考虑加上一个 + +范围内的值,使它变长、不再是最短路(退出奖牌争夺)就好了。 +对于加上的正整数值,不妨从 +开始加。不够就加上 ,还不够就加上 +,以... + + +
+ +
+
+ + + + + + + + + 题解 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 何为分块 +分块,正如其名,将一个整区间分为若干小区间进行操作。分块拥有比线段树更强的泛用性,但是时间复杂度略输一筹;分块代码更加直观、减少理解难度,但是时间复杂度稍逊风骚;分块的代码比线段树更短,但是时间复杂度惜败后者……线段树所上下传递的操作计算必须满足结合律,区间平均数、方差还行,像计算区间众数、中位数这样的问题,线段树就只能被薄纱了…… +考虑到树状数组理解难度较大、较难调试,一般都选用... + + +
+ +
+
+ + + + + + + + + oi算法 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 开发初衷 +Phigros玩得太烂了(确信) +啊作为一名中学生最重要的还得是学习!学习为重是吧。想着开发一个C#窗口程序练练手,顺便涉足一下OpenGL图像渲染的领域。挺重要的一点是感觉自己还是太闲了,再加上PC端音游实在太少喽。就萌生了这个想法。 +图形环境 +整体基于C#的.NET窗体程序,搭配OpenGL进行图形渲染和绘制。OpenGL本身调用起来比较麻烦,涉及很多底层操作(类似于C/C++... + + +
+ +
+
+ + + + + + + + + 开发记录 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + Hexo云后台——Qexo搭建教程 + +
+ + + +

+ +

+ +
+ + + 在开始之前,首先你需要有一个自己的域名(github.io不算在内,你必须能够亲自更改DNS解析设置),并在博客仓库设置的Pages选项卡中绑定自己的域名。 +部署Qexo环境 +官方提供了四种方式来部署Qexo环境,其中一种允许你在本地进行部署,另外三种各自使用了不同网站提供的免费数据库服务。综合考虑操作便捷性和成功率,这里选用Vercel提供的免费PostgreSQL服务进行部署。 +首先点击... + + +
+ +
+
+ + + + + + + + + 博客搭建 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + +诗曰: +“高数第一杀手,考试一考就寄。复数知识一用,算成正一。朴素演算善后,死磕公式何必?考场信心十足,全错当场暴毙。” + +前置知识:复数、位运算 +Part1. 快速傅里叶变换 +Div1. 世界上最优雅的算法 +FFT起源 +FFT的前身是DFT,可以简单看作是一堆OIer争先恐后对DFT算法进行优化的结果。美苏冷战期间,双方都对自己的核实力有所隐瞒,就等着某一天用自己的核导弹打对方个措手不及... + + +
+ +
+
+ + + + + + + + + oi算法 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 线性代数 简明教程 二 + +
+ + + +

+ +

+ +
+ + + pandoc测试自动部署 + + + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 约瑟夫环——春晚魔术表演原理解析 + +
+ + + +

+ +

+ +
+ + + +(操作没成功の尴尬,图片来自知乎) +前言 +这篇文章从数学方面推导刘谦2024年央视春晚上表演的第二个魔术的秘密、分析尼格买提错误之处,并在已知信息的加持下尝试推测尼格买提手上所剩的两张半面扑克牌的牌型。有一说一撒贝宁是真的会测假 +对应魔术节目:《守岁共此时》的回看请戳这里,在一小时十分整处。 +魔术步骤 + +四张牌面向下,并打乱。 +对折四张牌,并沿折痕撕开,得到两批半牌,每批四个共八个半牌 +(... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 线性代数 简明教程 一 + +
+ + + +

+ +

+ +
+ + + +线性代数 简明教程 +前言 + + + 前言正文 + + + + 我个人认为我自己与线性代数的渊源是极深的。差不多整一年之前,初三上册的寒假,我在启动某二字二次元风格开放世界游戏时偶然做到了一个世界解谜。与平常无脑过的难度不同,这次的解谜可谓是充满血和汗水的教训——看攻略前千万要搞清楚站位和朝向……于是一步错步步错,耗费了整整半个小时才碰巧还原到原始的... + + +
+ +
+
+ + + + + + + + + 自学的数学 + + + + +
+ + + +
+ +
+ +
+ + + +
+ + + + + + +
+ + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/archives/index.html b/archives/index.html new file mode 100644 index 0000000000..5625a8ea6e --- /dev/null +++ b/archives/index.html @@ -0,0 +1,4643 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ +
+
+ + +

JustPureH2O

+ + +

深水里摸大鱼

+ +
+ +
+ +
+ + + + + +
+ +
+
+ + + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/archives/page/2/index.html b/archives/page/2/index.html new file mode 100644 index 0000000000..f19f6b9d02 --- /dev/null +++ b/archives/page/2/index.html @@ -0,0 +1,4643 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ +
+
+ + +

JustPureH2O

+ + +

深水里摸大鱼

+ +
+ +
+ +
+ + + + + +
+ +
+
+ + + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/archives/page/3/index.html b/archives/page/3/index.html new file mode 100644 index 0000000000..1ecd3b2fdf --- /dev/null +++ b/archives/page/3/index.html @@ -0,0 +1,4643 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ +
+
+ + +

JustPureH2O

+ + +

深水里摸大鱼

+ +
+ +
+ +
+ + + + + +
+ +
+
+ + + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/biography-to-frc-delivery/index.html b/biography-to-frc-delivery/index.html new file mode 100644 index 0000000000..0192fc09b1 --- /dev/null +++ b/biography-to-frc-delivery/index.html @@ -0,0 +1,4413 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 人物传记·FRC(搬运) - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + + +
+
+

本文转载自:【F444 +の 光荣历史•其二】人物传记·FRC +作者:Lucas2011

+

一、简介

+

曾就读于东辰「教学8班·行政11班」与我同班(两个都是哦),是我初中阶段最好的朋友。现就读于七林9班,在高中数学竞赛的道路上越走越远。喜好有Minecraft、原和一些神奇的卡牌游戏。有批判性思维,不从众,但是对自己的观点有强烈的自信,不拿出证据证明他是错的的话他绝对不会善罢甘休(但是在学校里证据真的很难找awa)。特别喜欢讲故事,经常编一些东西以假乱真,甚至到了剩下的5个人异口同声的问他“真的吗?”这种地步。

+

二、外号来源

+

FRC又知名为天皇陛下,冯进村等等(反正都是从“日本天皇”衍生出来的)。那么这个外号是从哪里来的呢?据传说(主要大家基本都快忘了,经过讨论认定了这个最终版本),一次中午回寝,大家在激烈的讨论历史课上刚刚讲的日本明治维新相关的内容,FRC为了让大家认真的听他的观点,就说“我是天皇陛下…”,于是这个外号就传开了。四舍五入这个外号是他自己取的

+

三、关于学习

+

相信不用我多说了,能进七林九班的都不是什么善茬。但是我还是附上一次8年级(大概)的月考成绩图:

+
+月考成绩图 + +
+

∆天皇稳居第一,高第二名十多分

+

除了学习,其实我更想说的是他的批判性思维。这一点可能和其他寝室不同,我们寝室常常谈论一些时政内容或者类似的需要表达自己的观点并证明的内容。在这样的环境下,小蝴蝶、我、天皇和其他公民(ffy经常偷听我们聊天但是不说话,sbffy)都能有一套自己的论证思路并相互交融,我不认为这对逻辑思维能力的发展没有帮助。

+

四、关于游戏

+

分成两个部分吧,原和Minecraft。

+

原神

+

应该是初三下学期才入的坑,算比较晚的。他入坑在我看来应该是被逼无奈,实在和他的好朋友们没有共同话题才入的坑。但是他入坑后特别肝,现在应该55级了吧(思考)

+

由于他B我官(他B服,我官服,我们两个之间已经隔了一道厚障壁力(悲),所以基本没怎么联过机,但是后来他朋友送了他一个官服号,就和我玩过一两次(主要O是养成类游戏,那个号上什么也没有)。

+

他狂热地厨纳西妲,所以就在这里放两张纳西妲的游戏截图吧(太随性了awa):

+
+1 + +
+
+2 + +
+
+3 + +
+

∆这个应该是他草神的面板(翻了10分钟聊天记录才找到qwq

+

Minecraft

+

自从我认识他(在军训的时候)他就玩mc,还记得当时我们因为2个木板合成几个木棍而吵架(他说“两个木板合成两个木棍”,我说是4个,事后他便获得了“cloud +player”这个称号,不过现在已经没什么人喊了)。

+

和他在信息技术课上(常规课和社团课)玩过1.12匠魂,1.18原版和空岛,1.18.2匠魂等等(甚至为了这个去学了C++并考了校队,走上一条OI不归路

+

他记忆力很好,所有模组相关的合成表我都直接问他,像什么《匠魂宝典》都是他读,读完了就把有用的属性提炼出来给我说。

+

当然,我主要负责生电和指令嘛(撅嘴

+

下面是一些游戏截图:

+
+4 + +
+
+5 + +
+
+6 + +
+

∆这些都是匠魂的存档,空岛的没怎么截图

+

五、自述

+

由于天皇现在在七林扫荡,找不到他人,所以这个部分先咕掉(*≧ω≦)

+

当然,天皇是不会被放过的(早柚音

+

六、他人刻画

+

这个部分应该是最精彩的部分(确信

+
+

+

天皇为什么叫天皇我也不知道,开始他看起来比较可爱但后面就越来越猥琐,有着非常智慧的大脑,比较喜欢理性分析问题,然后感性处理问题(指看心情),好玩做事比较冲动喜欢玄学,求知欲旺,又不的问题,一定会细心请教不是不擅长运动比较懒惰,口才很好喜欢讲故事,有点贪睡眠质量良好呼噜声特别大特别情况下被刺激会暴怒。

+
+

+

冯氏、本名瑞辰。传闻天地初开之时,天下五分,雷占其四而天皇独占其一,是为一人之下,万人之上矣。遂有天皇之名(语出《sl经典语录》)数学之王(官方限定)在数学方面卓有天赋。为人和善。初极狭,才通人。口才极佳,善于讲故事。京中有善口技者,为寝室建设作出卓越贡献,但会在晚上使用声波武器,对寝室成员们进行精神攻击0.o

+
+

+

+

+

+

+

+

+

这个事件后面会讲(应该

+
+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

不可避免的偏题了qwq

+
+

总之感觉就是比我nb但是心术大不正(离谱 +的那种学神

+

+

+

话题莫名其妙的回来了awa

+
+
+

+

天皇陛下,不知道为什么,每次看到他抱着自己家的柴犬的照片时,总有一种兄弟情深的感觉。

+

感觉他严肃正经起来很有学霸的气息,但是一旦下了课,我总能在校围栏旁的草丛附近发现他的身影。

+

尤其喜爱捉某些昆虫(指蝴蝶),采摘水果(指东辰的桃子和杏),能夹,yin叫起来比大部分人(除开胡睿杰)更像女的。

+

自从他脸上受伤留下一道光荣印记以来,他的笑容比之前猥琐了指数倍。

+

但是对于他的智力,无可置疑的是他确实实力无限,他和那些闷头整天坐在教室里学习的娃的最大区别就是:他深谙劳逸结合的重要性,平时也会和同学打成一片,尤其喜欢叫外号,据个人无数据的不完全统计——他最钟爱的外号包括guozhen、sb飞飞鱼、小蝴蝶、草绿等。

+
+

+

+

不知道怎么请到的神奇人物

+
+

就看起来傻不拉叽,但十分聪明的一个人。奇奇怪怪,但很喜欢作为上课的气氛担当。就是说至于用书签削学校的转基因农作物,抓些小虫养在教室这种行为,我的评价是👍。讲真的,聪明人还是聪明人,还是有亿点离谱的。

+

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + +
+
+ + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/blog-personalization/index.html b/blog-personalization/index.html new file mode 100644 index 0000000000..29b7df7dcd --- /dev/null +++ b/blog-personalization/index.html @@ -0,0 +1,4359 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Volantis魔改记录 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + + +
+
+

在此记录我个人对博客的一些个性化改造

+

本博客使用的Volantis(版本 6.0.0 alpha +1)改造版主题已Fork原主题:

+ +
+

前端类

+

刷新式Banner

+

对视差滚动插件进行改造,将原先的定时更换变为了刷新更换,以减少窗口重获焦点后重复加载图片的问题。

+

这里查看本网站的Banner信息

+

OJ网站题目标签

+

添加了常用OJ网站(洛谷、AcWing)的题目难度标签CSS,现在可以直接通过span标签显示:

+

洛谷风格

+
    +
  1. 神秘客
  2. +
  3. 用脚切的题
  4. +
  5. 只用一只手切的题
  6. +
  7. 大规模出现DP、字符串、模拟等恶心题
  8. +
  9. 恭喜你进阶了
  10. +
  11. 只要线代学得好,蓝题狂刷少不了
  12. +
  13. 同学,网络流好学吗
  14. +
  15. 构造秒了
  16. +
  17. 题目来源:收钱协会举办的比赛之提高组    收钱协会举办的比赛之普及组    多 人 信 息 学 比 +赛    残 害 奶 牛 组 织 举 办 的 比 +赛
  18. +
  19. 相关比赛年份:2024    2023    2077    2233
  20. +
  21. 算法标签:大模拟    退火邪教    毒瘤数据结构    卡常
  22. +
  23. 特殊题目标签:吸氧题,O2    臭氧优化,O3    四聚氧优化,O4    红氧优化,O8
  24. +
  25. 题目来源区域:蒙德城    璃月    稻妻城    须弥城    枫丹廷
  26. +
+

以上均为整活

+

span标签:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!-- 题目难度评级 -->
<span data-v-71731098="" class="lfe-caption" style="color:#FFFFFF; background:#BFBFBF;">暂无评定</span>

<span data-v-71731098="" class="lfe-caption" style="color:#FFFFFF; background:#FE4C61;">入门</span>

<span data-v-71731098="" class="lfe-caption" style="color:#FFFFFF; background:#F39C11;">普及-</span>

<span data-v-71731098="" class="lfe-caption"data-v-f9624136="" style="color:#FFFFFF; background:#FFC116;">普及/提高-</span>

<span data-v-71731098="" class="lfe-caption" style="color:#FFFFFF; background:#52C41A;">普及+/提高</span>

<span data-v-71731098="" class="lfe-caption" style="color:#FFFFFF; background:#3498DB;">提高+/省选-</span>

<span data-v-71731098="" class="lfe-caption" style="color:#FFFFFF; background:#9D3DCF;">省选/NOI-</span>

<span data-v-71731098="" class="lfe-caption" style="color:#FFFFFF; background:#0E1D69;">NOI/NOI+/CTSC</span>
<!-- 题目来源 -->
<span data-v-71731098="" class="lfe-caption" style="color:#FFFFFF; background:#13C2C2;">NOIp 提高组</span>
<!-- 题目相关年份 -->
<span data-v-71731098="" class="lfe-caption" style="color:#FFFFFF; background:#3498DB;">2024</span>
<!-- 题目算法标签 -->
<span data-v-71731098="" class="lfe-caption" style="color:#FFFFFF; background:#2949B4;">线性代数</span>
<!-- 特殊题目标签 -->
<span data-v-71731098="" class="lfe-caption" style="color:#FFFFFF; background:#F39C11;">O2优化</span>
<!-- 题目来源区域 -->
<span data-v-71731098="" class="lfe-caption" style="color:#FFFFFF; background:#52C41A;">四川</span>
+

对应CSS:

+
1
2
3
4
5
6
7
8
9
10
11
12
.lfe_caption {
font-size: 0.875em;
}

span[data-v-71731098] {
display:inline-block;
padding:0 8px;
box-sizing:border-box;
font-weight:400;
line-height:1.5;
border-radius:2px
}
+

AcWing风格

+
    +
  1. 简单
  2. +
  3. 中等
  4. +
  5. 困难
  6. +
+

span标签:

+
1
2
3
4
5
<span class="label label-success round">简单</span>

<span class="label label-warning round">中等</span>

<span class="label label-danger round">困难</span>
+

对应CSS:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.round {
border-radius: 1020px;
}

.label {
display: inline;
padding: .2em .6em .3em;
font-size: 75%;
font-weight: 700;
line-height: 1;
color: #fff;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
border-radius: .25em;
}

.label-success {
background-color: #5cb85c;
}

.label-warning {
background-color: #f0ad4e;
}

.label-danger {
background-color: #d9534f;
}
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + +
+
+ + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/categories/index.html b/categories/index.html new file mode 100644 index 0000000000..019dbeae94 --- /dev/null +++ b/categories/index.html @@ -0,0 +1,4127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 所有分类 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ + + + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git "a/categories/oi\347\256\227\346\263\225/index.html" "b/categories/oi\347\256\227\346\263\225/index.html" new file mode 100644 index 0000000000..e9e25bbc7e --- /dev/null +++ "b/categories/oi\347\256\227\346\263\225/index.html" @@ -0,0 +1,4546 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类:oi算法 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ + +
+ + + +
+ + + + + + + + + + + + + + + + +
+
+ + + + + + +
+ + 闫氏DP 学习笔记 + +
+ + + +

+ +

+ +
+ + + 说在前面 +本博客中“闫氏DP”指的是2011年NOI金牌保送北京大学计算机系的算法选手闫学灿(yxc/y总)在教授动态规划时提出的“从集合角度分析DP问题的思维方式”。并非指代某类动态规划题型、也不是某种求解动态规划的固定算法。该文章仅作“闫氏DP”的学习笔记,一并附上例题的个人理解。为了使文章生动有趣,后文使用“yxc”或“y总”指代闫学灿本人。 +代码均经过本人实际测试AC后才给出,代码总... + + +
+ +
+
+ + + + + + + + + oi算法 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 何为分块 +分块,正如其名,将一个整区间分为若干小区间进行操作。分块拥有比线段树更强的泛用性,但是时间复杂度略输一筹;分块代码更加直观、减少理解难度,但是时间复杂度稍逊风骚;分块的代码比线段树更短,但是时间复杂度惜败后者……线段树所上下传递的操作计算必须满足结合律,区间平均数、方差还行,像计算区间众数、中位数这样的问题,线段树就只能被薄纱了…… +考虑到树状数组理解难度较大、较难调试,一般都选用... + + +
+ +
+
+ + + + + + + + + oi算法 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + +诗曰: +“高数第一杀手,考试一考就寄。复数知识一用,算成正一。朴素演算善后,死磕公式何必?考场信心十足,全错当场暴毙。” + +前置知识:复数、位运算 +Part1. 快速傅里叶变换 +Div1. 世界上最优雅的算法 +FFT起源 +FFT的前身是DFT,可以简单看作是一堆OIer争先恐后对DFT算法进行优化的结果。美苏冷战期间,双方都对自己的核实力有所隐瞒,就等着某一天用自己的核导弹打对方个措手不及... + + +
+ +
+
+ + + + + + + + + oi算法 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + +引入 +如果说数论是数学体系中专门用来研究数字性质的一个分支,那么初等数论则是对整数的性质进行系统性的探讨与研究。千万不要因为其中的“初等”二字小瞧这初等数论尽管名称和学习难度上都没有高等数论那么有逼格,就像初等数学之于高数,数论的所有内容均筑基于此。其中欧几里得证明的算数基本定理(一切合数都可被分解为有限个质数的乘积)在质数筛、GCD(以及LCA)计算、无理数证明等问题上均有用武之地。可以... + + +
+ +
+
+ + + + + + + + + oi算法 + + + + +
+ + + +
+ +
+ +
+ + + +
+ + + + + + + +
+ + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git "a/categories/\345\215\232\345\256\242\346\220\255\345\273\272/index.html" "b/categories/\345\215\232\345\256\242\346\220\255\345\273\272/index.html" new file mode 100644 index 0000000000..49331cd69a --- /dev/null +++ "b/categories/\345\215\232\345\256\242\346\220\255\345\273\272/index.html" @@ -0,0 +1,4408 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类:博客搭建 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ + +
+ + + +
+ + + + + + + + + + + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 在此记录我个人对博客的一些个性化改造 +本博客使用的Volantis(版本 6.0.0 alpha +1)改造版主题已Fork原主题: + +原主题仓库 +Fork + + +前端类 +刷新式Banner +对视差滚动插件进行改造,将原先的定时更换变为了刷新更换,以减少窗口重获焦点后重复加载图片的问题。 +在这里查看本网站的Banner信息 +OJ网站题目标签 +添加了常用OJ网站(洛谷、AcWing)的题目难度标签... + + +
+ +
+
+ + + + + + + + + 博客搭建开发记录 + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + Hexo云后台——Qexo搭建教程 + +
+ + + +

+ +

+ +
+ + + 在开始之前,首先你需要有一个自己的域名(github.io不算在内,你必须能够亲自更改DNS解析设置),并在博客仓库设置的Pages选项卡中绑定自己的域名。 +部署Qexo环境 +官方提供了四种方式来部署Qexo环境,其中一种允许你在本地进行部署,另外三种各自使用了不同网站提供的免费数据库服务。综合考虑操作便捷性和成功率,这里选用Vercel提供的免费PostgreSQL服务进行部署。 +首先点击... + + +
+ +
+
+ + + + + + + + + 博客搭建 + + + + +
+ + + +
+ +
+ +
+ + + +
+ + + + + + + +
+ + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git "a/categories/\345\274\200\345\217\221\350\256\260\345\275\225/index.html" "b/categories/\345\274\200\345\217\221\350\256\260\345\275\225/index.html" new file mode 100644 index 0000000000..723cc887d5 --- /dev/null +++ "b/categories/\345\274\200\345\217\221\350\256\260\345\275\225/index.html" @@ -0,0 +1,4407 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类:开发记录 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ + +
+ + + +
+ + + + + + + + + + + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 在此记录我个人对博客的一些个性化改造 +本博客使用的Volantis(版本 6.0.0 alpha +1)改造版主题已Fork原主题: + +原主题仓库 +Fork + + +前端类 +刷新式Banner +对视差滚动插件进行改造,将原先的定时更换变为了刷新更换,以减少窗口重获焦点后重复加载图片的问题。 +在这里查看本网站的Banner信息 +OJ网站题目标签 +添加了常用OJ网站(洛谷、AcWing)的题目难度标签... + + +
+ +
+
+ + + + + + + + + 博客搭建开发记录 + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 开发初衷 +Phigros玩得太烂了(确信) +啊作为一名中学生最重要的还得是学习!学习为重是吧。想着开发一个C#窗口程序练练手,顺便涉足一下OpenGL图像渲染的领域。挺重要的一点是感觉自己还是太闲了,再加上PC端音游实在太少喽。就萌生了这个想法。 +图形环境 +整体基于C#的.NET窗体程序,搭配OpenGL进行图形渲染和绘制。OpenGL本身调用起来比较麻烦,涉及很多底层操作(类似于C/C++... + + +
+ +
+
+ + + + + + + + + 开发记录 + + + + +
+ + + +
+ +
+ +
+ + + +
+ + + + + + + +
+ + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git "a/categories/\350\207\252\345\255\246\347\232\204\346\225\260\345\255\246/index.html" "b/categories/\350\207\252\345\255\246\347\232\204\346\225\260\345\255\246/index.html" new file mode 100644 index 0000000000..fb9d1447ce --- /dev/null +++ "b/categories/\350\207\252\345\255\246\347\232\204\346\225\260\345\255\246/index.html" @@ -0,0 +1,4325 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类:自学的数学 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ + +
+ + + +
+ + + + + + + + + + +
+
+ + + + + + +
+ + 线性代数 简明教程 一 + +
+ + + +

+ +

+ +
+ + + +线性代数 简明教程 +前言 + + + 前言正文 + + + + 我个人认为我自己与线性代数的渊源是极深的。差不多整一年之前,初三上册的寒假,我在启动某二字二次元风格开放世界游戏时偶然做到了一个世界解谜。与平常无脑过的难度不同,这次的解谜可谓是充满血和汗水的教训——看攻略前千万要搞清楚站位和朝向……于是一步错步步错,耗费了整整半个小时才碰巧还原到原始的... + + +
+ +
+
+ + + + + + + + + 自学的数学 + + + + +
+ + + +
+ +
+ +
+ + + +
+ + + + + + + +
+ + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git "a/categories/\351\242\230\350\247\243/index.html" "b/categories/\351\242\230\350\247\243/index.html" new file mode 100644 index 0000000000..373fcffcf0 --- /dev/null +++ "b/categories/\351\242\230\350\247\243/index.html" @@ -0,0 +1,4322 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 分类:题解 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ + +
+ + + +
+ + + + + + + + + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 题目传送门:P10178 +受到了题面的启发,我才想起那个早已死去的算法——SPFA +题面总结成一句话就是:最短路只能有一条。 +那么我们用最短路算法:如果有最短路,先选择最短路。如果在更新最短值时出现了冲突——即某两种方案路径长度相等时,让后来者考虑加上一个 + +范围内的值,使它变长、不再是最短路(退出奖牌争夺)就好了。 +对于加上的正整数值,不妨从 +开始加。不够就加上 ,还不够就加上 +,以... + + +
+ +
+
+ + + + + + + + + 题解 + + + + +
+ + + +
+ +
+ +
+ + + +
+ + + + + + + +
+ + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/common-algo-templates/index.html b/common-algo-templates/index.html new file mode 100644 index 0000000000..2b7168c707 --- /dev/null +++ b/common-algo-templates/index.html @@ -0,0 +1,4383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 常用算法模板 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ +
+
+ + + + + + + +
+ + + +
+ + + + +
+
+

1. Trie树(字典树)

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <bits/stdc++.h>
#define N 10010
using namespace std;

int son[N][70], idx = 0, cnt[N];

int map(char c) {
// 字符映射到对应数字
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'z') return c - 'a' + 11;
if (c >= 'A' && c <= 'Z') return c - 'A' + 37;
}

void insert(char s[]) {
// 插入一个字符串
int len = strlen(s);
int p = 0; // 指针
for (int i = 0; i < len; i++) {
// 遍历字符串中每一个字符
int u = map(s[i]); // 映射到数字
if (!son[p][u]) son[p][u] = ++idx;
p = son[p][u] // 更新指针,指向下一个节点
}
cnt[p]++;
}

bool query(char s[]) {
// 查询一个字符串
int len = strlen(s);
int p = 0;
for (int i = 0; i < len; i++) {
// 遍历+查找
int u = map(s[i]);
if (son[p][u]) p = son[p][u];
else return false;
}
return cnt[p];
}

int count(char s[]) {
// 对指定字符串计数
int len = strlen(s);
int p = 0;
// 可以用 if (query(s)) 代替下边的遍历查找
for (int i = 0; i < len; i++) {
int u = map(s[i]);
if (son[p][u]) p = son[p][u];
else return 0;
}
return cnt[p];
}
+

并查集

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <bits/stdc++.h>
#define N 10010
using namespace std;

int p[N];

int find(int x) {
// 查找父节点+路径压缩
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}

void merge(int a, int b) {
// 合并两个集合
p[find(a)] = find(b);
}

bool query(int a, int b) {
// 查询两个节点是否在同一个集合中
return find(a) == find(b);
}
+

单调队列

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <bits/stdc++.h>
#define N 10010
using namespace std;

struct Node {
int idx; // 下标
int val; // 数值
} nodes[N];

deque<Node> q;

void peak(int k) {
// 查找区间最值,n为数组大小,k为区间大小,即区间中有k个元素
for (int i = 1; i <= N; i++) {
// while (!q.empty() && nodes[i].val <= q.back().val) q.pop_back(); // 查找区间最小值,将大于号改为小于号
while (!q.empty() && nodes[i].val >= q.back().val) q.pop_back(); // 当新进元素大于队尾元素,删除队尾直到队尾大于新元素,或者直到队列为空
q.push_back(nodes[i]); // 将新进元素压入队尾
if (i - q.front().idx == k) q.pop_front(); // 滑出队头元素所在区间,弹出队头
if (i >= k) cout<<q.front().val<<endl;
}
}
+

单调栈

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <bits/stdc++.h>
#define N 10010
using namespace std;

struct Node {
int idx; // 下标
int val; // 数值
} nodes[N];

stack<Node> stk;
int ans[N];

void NGE(int k) {
// 查找下一个更大的元素,即NGE问题
for (int i = 1; i <= N; i++) {
// while (!stk.empty() && nodes[i].val < stk.back().val) // NSE问题,下一个更小的元素,仅改变大于小于号
while (!stk.empty() && nodes[i].val > stk.top().val) stk.pop(); // 将栈顶比当前更小的元素弹出
if (stk.empty()) ans[i] = 0; // 查无
else ans[i] = s.top(); // 顶为最大
stk.push(nodes[i]); // 压入当前
}
}
+

单源最短路径      朴素Dijkstra

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <bits/stdc++.h>
#define N 10010
#define INF 0x3f3f3f3f
using namespace std;

// 对于稠密图,使用邻接矩阵存图
int g[N][N], dist[N];
bool st[N];
int n;

void dijkstra() {
memset(dist, INF, sizeof dist); // 初始化距离,开始时均为正无穷,或者为-1

dist[1] = 0; // 起点最短路径就是0
for (int i = 1; i <= n; i++) {
int t = -1;
for (int j = 1; j <= n; j++) {
if (!st[j] && (t == -1 || dist[j] < dist[t])) t = j; // 循环所有未确定距离的点,找出最小值
}

st[t] = true; // 标记访问

for (int j = 1; j <= n; j++) {
dist[j] = min(dist[j], dist[t] + g[t][j]); // 间接的路径:从起点经t再连接到j点
}
}
}

+

单源最短路径      堆优化Dijkstra

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <bits/stdc++.h>
#define N 10010
#define INF 0x3f3f3f3f
using namespace std;

// 对于稀疏图,使用接表存图
int head[N], e[N], w[N], ne[N];
int idx = 0;

void add(int a, int b, int x) {
idx++;
e[idx] = b;
w[idx] = x;
ne[idx] = head[a];
head[a] = idx;
}

int dist[N];
bool st[N];
int n;

typedef pair<int, int> PIR; // 二元组存储点序号-距离
priority_queue<PIR, vector<PIR>, greater<PIR> > heap;

void dijkstra() {
memset(dist, INF, sizeof dist); // 初始化距离,开始时均为正无穷,或者为-1
heap.push((PIR) {1, 0}); // 初始点入队,序号为1距离为0

while (!heap.empty()) { // 堆不空时
PIR t = heap.top(); // 优先队列,队头元素总为未确定点中最近的一个
int id = t.first, dis = t.second;

if (st[id]) continue;

for (int i = head[id]; ~i; i = ne[idx]) {
int j = e[i]; // 边终点
if (dist[j] > dis + w[i]) {
dist[j] = dis + w[i]; // 更新最短距离
heap.push((PIR) {j, dist[j]}); // 更新的点压入优先队列
}
}
}
}

+

背包类动态规划      01背包

+

想象你在一个绝版手办售卖会上。这里的每种手办由于需要保证它的稀有程度,活动主办方提前向卖家商议了一个计策:即保证每种老婆 +手办有且只能有一个。这样他们就可以开出天价 +(但要保证在物价局划定的价格上限内) (爆long +long也没问题!)。那么作为一个资深 御宅 +手办收藏家的你,自然不会错过这次难得的机会,你出门时偷偷拿走了麻麻の钱包,发现里面有元现金(假定你不知道麻麻の银行卡密码),那么你可以买到手办的最大价值是多少?

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <bits/stdc++.h>
#define N 100010
using namespace std;

int w[N], v[N], dp[N];
// 价值 占地 容量上限为N时最大价值

int main() {
for (int i = 1; i <= n; i++) {
// 对于每个物品,从1到n
for (int j = c; j >= v[i]; j--) {
// 倒着循环,c为容量上限,防止做减法时减为负数内存异常
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
// 状态递推(一维压缩)
// 若不选该物品,则状态的剩余容量仍然为j,若选择则为j-v[i],相应的需要加上物品价值
}
}
cout<<dp[c];
return 0;
}
+

但是最后还是被麻麻发现力(悲

+

背包类动态规划      完全背包

+

这种问题类似于西方魔幻小说里的情节:一位勇士无意间闯进了古代君王的藏宝阁,受金钱和权力的蛊惑。看着地上不尽的金币与皇冠,他拿出了一个麻袋。他想要在麻袋规定的最大容量内装尽可能最大价值的物品,超出规定容量,这个袋子很可能破掉,导致财宝落入山谷、沼泽等任何危险的地方。这位勇士十分谨慎,他不希望总重量超过额定重量,那么他能装的最大物品价值是多少?

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <bits/stdc++.h>
#define N 100010
using namespace std;

int w[N], v[N], dp[N];
// 价值 占地 容量上限为N时最大价值

int main() {
// 完全背包,即每个物品数量有无限个,可以自由装配
for (int i = 1; i <= n; i++) {
// 对于每个物品,从1到n
for (int j = v[i]; j <= c; j++) {
// 正着循环,与01背包相反,c为容量上限
// 由于计算当前状态需用到dp[j-v[i]]状态,若升序循环,这个状态总会在前几步被算出
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
// 状态递推(一维压缩)
// 若不选该物品,则状态的剩余容量仍然为j,若选择则为j-v[i],相应的需要加上物品价值
// dp[i][j] = max(dp[i - 1][j], dp[i][j - v[i]] + w[i])
// 若不选择当前物品,最大价值为dp[i-1][j],即前一个/i-1个物品,容量上限为j (j<=c)时的最大价值
// 若选择当前物品,最大价值为dp[i][j-v[i]]+w[i],因为每种物品可以放入无限个,放入第i个物品后仍然可以继续放入相同物品直到超出容量上限j
}
}
cout<<dp[c];
return 0;
}
+

然而我们的勇士痴迷于装入财宝,忽视了高悬在他头顶的致命机关,随着绳子断裂,我们的勇士就此葬身于这个隐蔽的藏宝阁中,带不走任何一枚金币。因此我们的最大价值应该是 +因此我们应该拒绝这种来历不明的诱惑,青少年反诈,从我做起!

+

背包类动态规划      多重背包

+
+

《竞赛班传奇》    第一部,第一幕

+

人物:“和蔼可亲滴”福建籍物理竞赛教练 +茂华;“偷奸耍滑的”山东老家OIer +国祯;“热心尽职喜欢让同学们多多预习物理知识的”物理课代表曹牧

+

茂华上场,开玩笑的语气说

+

茂华: 电荷量滴单位是~库 +仑,符号C(写下一个大C),

+

全班哄笑,国祯猥琐的笑,茂华眉头一蹙,表情严肃,严肃语气

+

茂华: +国祯!还在那里笑,曹牧,检查一下国祯有没有记笔记!

+

曹牧起身走向国祯,其他人目光盯着曹牧,国祯将物理书翻开,指着笔记处,曹牧低头查看,然后抬头

+

曹牧: 他写了,但是……

+

严肃的,急速的,愤怒之极的,气震寰宇的,振聋发聩的,势如破竹的,响彻云霄的,如雷贯耳的,不共戴天的,耳机党爆炸的,外放党社死的

+

茂华: 站起来!没写笔记!

+

国祯吓一跳,乖乖站起,曹牧缓缓退回,众人起哄国,茂华声音略小

+

茂华: +在这里偷奸耍滑是会被刷出去滴。到时候你竞赛搞不好,高考也考滴西撇,看你到时候怎么办!

+

国祯: (解释的语气)我没有偷奸耍滑!

+

茂华语气有所缓和

+

茂华: 那你把这道题解出来,你就可以坐下了

+
+

题面: 给定个物品,背包最大容量。对于第种物品,给定每个种物品的大小,价值,以及个数,试求出背包可以装下物品的最大价值

+

国祯小嘴一撇,这还不简单?他立马拿起了一支0.5mm的黑色签字笔在草稿纸上飞速演算。得益于他积累了一坤年的OI知识,2分钟后,在众人惊异的目光中,国祯自信满满地拿出了写有正确答案的草稿纸。他将右手伸得十分用力,好像要把草稿纸怼到茂华脸上一样,他的嘴角浮现出一抹byd笑容。

+

只见茂华呆立原地,嘴巴微张,如同按下了暂停键。3秒钟的寂静过后,下课铃如同国祯的战鼓一般敲响,宣告这次对决以国祯的大比分取胜而落下帷幕。茂华直立的双腿尴尬的向门口转去,颤抖的双唇之间轻飘飘冒出了两个字:“下课”。随后咬紧嘴唇,一步一步踱向门外。

+

国祯如获新生。在众人崇拜和惊诧的目光中,他迷失了自我,他快步走向一体机,熟练地打开希沃白板,好像已经练习过成千上万遍似的,将一句话加粗写在了白板上:

+
+

通常情况下,多重背包的思路是将一堆A物品拆分成n个A物品,每个物品只能使用一次,便可转化为01背包问题

+
+

他不管大家是否了解01背包的含义,他此刻只想在众人面前分享打败茂华的喜悦感,以及打败茂华所需要的知识,这又何尝不是一种爱屋及乌的思想呢?

+

第二天,当上午的物理课准时来到,茂华却没有准时跨进教室的门。通常情况下,他每次课前都会提前2分钟来到教室里对同学进行题目过关。

+

1分钟后,茂华挟着几本不合身份的普及组信息竞赛导论及考纲,昂首阔步地走进了一班教室。他大声说着:“通常情况下。这是国祯同学昨天下课后给你们上的课里的一句原话!”

+

原来茂华前一天下课后并没有跑回办公室又哭又闹大发牢骚,而是现场网购了信息竞赛教程,准备在第二天的物理课上给国祯单独上节课:学生是永远无法击败老师滴!

+

他打开了浏览器,输入一行神秘的IP地址,按下回车,一个界面清爽的网站跳了出来。顶端用紫色的大写字母写着MHOI四个大字。

+

“牛逼吧,这是我连夜赶工自创的网站,”他笑着打开了题目列表中的第一道题,标题: +国祯接招 +。国祯轻蔑地瞥了一眼,题干还是昨天那样,一模一样,“看好了国祯,”他指向下排的一行小字,“数据范围:!看你那吃了食的小脑袋还能不能算出这道题目。”

+

显然,茂华是有备而来,国祯倒吸一口冷气。手工计算绝对是行不通了,但是对于竞赛班的高思娃国祯,绝对是有两把刷子的,毕竟正如茂华所说:“偷奸耍滑耍小聪明早就被刷下去了”。

+
+

面对如此巨大的物品总数,一些牛逼娃想到了用二进制拆分表示物品个数的方法。尽管换汤不换药,本质还是一个01背包问题,但是经过祖先们灵魂的注入,茂华是肯定不敢把你踢出竞赛班滴。

+

+

假设原有10个价值为2的物品,将10分为1+2+4+3,等同于有4个不同的01物品,价值分别为12=2,22=4,42=8,32=6,即2,4,8,6

+
+

国祯很快在VSCode上写出了一段教科书式的、注释易懂的模板代码,这次就算是物竞数竞化竞生竞的人也可以轻易看懂了:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <bits/stdc++.h>
#define N 100010
using namespace std;

int w[N], v[N], dp[N];
// 价值 占地 容量上限为N时最大价值
int idx = 0;
// 记录数组下标

int main() {
int n, c;
cin>>n>>c;

for (int i = 1; i <= n; i++) {
int a, b, s;
// v w n
// 即体积,价值,个数
cin>>a>>b>>s;

int k = 1; // 记录2的幂,初始值为2的0次幂,即1
//if (s == 0) s = INF; // 当题目中说数量0时默认为无限次时可以使用,这其实已经属于混合背包(多重+完全)的范畴
while (k <= s) {
// 个数可以继续被分解
s -= k; // 更新个数
idx++; // 新的下标
v[idx] = a * k; // 分解后该物品的大小
w[idx] = b * k; // 分解后该物品的价值
k *= 2; // k更新为2的下一个幂
}
if (s) {
// 若无法被完全分解,剩下一部分
idx++; // 记录新的下标
v[idx] = a * s; // 大小
w[idx] = b * s; // 价值
}
}
// 01背包模板
for (int i = 1; i <= n; i++) {
for (int j = c; j >= v[i]; j--) {
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
}
cout<<dp[c];
return 0;
}
+

国祯长舒一口气,这次他又获得了胜利。评测点加载了几秒。国祯定住了,#10号点出现一个大大的。国祯感觉堕入了万丈深渊,只见茂华狂笑了起来,带动全班其他同学的笑容,一班霎时被笑声吞没。国祯盯着评测信息,的运行时间让他更为疑惑,莫非茂华手动写了一个错误答案?

+

国祯尴尬的转向各位同学,其他同学瞬间停止了笑容。先前还在交头接耳的同学们如同机器一般齐刷刷的转向国祯,给人一种惊悚透骨的感觉。他们异口同声张开了嘴,在茂华扭曲的笑容下,说出了让国祯后悔了一辈子的话来:

+

“三年OI一场空,不开long long见祖宗!”

+

+

背包类动态规划      混合背包

+

混合背包,顾名思义。它混合了多种背包,实际应用中这一类问题比较有现实意义。主要思路是,将分属于各个类型背包的物品用几个条件判断语句写出来,然后分别套用各类背包的解决方案进行求解。

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <bits/stdc++.h>
#define N 100010
using namespace std;

int w[N], v[N], dp[N];
// 价值 占地 容量上限为N时最大价值

int main() {
for (int i = 1; i <= n; i++) {
if (A) {
// 01背包物品,写01背包模板
}
if (B) {
// 完全背包物品,写完全背包模板
}
if (C) {
// 其他……
}
}
return 0;
}
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + +
+
+ + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/content.json b/content.json new file mode 100644 index 0000000000..7f9990a579 --- /dev/null +++ b/content.json @@ -0,0 +1 @@ +{"meta":{"title":"JustPureH2O的博客","subtitle":"深水摸大鱼","description":"JustPureH2O的小窝","author":"JustPureH2O","url":"https://justpureh2o.github.io","root":"/"},"pages":[{"title":"","date":"2024-02-23T08:17:48.754Z","updated":"2024-02-21T23:14:48.900Z","comments":true,"path":"404.html","permalink":"https://justpureh2o.github.io/404.html","excerpt":"","text":"404 QWQ 迷路了~ 网络的尽头 虚无之地 [飞回母星](https://justpureh2o.cn/)"},{"title":"随笔","date":"2024-02-17T18:50:06.811Z","updated":"2024-02-19T19:44:30.315Z","comments":true,"path":"talks.html","permalink":"https://justpureh2o.github.io/talks.html","excerpt":"","text":"showQexoTalks(\"qexot\", \"https://admin.justpureh2o.cn\", 5)"},{"title":"","date":"2023-10-26T08:03:52.000Z","updated":"2024-02-23T08:17:48.754Z","comments":true,"path":"about/index.html","permalink":"https://justpureh2o.github.io/about/index.html","excerpt":"","text":""},{"title":"所有分类","date":"2024-02-23T08:17:48.754Z","updated":"2024-02-23T08:17:48.754Z","comments":true,"path":"categories/index.html","permalink":"https://justpureh2o.github.io/categories/index.html","excerpt":"","text":""},{"title":"DC Doujin 同人创作","date":"2023-11-04T08:33:40.000Z","updated":"2024-02-23T08:17:48.754Z","comments":true,"path":"dcdoujin/index.html","permalink":"https://justpureh2o.github.io/dcdoujin/index.html","excerpt":"","text":"DC Doujin 简介 DC Doujin 同人创作(以下简称DCD),由JustPureH2O于2023年11月5日创建。主要发布一些幽默视频,以及对应的幕后纪实。旨在用最真实最还原的镜头记录学校生活的点点滴滴。目前该频道的拍摄、剪辑、发布均由JustPureH2O一人承担,主要演员有木稿比你铁、狂三唯吾所爱 新闻 DC Doujin 2023 EP1 先行预告 DC Doujin 2023 EP1 一触即发 正式发布 演员 1. 木稿比你铁 DC Doujin 2023 EP1 拍摄前 2. 狂三唯吾所爱 (左侧)DC Doujin 2023 EP1 拍摄时"},{"title":"友情链接","date":"2024-02-23T08:17:48.782Z","updated":"2024-02-19T02:11:44.856Z","comments":true,"path":"friends/index.html","permalink":"https://justpureh2o.github.io/friends/index.html","excerpt":"","text":"loadQexoFriends(\"qexo-friends\", \"https://admin.justpureh2o.cn\")"},{"title":"高2023级一班热梗总结","date":"2023-11-04T08:33:30.000Z","updated":"2024-02-23T08:17:48.782Z","comments":true,"path":"memes/index.html","permalink":"https://justpureh2o.github.io/memes/index.html","excerpt":"","text":"2023.9 1. 吃饱啦 九月初的某节语文课,当语文老师问及苏轼的个人形象时,国祯和小又肥同时说出了“优雅”二字,国祯更是以一个屁总结了自己的观点。此后不久,国祯和冰正在激烈地讨论老八秘制小汉堡的事情,正当所有人因为思考语文老师提出的问题而陷入短暂沉寂时,冰向后一靠,把手垫在脑后,说了一句:“吃饱啦!”。便如此得名。 2. 电饭煲 国祯表示历史老师长得很像电饭煲,于是得名 3. 干饭 9月4日,一班真正意义上进行了一次以教室为起点的干饭行动,基本上一分钟内能够到达食堂。 4. Global Reading 张伟水课的新型套路——不讲正课天天喊我们拿出Global Reading来看,久而久之成为英语课和扣分的代名词。 5. 手套月饼 9月28日周四晚,东辰组织制作月饼,有人在月饼里放狠料咖啡粉、硬币、长尾夹(后被取出)。事后国祯将此事传开,被茂华得知,被张伟处分。 6. 巨人熊猫,孔子牙膏(富兰克林,酱香瑞幸) 张伟最爱罚背的几篇Global Reading上的文章,国庆放假前被总结为这句口头禅 2023.10 7. 奖励 张伟扣分前的口头禅,后演变为罚背的代名词"},{"title":"机房管理助手 v9.x已成功破解","date":"2023-12-24T00:45:33.000Z","updated":"2024-02-23T08:17:48.782Z","comments":true,"path":"misc/index.html","permalink":"https://justpureh2o.github.io/misc/index.html","excerpt":"","text":"任务管理器已解禁,您也可以自由使用注册表和组策略进行其他操作"},{"title":"网页图片信息 索引","date":"2024-02-13T05:25:57.000Z","updated":"2024-02-23T08:17:48.782Z","comments":true,"path":"picinfo/index.html","permalink":"https://justpureh2o.github.io/picinfo/index.html","excerpt":"","text":"选择一个项以获取该网页上的图片信息: 网站Banner:这里"},{"title":"所有标签","date":"2023-10-26T08:56:08.000Z","updated":"2024-02-23T08:17:48.782Z","comments":true,"path":"tags/index.html","permalink":"https://justpureh2o.github.io/tags/index.html","excerpt":"","text":""},{"title":"网站Banner信息","date":"2024-02-13T05:25:57.000Z","updated":"2024-02-23T08:17:48.782Z","comments":true,"path":"picinfo/banners/index.html","permalink":"https://justpureh2o.github.io/picinfo/banners/index.html","excerpt":"","text":"1 图片地址:这里 崩坏·星穹铁道 流萤 游戏内截图 2 图片地址:这里 崩坏·星穹铁道 花火 游戏内截图 3 图片地址:这里 崩坏·星穹铁道 流萤&星 游戏内截图 4 图片地址:这里 原神 芙宁娜 同人原创作品 5 图片地址:这里 原神 芙宁娜 同人原创作品 6 图片地址:这里 虚拟歌姬Vocaloid 初音未来·雪 同人原创作品 画师:Lunami Pixiv:雪·月 PID:65261833 7 图片地址:这里 虚拟歌姬Vocaloid 初音未来 同人原创作品 画师:Bison倉鼠 Pixiv:ネズミク PID:79008828 8 图片地址:这里 崩坏·星穹铁道 符玄 同人原创作品 9 图片地址:这里 崩坏·星穹铁道 停云&驭空 同人原创作品 10 图片地址:这里 画师:AutoINS Pixiv(从左至右):もう、そんなに見つめないでよ;二ヤ一;見て見て~ PID(从左至右):112244258;113354064;112841548 11 图片地址:这里 画师:AutoINS Pixiv(从左至右):✌️;二ヤ一;いい~疲れた~なぁ~ PID(从左至右):111148418;113354064;111548585"}],"posts":[{"title":"Volantis魔改记录","slug":"blog-personalization","date":"2024-02-21T23:18:20.738Z","updated":"2024-02-22T23:57:59.514Z","comments":true,"path":"blog-personalization/","link":"","permalink":"https://justpureh2o.github.io/blog-personalization/","excerpt":"","text":"在此记录我个人对博客的一些个性化改造 本博客使用的Volantis(版本 6.0.0 alpha 1)改造版主题已Fork原主题: 原主题仓库 Fork 前端类 刷新式Banner 对视差滚动插件进行改造,将原先的定时更换变为了刷新更换,以减少窗口重获焦点后重复加载图片的问题。 在这里查看本网站的Banner信息 OJ网站题目标签 添加了常用OJ网站(洛谷、AcWing)的题目难度标签CSS,现在可以直接通过span标签显示: 洛谷风格 神秘客 用脚切的题 只用一只手切的题 大规模出现DP、字符串、模拟等恶心题 恭喜你进阶了 只要线代学得好,蓝题狂刷少不了 同学,网络流好学吗 构造秒了 题目来源:收钱协会举办的比赛之提高组 收钱协会举办的比赛之普及组 多 人 信 息 学 比 赛 残 害 奶 牛 组 织 举 办 的 比 赛 相关比赛年份:2024 2023 2077 2233 算法标签:大模拟 退火邪教 毒瘤数据结构 卡常 特殊题目标签:吸氧题,O2 臭氧优化,O3 四聚氧优化,O4 红氧优化,O8 题目来源区域:蒙德城 璃月 稻妻城 须弥城 枫丹廷 以上均为整活 span标签: 1234567891011121314151617181920212223242526<!-- 题目难度评级 --><span data-v-71731098=\"\" class=\"lfe-caption\" style=\"color:#FFFFFF; background:#BFBFBF;\">暂无评定</span><span data-v-71731098=\"\" class=\"lfe-caption\" style=\"color:#FFFFFF; background:#FE4C61;\">入门</span><span data-v-71731098=\"\" class=\"lfe-caption\" style=\"color:#FFFFFF; background:#F39C11;\">普及-</span><span data-v-71731098=\"\" class=\"lfe-caption\"data-v-f9624136=\"\" style=\"color:#FFFFFF; background:#FFC116;\">普及/提高-</span><span data-v-71731098=\"\" class=\"lfe-caption\" style=\"color:#FFFFFF; background:#52C41A;\">普及+/提高</span><span data-v-71731098=\"\" class=\"lfe-caption\" style=\"color:#FFFFFF; background:#3498DB;\">提高+/省选-</span><span data-v-71731098=\"\" class=\"lfe-caption\" style=\"color:#FFFFFF; background:#9D3DCF;\">省选/NOI-</span><span data-v-71731098=\"\" class=\"lfe-caption\" style=\"color:#FFFFFF; background:#0E1D69;\">NOI/NOI+/CTSC</span><!-- 题目来源 --><span data-v-71731098=\"\" class=\"lfe-caption\" style=\"color:#FFFFFF; background:#13C2C2;\">NOIp 提高组</span><!-- 题目相关年份 --><span data-v-71731098=\"\" class=\"lfe-caption\" style=\"color:#FFFFFF; background:#3498DB;\">2024</span><!-- 题目算法标签 --><span data-v-71731098=\"\" class=\"lfe-caption\" style=\"color:#FFFFFF; background:#2949B4;\">线性代数</span><!-- 特殊题目标签 --><span data-v-71731098=\"\" class=\"lfe-caption\" style=\"color:#FFFFFF; background:#F39C11;\">O2优化</span><!-- 题目来源区域 --><span data-v-71731098=\"\" class=\"lfe-caption\" style=\"color:#FFFFFF; background:#52C41A;\">四川</span> 对应CSS: 123456789101112.lfe_caption { font-size: 0.875em;}span[data-v-71731098] { display:inline-block; padding:0 8px; box-sizing:border-box; font-weight:400; line-height:1.5; border-radius:2px} AcWing风格 简单 中等 困难 span标签: 12345<span class=\"label label-success round\">简单</span><span class=\"label label-warning round\">中等</span><span class=\"label label-danger round\">困难</span> 对应CSS: 12345678910111213141516171819202122232425262728.round { border-radius: 1020px;}.label { display: inline; padding: .2em .6em .3em; font-size: 75%; font-weight: 700; line-height: 1; color: #fff; text-align: center; white-space: nowrap; vertical-align: baseline; border-radius: .25em;}.label-success { background-color: #5cb85c;}.label-warning { background-color: #f0ad4e;}.label-danger { background-color: #d9534f;}","categories":[{"name":"开发记录","slug":"开发记录","permalink":"https://justpureh2o.github.io/categories/%E5%BC%80%E5%8F%91%E8%AE%B0%E5%BD%95/"},{"name":"博客搭建","slug":"博客搭建","permalink":"https://justpureh2o.github.io/categories/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/"}],"tags":[{"name":"博客","slug":"博客","permalink":"https://justpureh2o.github.io/tags/%E5%8D%9A%E5%AE%A2/"},{"name":"前端","slug":"前端","permalink":"https://justpureh2o.github.io/tags/%E5%89%8D%E7%AB%AF/"},{"name":"后端","slug":"后端","permalink":"https://justpureh2o.github.io/tags/%E5%90%8E%E7%AB%AF/"},{"name":"开发记录","slug":"开发记录","permalink":"https://justpureh2o.github.io/tags/%E5%BC%80%E5%8F%91%E8%AE%B0%E5%BD%95/"}]},{"title":"闫氏DP 学习笔记","slug":"yans-dp-learning-notes","date":"2024-02-19T20:15:55.881Z","updated":"2024-02-22T02:41:54.933Z","comments":true,"path":"yans-dp-learning-notes/","link":"","permalink":"https://justpureh2o.github.io/yans-dp-learning-notes/","excerpt":"","text":"说在前面 本博客中“闫氏DP”指的是2011年NOI金牌保送北京大学计算机系的算法选手闫学灿(yxc/y总)在教授动态规划时提出的“从集合角度分析DP问题的思维方式”。并非指代某类动态规划题型、也不是某种求解动态规划的固定算法。该文章仅作“闫氏DP”的学习笔记,一并附上例题的个人理解。为了使文章生动有趣,后文使用“yxc”或“y总”指代闫学灿本人。 代码均经过本人实际测试AC后才给出,代码总耗时也会给出,以AC记录的时间为准。代码由CLion格式化。 了解动态规划 了解DP的大佬可以直接看到下一节~ 什么是动态规划 动态规划(Dynamic Programming,简称DP)是运筹学的一个分支,用于求解多决策过程的最优解,最初由Bellman等人提出。当一个过程存在多个决策,且每个决策之间都会互相影响(最终影响到结果)时,就可以考虑使用动态规划。动态规划建立在递推关系之上,主张用已有的状态去表示未知的状态。正因如此,找出各个决策所产生的状态之间的关系是至关重要的(这个重要信息后期会被转译为状态转移方程求解DP)。 常见的动态规划根据问题的特点,分别被称作:线性DP,背包,树上DP,区间DP,数位DP,插头DP…… 传统DP分析法 DP自诞生之初就用来解决多决策过程问题,解决多决策问题就需要考虑如下性质,这些也是传统动态规划所考虑的角度: 状态:相当于 dp[i][j]所表示的意义,各个状态之间有内在的联系 无后效性:第个状态仅由第个状态决定,而不是其他的任何状态 最优子结构:把最优解拆开成一个个小部分,每个组成最优解的部分也一定是最优的 这样的传统方法看起来比较抽象,但这种方法的确是DP问题的标准解法,因为上述几种性质组成一个完整的动态规划问题。自然针对其组成部分提出的解决方案是最为标准的。 闫氏DP分析法 这张图(讲课板书)很清晰的阐明了闫氏DP分析法的内核,其中动态规划问题的求解依赖于状态的表示和计算,而搞清楚状态表示又需要读题分析需要规划的总集合、以及问题的属性。这个基本框架在求解DP问题中发挥了极其重要的作用。 状态计算里有一个非常重要的地方——搞清楚“前驱状态的转移”。就是需要解释清楚当前的状态是怎么由前面一个状态得到的。虽然说起来用不了几个字,但是这也是DP问题的难点,毕竟转移方程是DP问题的灵魂,得到了方程整个问题也就解决了。 线性DP 迷宫型 线性DP P1216 数字三角形 题目传送门 难度:普及- 观察下面的数字金字塔。 写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。 在上面的样例中,从的路径产生了最大权值。 这个题似乎连读入都要好好想一想 定义一个二维 map数组,map[i][j]表示第层从左数第个数,所以实际读入的数组输出出来会与上图有一些差别,为了与读入保持一致,使用下面给出的数组进行思考: 1234573 88 1 02 7 4 44 5 2 6 5 我们需要解决的问题的总集合就是从第一层走到第五层的可能路径,而属性就是 max(最大值)。这些都是读题能找出来的东西。 接着思考状态表示:摸清楚前驱状态。如果按照正向思维,从上往下遍历(第一次在第一层、第二次在第二层),会有一个问题——不知道前驱状态。那我们就反着来,由最下层向最上层遍历! 既然向上遍历,我们就脑补一下——把题图里面所有的箭头反向。这样一来上层的总和就可以用下边的点之和来转移了。例如倒数第二层的,表示出来就是 dp[4][2];它可以用下层的或得来,分别对应 dp[5][2]和 dp[5][3]。推广一下就是 dp[i][j]可以由 dp[i + 1][j]和 dp[i + 1][j + 1]得来,结合先前所述的状态表示,得出状态转移方程:dp[i][j] = max(dp[i + 1][j], dp[i + 1][j + 1]) + map[i][j]。那么这个最大和从下边一路推到最上边,到达点(顶点)时显然就是整个问题的解,因此最后输出 dp[1][1]即可。 最后是初始化:明显地,dp数组的最后一层应该全部赋值为 map数组的最后一层,这样才能让整个算法基于金字塔的最底端进行递推,得到正确答案(或者可以直接用 map数组计算)。 123456789101112131415161718192021222324#include <bits/stdc++.h>#define N 1010using namespace std;int dp[N][N], mp[N][N];int main() { int r; cin >> r; for (int i = 1; i <= r; i ++) { for (int j = 1; j <= i; j ++) { cin >> mp[i][j]; } } for (int i = 1; i <= r; i ++) dp[r][i] = mp[r][i]; // 初始化最后一层 for (int i = r - 1; i >= 1; i --) { // 反着扫每一层 for (int j = 1; j <= r - 1; j ++) { // 每一列 dp[i][j] = max(dp[i + 1][j], dp[i + 1][j + 1]) + mp[i][j]; } } cout << dp[1][1] << endl; return 0;} 由于命名冲突,原文中 map数组实为 mp数组。 总用时: 记录 AcWing1015 摘花生 原题地址:AcWing1015(原AcWing1017) 难度:简单 不知道为什么听课的时候y总说是1017现在变成1015了(但网址还是1017)……可能是题库变动,前面少了两道题吧…… Hello Kitty想摘点花生送给她喜欢的米老鼠。 她来到一片有行列的网格状道路的矩形花生地(如下图),从西北角进去,东南角出来。 地里每个道路的交叉点上都有种着一株花生苗,上面有若干颗花生,经过一株花生苗就能摘走该它上面所有的花生。 Hello Kitty只能向东或向南走,不能向西或向北走。 问Hello Kitty最多能够摘到多少颗花生。 1.gif 这道题属于经典的“走方格最值型线性DP”(自己瞎起的名字),很多DP题目里都有它的影子。例如洛谷 P1176 路径计数2、洛谷 P1958 上学路线和AcWing 1018 最低通行费。 首先读入整个地图,用数组w存储每个点的花生数(点权)。 接下来解题:状态表示,读题——总集合是从点(左上角)走到点(右下角)的所有路径,属性则是max。 接下来是状态计算,既然全集是所有合法路径,那我们如何划分这个“合法路径集”呢? 再读题,它说:“只能向东或向南走”。对应到方向标(上北下南左西右东),那就是只能向右或向下走(不走回头路)一直到右下角。假如她某次移动到了点(),那么她可能是从点或者是过来的。既然如此,将两条支路的数据汇集起来,取一个最大值max,不就是整道题的答案吗?因而,状态转移方程就是dp[i][j] = max(dp[i - 1][j] + w[i][j], dp[i][j - 1] + w[i][j]),等价于dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + w[i][j]。由于递推是正向的,到点结束,因此最终输出dp[r][c]。 当我们高高兴兴写代码的时候就会发现一些问题:如果我在第一列(最左边那一列),按照转移方程,左侧的点将会汇入计算,但第一列左侧的点并不存在;同理,第一行(最上边那一行)的上侧的点也不存在。那么该怎么样处理这样的特殊情况呢? 一般来说,OIer在开数组存值时,会从下标开始——但是在计算机中,一个数组真正的下标从开始。因此可以考虑在第一列和第一行的左侧和上侧点在w数组中设为-INF(和负数均可),总之让它们成为“虚点”,对整体结果无实际影响就行。或者在循环中写入特判第一列和第一行的情况,两种方案均可。我选择了比较方便的填充特殊值法,代码在下边给出: 1234567891011121314151617181920212223242526272829303132// 给地图外部的行/列赋特殊值#include <bits/stdc++.h>#define INF 0x3f3f3f3f#define N 110using namespace std;int dp[N][N], w[N][N];int main() { int T, r, c; cin >> T; while (T--) { cin >> r >> c; for (int i = 1; i <= r; i++) { for (int j = 1; j <= c; j++) { cin >> w[i][j]; } } // 初始化特殊行/列 for (int i = 0; i <= r; i++) w[0][i] = -INF; for (int i = 0; i <= c; i++) w[i][0] = -INF; for (int i = 1; i <= r; i++) { for (int j = 1; j <= c; j++) { dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + w[i][j]; } } cout << dp[r][c] << endl; } return 0;} 当然,这道题也可以不填充特殊值,因为全局定义的数组在内存中的默认值就是0,但为了保险这里还是加上了负无穷的填充。 总用时: 记录 P1004 方格取数 题目传送门 难度:普及+/提高 来源:NOIp 提高组 2000 2008年NOIP官方送来的双倍经验,请注意查收:P1006 传纸条 设有 的方格图 ,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 。如下图所示(见样例): 某人从图的左上角的 点出发,可以向下行走,也可以向右走,直到到达右下角的 点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字 )。 此人从 点到 点共走两次,试找出 条这样的路径,使得取得的数之和为最大。 输入的第一行为一个整数 (表示 的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的 表示输入结束。 数据范围:。 好家伙,两次DP???我们就选择用一个DP数组记录两条路径,同时遍历寻找最优解,最后输出即可。 状态表示就很明朗了,全集是两条从点走到点的路径可能性,属性是max。在状态计算方面,我们选用dp[i1][j1][i2][j2]表示第一条路线从走到了当前的;第二条路线从走到了当前的。这样来看,我们就只需要判断路径重合的情况:当时两条路径有可能重合。既然是「有可能」,那也就是说存在误判的情况失手了口牙。这里,y总引入了一个新变量,并使上式中的,如此操作,就可以删去dp数组的和,转而用dp[k][i1][i2]表示,移项可得。因为DP操作仅限于这个的方阵中,所以取值范围,最大值就是到达右下角的,因此(严格来说,)。关于的循环应该是从开始一直到才对。 然后考虑状态之间的转移,就需要找到当前状态和上一个状态之间的联系。dp数组存储了两条路径,第一条路径可能从左侧过来、同时第二条路径也可能从左边过来;第一条从左边来、第二条从上边来;第一条从上边来、第二条从左边来;最后是两条都从上边来的情况。我们显然需要计算出这四种情况的状态后对所有状态联合取最大值,以第一种情况为例:两条都从左边来,那么就是从来的;如果是第二种情况,那么由过来、由来,该情况写成转移方程就是dp[k][i1][i2] = max(dp[k][i1][i2], dp[k - 1][i1][i2] + w[i1][j1] + w[i2][j2])。 最后是重合路径的问题,当唯一确定,时,,所以,两点重合。所以当循环内出现的情况时直接抛除就好。状态转移方程里面也不能按w[i1][j1] + w[i2][j2]加和而是需要按w[i1][j1]进行累加。注意判断和是否都在地图范围内。 123456789101112131415161718192021222324252627282930313233343536373839#include <bits/stdc++.h>#define N 15using namespace std;int dp[2 * N][N][N], w[N][N];int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int n; cin >> n; int x = 1, y = 1, d = 1; while (x || y || d) { // 谨防毒瘤数据权值出成0!!! // 我也不知道权值会不会是0……保险保险 cin >> x >> y >> d; w[x][y] = d; } for (int k = 2; k <= 2 * n; k++) { // 注意k的取值范围 for (int i1 = 1; i1 <= n; i1++) { for (int i2 = 1; i2 <= n; i2++) { int j1 = k - i1, j2 = k - i2; if (1 <= i1 <= n && 1 <= i2 <= n && 1 <= j1 <= n && 1 <= j2 <= n) { int val = (i1 == i2) ? w[i1][j1] : w[i1][j1] + w[i2][j2]; // 判断是否重合 int &current = dp[k][i1][i2]; // 设置引用缩减码量 current = max(current, dp[k - 1][i1][i2] + val); // 两条都从上边来 current = max(current, dp[k - 1][i1][i2 - 1] + val); // 第一条从上边来,第二条从左边来 current = max(current, dp[k - 1][i1 - 1][i2] + val); // 第一条从左边来,第二条从上边来 current = max(current, dp[k - 1][i1 - 1][i2 - 1] + val); // 两条都从左边来 } } } } cout << dp[2 * n][n][n] << endl; return 0;} 总用时: 记录 来都来了,顺便放一下传纸条的代码,两道题思路是相同的(状态转移方程都不需要改!),但是读入有点恶心,一定注意读入问题! 12345678910111213141516171819202122232425262728293031323334353637383940#include <bits/stdc++.h>#define N 110using namespace std;int dp[2 * N][N][N], w[N][N];int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int n, m; cin >> n >> m; // 注意读入问题 for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { int d; cin >> d; w[i][j] = d; } } for (int k = 2; k <= m + n; k++) { // 注意k的取值范围 for (int i1 = 1; i1 <= n; i1++) { for (int i2 = 1; i2 <= n; i2++) { int j1 = k - i1, j2 = k - i2; if (1 <= i1 <= n && 1 <= i2 <= n && 1 <= j1 <= m && 1 <= j2 <= m) { int val = (i1 == i2) ? w[i1][j1] : w[i1][j1] + w[i2][j2]; // 判断是否重合 int &current = dp[k][i1][i2]; // 设置引用缩减码量 current = max(current, dp[k - 1][i1][i2] + val); // 两条都从上边来 current = max(current, dp[k - 1][i1][i2 - 1] + val); // 第一条从上边来,第二条从左边来 current = max(current, dp[k - 1][i1 - 1][i2] + val); // 第一条从左边来,第二条从上边来 current = max(current, dp[k - 1][i1 - 1][i2 - 1] + val); // 两条都从左边来 } } } } cout << dp[m + n][n][n] << endl; return 0;} 总用时: 记录 子序列型 线性DP 子序列问题 概述 子序列指在原序列中,在不改变元素之间的相对顺序的前提下,从中抽取出的元素组成的序列。例如数列1 4 5 6 7 8,1 5 7 8就是原序列的一个长度为的子序列,特殊地,原序列本身也是它的一个子序列。根据子序列元素之间的大小关系,大致分为“上升型”、“不下降型”、“下降型”和“不上升型”,分别对应前后元素是小于、小于等于、大于和大于等于的关系。在引入第二个序列的情况下,问题还可以进阶成为“公共子序列问题”,公共子序列正如其名:若某序列是两个及以上的序列的子序列,那么这个序列就是后者的公共子序列。 线性DP可以用于求解符合以上特点的子序列的最长长度,在的复杂度内得出结果,某些子序列计算可以通过贪心进行优化,最快可到级别。在竞赛中通常以英文缩写称之,例如最长上升子序列LIS、最长公共子序列LCS和二者的融合——最长上升公共子序列LCIS问题。 洛谷 B3637 最长上升子序列 LIS 题目传送门:B3637 最长上升子序列 难度:普及- 来源:NOIp 提高组 2004 这是一个简单的动规板子题。 给出一个由 个不超过 的正整数组成的序列。请输出这个序列的最长上升子序列的长度。 最长上升子序列是指,从原序列中按顺序取出一些数字排在一起,这些数字是逐渐增大的。 甚至你有可能都没见过B开头的洛谷题……在题库上端的“入门与面试”选项卡里,你可以找到B开头的题 在子序列DP的思考中,通常对DP的全集有一个比较跳脱常理的思维,通常让dp[i]作为以a[i]结尾的某类型子序列的最长长度。而子序列问题的状态集合属性也自然而然就是max了。 那么假设此时DP进行到了第项(),为了得出状态转移方程,我们聚焦到dp[i]的前一项,也就是dp[i - 1]。搞明白在什么情况下dp[i - 1]才能转化为dp[i]。不难发现,解决LIS问题,核心就是保证后一项的数严格大于前一项的数。于是当时,我们就可以将纳入最长子序列的计数中,也就是dp[i] = dp[i - 1] + 1。 对于dp数组初始化,因为每个元素本身就是原序列的一个长度为1的上升子序列,所以必须让dp数组的每个位置都初始化成。在最后,因为我们也不知道以第几个元素为结尾的上升子序列可以取到最大长度,因此我们还需要从头到尾扫一遍取最大值。代码给出: 1234567891011121314151617181920212223242526#include <bits/stdc++.h>#define N 5010using namespace std;int dp[N], a[N];int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= n; i++) dp[i] = 1; for (int i = 1; i <= n; i++) { for (int j = 1; j < i; j++) { if (a[j] < a[i]) dp[i] = max(dp[i], dp[j] + 1); } } int ans = -1; for (int i = 1; i <= n; i++) ans = max(ans, dp[i]); cout << ans << endl; return 0;} 总用时: 记录 洛谷 P1091 合唱队形 题目传送门:这里 难度:普及/提高- 位同学站成一排,音乐老师要请其中的 位同学出列,使得剩下的 位同学排成合唱队形。 合唱队形是指这样的一种队形:设 位同学从左到右依次编号为 … ,他们的身高分别为 … ,则他们的身高满足 … 。 你的任务是,已知所有 位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。 输入共二行。 第一行是一个整数 (),表示同学的总数。 第二行有 个整数,用空格分隔,第 个整数 ()是第 位同学的身高(厘米)。 对于全部的数据,保证有 。 样例输入 128186 186 150 200 160 130 197 200 样例输出 4 要想出列的人最少,留下的人必须最多!废话 那么如何保证留下的人最多呢?读题,要求是让整个队形变成先升后降的形式。我们不妨将样例输入进行一次可视化: 题目想让我们把这张图变成左边上升右边下降的样子,形状酷似山峰,因此我称之为山峰模型。联系到刚才所说,需要让留下的人最多。我们在选择C位同学时就需要注意一下,让他左侧留下的人最多、而不是一定要让最高的站中间。这下就很明朗了,我们先正向(从左至右)做一遍LIS问题,就知道让哪个人站C位可以使得Ta左边的人出列最少。那么还差右边的人,怎么办呢?我们会发现如果将整个序列倒序一下(水平翻转),那么原先的右侧就变为现在的左侧,原先让右侧单调下降,现在就变成了左侧单调上升,也就是和处理左侧同样的思路。于是我们就对原序列跑一遍LIS,再对反向的序列跑一遍LIS。最后统计一下每个点跑两次LIS后结果的总和(对应留下的人的人数),找出总和最大的那个就好了。至此我们已经成功将这个问题转化为两次异向LIS问题了! 最后有一点小细节,是关于最终结果的。样例输入的原理是将中间那个身高两米(176cm小矮个瑟瑟发抖)的设为C位,让左侧150cm和任意一个186cm、右侧197cm和200cm的人出列(注意是保证严格上升,因此若连续二者身高相等则不计入LIS计数)。答案就是。可以发现中间200cm的同学,正向LIS的结果是、反向LIS的结果是。但是,少了一个人去哪了——这是因为正反向LIS都算入了一次那个两米的同学,根据容斥原理,多算一次,就要减去一次,实际留下的人数是人,答案就是人。 代码如下: 1234567891011121314151617181920212223242526272829303132333435#include <bits/stdc++.h>#define rev(x) n - x + 1#define N 5010using namespace std;int dp[N], rev_dp[N];int a[N];int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= n; i++) { dp[i] = 1; for (int j = 1; j < i; j++) { if (a[j] < a[i]) dp[i] = max(dp[i], dp[j] + 1); } } reverse(a + 1, a + n + 1); for (int i = 1; i <= n; i++) { rev_dp[i] = 1; for (int j = 1; j < i; j++) { if (a[j] < a[i]) rev_dp[i] = max(rev_dp[i], rev_dp[j] + 1); } } int ans = -1; for (int i = 1; i <= n; i++) ans = max(ans, dp[i] + rev_dp[rev(i)]); cout << n - (ans - 1) << endl; return 0;} 总用时: 记录 洛谷 P2782 友好城市 题目传送门:这里 难度:普及/提高- 有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置各不相同的 个城市。北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同。每对友好城市都向政府申请在河上开辟一条直线航道连接两个城市,但是由于河上雾太大,政府决定避免任意两条航道交叉,以避免事故。编程帮助政府做出一些批准和拒绝申请的决定,使得在保证任意两条航道不相交的情况下,被批准的申请尽量多。 输入第一行,一个整数 ,表示城市数。 输入第二行到第 行,每行两个整数,中间用一个空格隔开,分别表示南岸和北岸的一对友好城市的坐标。 输出仅一行,一个整数,表示政府所能批准的最多申请数。 样例输入 12345678722 42 610 315 129 817 174 2 样例输出 14 数据范围 对于 的数据,,。 对于 的数据,,。 样例看起来不是那么直观,考试时可以考虑用画图软件增强样例可读性,样例画成图就是下边这样: 样例输出为,意味着我们需要删去条边,分别是边、和。为了探寻普遍规律,我们分离部分相交的航道来看一看,寻找相交线与河岸两头编号的规律。 我将北岸城市所连接的南岸城市的编号以深蓝色字体标在了对应北岸城市的下方,这下就可以看出端倪了:北岸城市从左至右,当底部蓝色数字单调上升时,航线不会交叉;反之若出现破坏单调性的蓝色数字,就代表航线交叉。但这个不完全归纳出来的结论还是欠缺证据支撑,对于北岸城市,编号单调递增,也就是说若航线以北岸城市为起点,那么起点处航线是绝对不会相交的;但是对于整条航线,它在整条河上是连续不断的——比如上图中蓝色数字和,表明北四号城市连接了一个很远的南二十二号城市;下一个是北十二号城市,连接南十五号城市。整条航线在河上连续不断,意味着航线总会在河上有一个正对南四~二十二号城市的点,此时当航线出现时,它们总会在某处相交。南岸证明同理。至此就证明了这个单调递增规律的问题,因此我们就想办法把南北岸城市的编号一一对应起来,接着跑一遍LIS,就可以解出答案了。 这里介绍一下C++的pair:pair是一个二元组,在定义时传入第一参数和第二参数的数据类型,类似于vector的定义,它们也用一对尖括号包裹。特定类型的pair,例如pair<int, int>、pair<double, double>、pair<float, float>等,在sort函数中可以自动按第一参数排序。这里我们选择双int型pair来存储南北城市的对应关系。代码如下: 123456789101112131415161718192021222324252627282930#include <bits/stdc++.h>#define N 200010using namespace std;typedef pair<int, int> coord;int dp[N];coord a[N];int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i].first >> a[i].second; sort(a + 1, a + n + 1); for (int i = 1; i <= n; i++) { dp[i] = 1; for (int j = 1; j < i; j++) { if (a[j].second < a[i].second) dp[i] = max(dp[i], dp[j] + 1); } } int res = -1; for (int i = 1; i <= n; i++) res = max(res, dp[i]); cout << res << endl; return 0;} 总用时:TLE 记录 注意到这里的数据范围:前50%没有问题,重点是后50%,它们的。LIS的时间复杂度是,早T飞了。不过AcWing对应的例题的数据没有洛谷上这么强,在AcWing 1012 友好城市里可以用LIS代码AC,后者的数据范围是。要想通过洛谷的友好城市,就必须用贪心等其他优化方式将时间复杂度降到对数级别才行……画大饼画大饼 AcWing 1016 最大上升子序列和 题目传送门:这里 难度:简单 最大上升子序列和,又称MASS(Maxiumum Ascending Subsequence Sum)问题。是LIS问题的一种变式,它不再是只局限于上升子序列的最长长度、而是开始关注选定子序列的元素之和。MASS问题其实可以拆分为两个子问题求解,其一是上升子序列问题、其二是最大和问题。上升子序列无需多言,其本质是在循环内加上判断a[j] < a[i]来累加合法解个数。因此,如果想要再融合进最大值问题,我们就需要在状态转移那里改一下代码:考虑到LIS问题的dp数组记录的是合法解的个数,而每次找到一组合法解,答案只会累加;对于MASS问题,每次找到一组合法解,需要累加的是元素本身的权值,特殊情况,单元素组成子序列时,答案就是它本身的权值,因而初始化时需要把dp[i]设置成a[i]才对。 代码: 1234567891011121314151617181920212223242526#include <bits/stdc++.h>#define N 1010using namespace std;int dp[N], a[N];int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= n; i++) { dp[i] = a[i]; for (int j = 1; j < i; j++) { if (a[j] < a[i]) dp[i] = max(dp[i], dp[j] + a[i]); } } int res = -1; for (int i = 1; i <= n; i++) res = max(res, dp[i]); cout << res << endl; return 0;} 总用时: 记录 AcWing 1010 拦截导弹 题目传送门:这里 难度:简单 来源:NOIp 提高组 1999 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。 输入导弹依次飞来的高度,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。 输入仅一行,若干个整数,中间由空格隔开。 输出包含两行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。 样例输入 1389 207 155 300 299 170 158 65 样例输出 1262 保证导弹数量不超过 同样画图理解样例抽象派画师又要登场喽! 那么怎么做才是样例输出的解呢?很明显,把207和155单独提出来作为一个新系统;剩下的作为一个系统。也就是说最多能拦截除开207和155的其他六枚导弹,而新开了一个系统,所以总共是两个系统。 乍一看这很像一个求解最长单调不上升子序列的问题,但是它居然让我们求出系统的数量,这就很棘手了……所以我们需要一个两头兼顾的方法来解题: 当我们拿到这个序列,之后只会进行两种操作:第一种是将某个数接到已有的子序列之后、第二种是新开一个子序列。考虑到我们的目标之一是让新开的子序列尽量小,那我们就需要尽可能缩减第二种操作的执行次数——让尽可能多的数被归入子序列中,这样的话我们就需要让插入的数和插入前队尾的数尽可能接近才是,如此会让系统的利用率最大化(如果你是舰长总司令,拿到这种系统,你肯定不会轻易地让它拦截很低的导弹,这样只会降低系统利用率)。当然,我们也希望打头的元素尽量大一些,这样才会容纳进更多的元素。诶?这不就是贪心的思路吗?为了方便阅读,做归纳如下: 贪心过程:从前到后扫描每个数,并且: 如果现有的所有子序列的结尾都小于这个数,显然不能插入,就开新序列(创建新系统) 如果存在合法(符合题意且当前元素可插入队尾)的子序列,遍历队尾元素,找到和当前元素最相近的那个队尾对应的子序列插入 代码: 123456789101112131415161718192021222324252627282930313233#include <bits/stdc++.h>#define N 1010using namespace std;int dp[N], a[N], b[N];int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int n = 1; while (cin >> a[n]) n++; n--; int lis = -1; for (int i = 1; i <= n; i++) { dp[i] = 1; for (int j = 1; j < i; j++) { if (a[j] >= a[i]) dp[i] = max(dp[i], dp[j] + 1); } lis = max(lis, dp[i]); } int cnt = 0; for (int i = 1; i <= n; i++) { int tmp = 0; while (tmp < cnt && b[tmp] < a[i]) tmp++; b[tmp] = a[i]; if (tmp >= cnt) cnt++; } cout << lis << endl << cnt << endl; return 0;} 总用时: 记录 补 贪心优化子序列问题 正常做子序列问题的时候,由于要枚举每一个可能的状态,因此需要循环级别次,时间复杂度也就来到了惊人的(大多数题目的暴力算法都是这个复杂度),当时就TLE了,更别说更加毒瘤的数据了……好在对于最值子序列问题,人们提出了贪心法,可以将复杂度降落到对数级别,一般是(某些题用特定的数据结构还可以降到复杂度)。是一种极其高效的优化方式。 补 DFS暴搜求解最值问题 有些时候,就算是贪心也不能解决某些DP的决策问题。转而寻找与普通DP时间复杂度相近的替代方案——DFS暴搜。我们都知道,宽搜BFS常用于求解这类最值问题(尤其是最小步数),是因为BFS的实现基于对图的按层遍历;但是DFS就不太一样了,它不撞南墙不回头、有时还会爆栈(递归过深)……但是面对DP问题这样的一个根节点连巨多子节点的情况,BFS在压入每层节点时也会爆空间,而且DFS剪枝会比较容易……接下来用一个例题详解DFS暴搜的基本原理。 AcWing 187 导弹防御系统 题目传送门:这里 难度:简单 为了对抗附近恶意国家的威胁,国更新了他们的导弹防御系统。 一套防御系统的导弹拦截高度要么一直 严格单调 上升要么一直 严格单调 下降。 例如,一套系统先后拦截了高度为和高度为的两发导弹,那么接下来该系统就只能拦截高度大于的导弹。 给定即将袭来的一系列导弹的高度,请你求出至少需要多少套防御系统,就可以将它们全部击落。 输入包含多组测试用例。 对于每个测试用例,第一行包含整数,表示来袭导弹数量。 第二行包含个不同的整数,表示每个导弹的高度。 当输入测试用例时,表示输入终止,且该用例无需处理。 对于每个测试用例,输出一个占据一行的整数,表示所需的防御系统数量。 样例输入 12353 5 2 4 10 样例输出 12 样例解释 对于给出样例,最少需要两套防御系统。 一套击落高度为的导弹,另一套击落高度为的导弹。 数据范围 样例已经解释过了,就不画图了……您的抽象派画师先生已下线 要么上升要么下降……其实在导弹拦截这里已经介绍过贪心的思路。这道题只是在那道题的基础上,在贪心的外部再加入一个选择上升还是下降的贪心。哦豁,不太好搞了——开局要做一个单选,每个选项下又有选项脑袋抓破,此时试着用高雅的暴戾算法DFS搜索来解决这个DP问题。 我们的目标是让系统数尽可能少节约开支,在DFS的处理过程中也要贯彻最小值的思想,但正如开头所说,DFS毕竟是不撞南墙不回头的搜索方式,怎么做才能让DFS具备BFS的最小值处理能力呢?有两种方法:记录全局最小值和迭代加深。 实现方法一 全局记录最值 设计DFS函数时,引入三个参数:当前点的下标(DFS必备)、以该点结尾最长上升子序列的长度、以该点结尾最长下降子序列的长度。函数签名就像这样:void dfs(int idx, int lis, int lds)(LDSLongest Decreasing Subsequence,最长下降子序列)。","categories":[{"name":"oi算法","slug":"oi算法","permalink":"https://justpureh2o.github.io/categories/oi%E7%AE%97%E6%B3%95/"}],"tags":[{"name":"算法","slug":"算法","permalink":"https://justpureh2o.github.io/tags/%E7%AE%97%E6%B3%95/"},{"name":"oi","slug":"oi","permalink":"https://justpureh2o.github.io/tags/oi/"},{"name":"dp","slug":"dp","permalink":"https://justpureh2o.github.io/tags/dp/"},{"name":"学习笔记","slug":"学习笔记","permalink":"https://justpureh2o.github.io/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"}]},{"title":"洛谷 陌路寻诗礼 题解","slug":"i-love-furina-instead","date":"2024-02-19T01:44:37.366Z","updated":"2024-02-19T19:22:58.270Z","comments":true,"path":"i-love-furina-instead/","link":"","permalink":"https://justpureh2o.github.io/i-love-furina-instead/","excerpt":"","text":"题目传送门:P10178 受到了题面的启发,我才想起那个早已死去的算法——SPFA 题面总结成一句话就是:最短路只能有一条。 那么我们用最短路算法:如果有最短路,先选择最短路。如果在更新最短值时出现了冲突——即某两种方案路径长度相等时,让后来者考虑加上一个 范围内的值,使它变长、不再是最短路(退出奖牌争夺)就好了。 对于加上的正整数值,不妨从 开始加。不够就加上 ,还不够就加上 ,以此类推……在经历若干次最短路淘汰后,如果边权加上 仍然不能满足最短路唯一的硬性需求时,代表这组数值根本就是无解的,因此需输出No。反之将试加的值记录到ans数组中去,在每组数据结束后输出即可。 同时请注意多测清空! 代码,但是 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970#include <bits/stdc++.h>#define N 300010using namespace std;int k;int h[N], to[N], ne[N], ans[N], dis[N];bool st[N];int idx = 0;void add(int u, int v) { idx++; to[idx] = v; ne[idx] = h[u]; h[u] = idx;}bool spfa() { queue<int> q; q.push(1); dis[1] = 0; st[1] = true; while (!q.empty()) { int top = q.front(); q.pop(); for (int i = h[top]; ~i; i = ne[i]) { int j = to[i]; if (top == j) { ans[i] = k; continue; } int trial = 1; if (dis[j] > dis[top] + trial) { dis[j] = dis[top] + trial; if (!st[j]) q.push(j), st[j] ^= 1; } else if (dis[j] == dis[top] + trial) trial++; if (trial > k) return false; ans[i] = trial; } } return true;}int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int t, n, m; cin >> t; while (t--) { memset(dis, 0x3f, sizeof dis); memset(h, -1, sizeof h); memset(st, 0, sizeof st); idx = 0; cin >> n >> m >> k; for (int i = 1; i <= m; i++) { int u, v; cin >> u >> v; add(u, v); } if (spfa()) { cout << \"Yes\\n\"; for (int i = 1; i <= m; i++) cout << ans[i] << ' '; } else cout << \"No\"; cout << endl; } return 0;} 这段代码居然一反常态的在第一组测试点处TLE了???于是重新看到数据范围——,发现竟然是清空的memset出了问题!当你定义了一个大小为 的数组时,调用memset的结果就是对这整个 的空间进行内存赋值,而且估计第一组测试点出了一个比较大的询问个数 ,导致TLE。 解决方案就是从 循环到 清空,避免不必要的性能浪费 代码 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172#include <bits/stdc++.h>#define N 300010using namespace std;int k;int h[N], to[N], ne[N], ans[N], dis[N];bool st[N];int idx = 0;void add(int u, int v) { idx++; to[idx] = v; ne[idx] = h[u]; h[u] = idx;}bool spfa() { queue<int> q; q.push(1); dis[1] = 0; st[1] = true; while (!q.empty()) { int top = q.front(); q.pop(); for (int i = h[top]; ~i; i = ne[i]) { int j = to[i]; if (top == j) { ans[i] = k; continue; } int trial = 1; if (dis[j] > dis[top] + trial) { dis[j] = dis[top] + trial; if (!st[j]) q.push(j), st[j] ^= 1; } else if (dis[j] == dis[top] + trial) trial++; if (trial > k) return false; ans[i] = trial; } } return true;}int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int t, n, m; cin >> t; while (t--) { cin >> n >> m >> k; for (int i = 1; i <= n; i++) { idx = 0; dis[i] = 0x3f3f3f3f; st[i] = false; h[i] = -1; ans[i] = 0; } for (int i = 1; i <= m; i++) { int u, v; cin >> u >> v; add(u, v); } if (spfa()) { cout << \"Yes\\n\"; for (int i = 1; i <= m; i++) cout << ans[i] << ' '; } else cout << \"No\"; cout << endl; } return 0;} 发现第一组数据跑得飞快,完全不见了方才TLE时的拖沓! 本蒟蒻第一篇题解,害怕~","categories":[{"name":"题解","slug":"题解","permalink":"https://justpureh2o.github.io/categories/%E9%A2%98%E8%A7%A3/"}],"tags":[{"name":"题解","slug":"题解","permalink":"https://justpureh2o.github.io/tags/%E9%A2%98%E8%A7%A3/"},{"name":"oi","slug":"oi","permalink":"https://justpureh2o.github.io/tags/oi/"}]},{"title":"OI 分块","slug":"oi-partitioning","date":"2024-02-17T16:19:26.709Z","updated":"2024-02-18T18:10:04.497Z","comments":true,"path":"oi-partitioning/","link":"","permalink":"https://justpureh2o.github.io/oi-partitioning/","excerpt":"","text":"何为分块 分块,正如其名,将一个整区间分为若干小区间进行操作。分块拥有比线段树更强的泛用性,但是时间复杂度略输一筹;分块代码更加直观、减少理解难度,但是时间复杂度稍逊风骚;分块的代码比线段树更短,但是时间复杂度惜败后者……线段树所上下传递的操作计算必须满足结合律,区间平均数、方差还行,像计算区间众数、中位数这样的问题,线段树就只能被薄纱了…… 考虑到树状数组理解难度较大、较难调试,一般都选用泛用性强、码量折中、效率及格、调试简便的分块算法求解。 如何分块 不同于线段树的二分存储,分块所使用的块状数组本质上只是一个带有块起始下标和块末尾下标的普通数组,就像在一列数中间插上分割线分出区块。对于区间修改操作,只需要进行以下几步就可以: 判断左端点l和右端点r所在的区块 若两个端点在同一个区块内:暴力循环更新值 若两个端点不在同一个区块内:在l所在区块内,从l开始循环至该区块结束,暴力更新值,相应的从r开始,往回循环至该区块起始处,暴力更新值,最后将二者中间整块的区块打上更新标记 我们会发现,分块其实就是将完全暴力的操作拆分成部分暴力的操作和部分取巧的操作。尽管看起来还是在使用暴力算法,但实际上优化了不少东西,而优化的效率还得取决于每个区块的长度。那么我们如何选择区块的长度呢? 最坏情况下,指定的左右端点就是整个数组的左右端点。假设总长度为,一般采取的区块长度是。这样一来,就有个整区块会被打上标记,而两头的区块(长度都为)暴力修改的复杂度是。这也就意味着分块是一种根号算法(时间复杂度是根号级别的算法),尽管它在时间复杂度上比不过线段树的。但是只要满足或者(为询问个数),基本上就不会TLE(1s)。 既然已经知道了的来历,我们对数组进行分块时就简单了。首先循环次用以记录区块的起点和终点,但是注意如果数组长度不为完全平方数就需要将最后一个区块(编号为的区块)的终点下标设为以免访问越界。开两个长度略大于的数组st和ed分别记录每个区块的起点下标和终点下标;加上一个查询数组bel,用于查找第个数所属的区块编号;同时为了避免后期访问到最后一个区块时出现下标越界RE的情况,再开一个长度的数组记录每个区块长度(也可以只开一个变量存,特判是否是最后一个区块即可)。接下来就可以循环遍历整个数组了: 这是求解区间和的一段代码,init()函数中,我们把每个区块的和存在sum对应下标处 123456789101112131415161718192021222324#include <bits/stdc++.h>#define N 1000010#define SQN 1010typedef long long ll;int st[SQN], ed[SQN], size[SQN], bel[SQN];ll a[N], tag[N], sum[N];void init() { int sq = (int) sqrt(n); for (int i = 1; i <= sq; i++) { st[i] = sq * (i - 1) + 1; ed[i] = sq * i; size[i] = ed[i] - st[i] + 1; } ed[sq] = n; size[sq] = ed[sq] - st[sq] + 1; for (int i = 1; i <= sq; i++) { for (int j = st[i]; j <= ed[i]; j++) { bel[j] = i; sum[i] += a[j]; } }} 按照如上所述的修改原理: 123456789void update(int l, int r, int x) { if (bel[l] == bel[r]) { for (int i = l; i <= r; i++) a[i] += x, sum[bel[i]] += x; } else { for (int i = l; i <= ed[bel[l]]; i++) a[i] += x, sum[bel[l]] += x; for (int i = st[bel[r]]; i <= r; i++) a[i] += x, sum[bel[r]] += x; for (int i = bel[l] + 1; i < bel[r]; i++) tag[i] += x; }} 询问区间和的原理比较相似,同样是分l和r所在区块进行讨论。只是当进行整体区块操作时,用与线段树相似的方法——将标记乘到总和中并累加即可。 1234567891011ll askSum(int l, int r) { ll res = 0; if (bel[l] == bel[r]) { for (int i = l; i <= r; i++) res += (a[i] + tag[bel[l]]); } else { for (int i = l; i <= ed[bel[l]]; i++) res += (a[i] + tag[bel[l]]); for (int i = st[bel[r]]; i <= r; i++) res += (a[i] + tag[bel[r]]); for (int i = bel[l] + 1; i < bel[r]; i++) res += (size[i] * tag[i] + sum[i]); } return res;} 以上求区间和的代码可以提交到洛谷 P3372 线段树模板 一里。与线段树相比,分块的速度慢了大约40ms,在300ms左右,还是可以接受的。","categories":[{"name":"oi算法","slug":"oi算法","permalink":"https://justpureh2o.github.io/categories/oi%E7%AE%97%E6%B3%95/"}],"tags":[{"name":"算法","slug":"算法","permalink":"https://justpureh2o.github.io/tags/%E7%AE%97%E6%B3%95/"},{"name":"oi","slug":"oi","permalink":"https://justpureh2o.github.io/tags/oi/"}]},{"title":"从零开始的桌面端音游开发 (一)环境","slug":"echorhy-dev-from-scratch-i","date":"2024-02-16T20:10:19.283Z","updated":"2024-02-16T22:09:57.264Z","comments":true,"path":"echorhy-dev-from-scratch-i/","link":"","permalink":"https://justpureh2o.github.io/echorhy-dev-from-scratch-i/","excerpt":"","text":"开发初衷 Phigros玩得太烂了(确信) 啊作为一名中学生最重要的还得是学习!学习为重是吧。想着开发一个C#窗口程序练练手,顺便涉足一下OpenGL图像渲染的领域。挺重要的一点是感觉自己还是太闲了,再加上PC端音游实在太少喽。就萌生了这个想法。 图形环境 整体基于C#的.NET窗体程序,搭配OpenGL进行图形渲染和绘制。OpenGL本身调用起来比较麻烦,涉及很多底层操作(类似于C/C++的窗体程序开发,代码里全是底层调用),所幸还是有能人志士对繁琐的过程做了简化,对底层的OpenGL进行了一定的函数封装,推出了稳定高效简洁的OpenGL支持库。这里主要有以下几种: SharpGL——部署安装方便、高版本OpenGL支持;但存在内存泄露问题、不支持Linux和Mac CsGL——轻量级、响应快;不支持高版本OpenGL、仅支持32位系统炸裂 OpenTK——部署安装方便、跨平台开发、响应快于SharpGL,但慢于CsGL Tao——C风格、支持库 这里选用OpenTK,综合来讲它的功能够用、开发文档也比较充足最重要我不喜欢C风格的库。若想将OpenTK部署到项目里,新建.NET窗体工程,在NuGet包管理器中搜索OpenTK,点击安装OpenTK.GLControl,这是OpenGL对应的控件包,其中包含了OpenTK库。安装完毕后就可以看到OpenTK控件了。 OpenTK 官方文档","categories":[{"name":"开发记录","slug":"开发记录","permalink":"https://justpureh2o.github.io/categories/%E5%BC%80%E5%8F%91%E8%AE%B0%E5%BD%95/"}],"tags":[{"name":"整活","slug":"整活","permalink":"https://justpureh2o.github.io/tags/%E6%95%B4%E6%B4%BB/"},{"name":"开发记录","slug":"开发记录","permalink":"https://justpureh2o.github.io/tags/%E5%BC%80%E5%8F%91%E8%AE%B0%E5%BD%95/"},{"name":"C#","slug":"C","permalink":"https://justpureh2o.github.io/tags/C/"}]},{"title":"Hexo云后台——Qexo搭建教程","slug":"qexo-deploy","date":"2024-02-14T17:52:57.521Z","updated":"2024-02-21T20:12:28.188Z","comments":true,"path":"qexo-deploy/","link":"","permalink":"https://justpureh2o.github.io/qexo-deploy/","excerpt":"","text":"在开始之前,首先你需要有一个自己的域名(github.io不算在内,你必须能够亲自更改DNS解析设置),并在博客仓库设置的Pages选项卡中绑定自己的域名。 部署Qexo环境 官方提供了四种方式来部署Qexo环境,其中一种允许你在本地进行部署,另外三种各自使用了不同网站提供的免费数据库服务。综合考虑操作便捷性和成功率,这里选用Vercel提供的免费PostgreSQL服务进行部署。 首先点击这里进入Vercel的仓库克隆界面。建议新建一个私有仓库进行Qexo仓库的克隆工作,第一次操作时你需要授权Vercel登录你的Github账号,在新跳出的浏览器窗口里按顺序授权即可。 设置好仓库名称后,点击Create创建,下边会有一个Deploy界面。Vercel在创建和更改仓库时会自动进行一次部署,因此创建完毕后部署将会自动启动,并且这第一次部署是一定会失败的。因为Qexo所依赖的数据库还没有配置。因此点击网页左上角的三角形符号,或者点这里快捷进入你的项目管理页面。不出意外的话,界面将是这个样子: (我这里是已经配置好了Qexo) 然后我们开始配置PostgreSQL数据库,在Storage界面可以申请,点击右上角Create Database并选择Postgres,Vercel的免费Postgre数据库仅限创建一个,如果你先前没有配置过——点击Continue进入数据库连接配置,在Connect界面选择地区为Washington DC或者USA (east)。创建完毕后,在Storage选项卡里选择进入你创建的数据库配置界面。在左侧边栏点击Project,接着点击Connect Project: 选择自己想要部署Qexo的仓库即可,接着回到项目管理界面,点击部署用的仓库。在Settings里面选择Domains域名选项,添加自己购买的域名。注意不要将域名指向到主页地址,如果你购买的主域名是abcd.xyz,此处建议绑定到它的子域名admin.abcd.xyz,而不能直接绑定到abcd.xyz!。 当你添加了一个目标域名后,Vercel会自动对填入的域名进行DNS检查,若第一次配置,大概率会出现以下情况: 此时你需要打开自己域名的DNS解析设置,添加一个A解析:主机记录为@,记录值为76.76.21.21。补充一句,这个IP地址指向vercel.app的域名服务器,然而这个域名已经处于DNS污染的状态,无法访问。Vercel的临时备用方案是将IP改成76.223.126.88,事实证明到现在这个方案还是有效的。 配置完部署域名后,转到顶端选项卡Deployment中点击Redeploy开始二次部署。一般等待一分钟左右无报错信息即可完成部署。 如果你使用的是MongoDB,有可能在二次部署开始三到四分钟后接收到部署失败的信息。如果失败信息里出现了类似于handshake failed的握手失败信息时,建议放弃该方法(很可能是国内墙掉了MongoDB的连接接口导致部署时无法访问)并转而使用上边介绍的PostgreSQL法重新部署。 查看其他部署具体步骤,见官方文档——部署;若部署时遇到报错,可以进入官方文档——常见问题排错。 初始化Qexo Github配置 部署完毕后,切换到绑定的域名,本例中我们转到admin.abcd.xyz。如果没有出现Qexo的初始化配置界面,试着转到admin.abcd.xyz/init/。如果你使用Hexo,并在Github上托管,在Github的配置界面,你会看到这几项: (这是已经配置好的Qexo的设置界面,只是我将填写的内容删去了,但是项目是完全一致的) Github密钥这一项,你需要在Github设置中申请。右上角选择Generate New Token,有两个选项,选择classic。接着完成身份验证。改变如下几项: Note必填,作为这个token的使用目的;Expiration是生效期限,安全起见建议设置一个较短的期限,然后定时重置,重新配置Qexo设置,这里我选择的是永久有效;在下边的生效条目里,保证repo下的复选框全部勾选,建议同时勾选workflow,但官方不建议给出所有权限。这么做的目的是保证Qexo有足够权限访问Github API从而在线修改Github博客源码的内容。 申请完毕后复制下来,出于安全,Github仅在token初次创建完毕后给出复制选项,所以尽快保存,并填入初始化界面的“Github 密钥”文本框中。 然后在Github里新建仓库,用于存放博客源码。接着在本地转到你的博客源码文件夹中(就是你执行hexo clean & hexo g & hexo d的文件夹),右键点击git bash here,依次键入以下的代码: (“查看”里勾选“显示隐藏的文件”后,若源码目录下没有名为.git的文件夹,有则跳过该步骤)git init 复制仓库的网页地址,例:https://github.com/<username>/<repo> 输入git remote add <name> https://github.com/<username>/<repo>.git(这里的<name>任取,但保证先前未创建过,且不与已经存在的<name>重复,否则将可能不会上传当前的文件夹) 输入git pull <name> master,master可更改,但保证和新建仓库的主branch同名 输入git add .(注意有个点) 输入git commit -m \"Commit内容\"(内容可更改,但需要用半角双引号包裹起来) 输入git push <name> master(master保持前后一致即可) 如果是第一次上传,按顺序执行以下七步操作;如果已经上传过了,想要提交一些个人的更改,执行第四到第七步即可。“Github 仓库”这一项就填刚刚创建并上传的源码仓库,格式是<username>/<repo>(例:mynameisabcd/BlogSourceCode)。 “项目分支”填源代码仓库的主要分支,一般是master;“博客路径”留空即可。 若使用Gitlab,或者想要通过本地进行初始化,见官方文档。 Vercel配置 “VERCEL_TOKEN”一项,需要在这里生成。 同样是填写token名称、生效范围(这里选择xxx's projetcs)和生效期限(建议期限短些)。完毕后点击Create生成密钥,也是需要尽快复制下来,粘贴到“VERCEL_TOKEN”里。 “PROJECT_ID”则需要回到Vercel对应的项目的Settings里,在General选项卡中向下翻到Project ID并复制内容,粘贴到PROJECT_ID中就完成Vercel配置了。 接下来你还需要设置管理员账号密码,设置完毕后就可以从admin.abcd.xyz快捷进入管理界面了。 其他设置 设置友链 在博客源码目录里打开命令行,输入hexo new page links创建友链页面,打开source/links/index.md,将front-matter修改成如下格式: 1234---layout: friends # 必须title: 我的朋友们 # 可选,这是友链页的标题--- 并且在front-matter后的正文部分直接粘贴: 12345<div id=\"qexo-friends\"></div><link rel=\"stylesheet\" href=\"https://unpkg.com/qexo-friends/friends.css\"/><script src=\"https://cdn.jsdelivr.net/npm/qexo-static@1.6.0/hexo/friends.js\"></script><script>loadQexoFriends(\"qexo-friends\", \"Qexo部署的网址\")</script> 需要更改“Qexo部署的网址”为你方才Vercel设置里填写的域名。 部分主题有专门的主题适配选项,详情见这里。 设置说说 在Hexo源代码根目录里新建页面hexo new page talks。 在source/talks/index.md中正文部分加入: 12345<div id=\"qexot\"></div><script src=\"https://cdn.jsdelivr.net/npm/qexo-static@1.6.0/hexo/talks.js\"></script><link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/qexo-static@1.6.0/hexo/talks.css\"><script>showQexoTalks(\"qexot\", \"Qexo部署的网址\", 5)</script> 同样是更改“Qexo部署的网址”,网址后的数字代表每页展示的说说个数,可根据需要自行调整。还可以美化样式。","categories":[{"name":"博客搭建","slug":"博客搭建","permalink":"https://justpureh2o.github.io/categories/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/"}],"tags":[{"name":"博客","slug":"博客","permalink":"https://justpureh2o.github.io/tags/%E5%8D%9A%E5%AE%A2/"},{"name":"后端","slug":"后端","permalink":"https://justpureh2o.github.io/tags/%E5%90%8E%E7%AB%AF/"},{"name":"qexo","slug":"qexo","permalink":"https://justpureh2o.github.io/tags/qexo/"}]},{"title":"信息竞赛 高级数学","slug":"oier-math-senior","date":"2024-02-13T19:02:49.000Z","updated":"2024-02-17T18:22:46.873Z","comments":true,"path":"oier-math-senior/","link":"","permalink":"https://justpureh2o.github.io/oier-math-senior/","excerpt":"","text":"诗曰: “高数第一杀手,考试一考就寄。复数知识一用,算成正一。朴素演算善后,死磕公式何必?考场信心十足,全错当场暴毙。” 前置知识:复数、位运算 Part1. 快速傅里叶变换 Div1. 世界上最优雅的算法 FFT起源 FFT的前身是DFT,可以简单看作是一堆OIer争先恐后对DFT算法进行优化的结果。美苏冷战期间,双方都对自己的核实力有所隐瞒,就等着某一天用自己的核导弹打对方个措手不及……在一次科学议会上,有人提出在苏联国境周边安装大量地震波传感器,将传感器的数据回收处理,分析是否出现了类似于核试验产生的震波从而判断苏联是否在进行秘密核试验。但是在当时用于频谱分析的DFT算法效率太过低下,传感器又必须在短时间内分析大量的频谱数据,因此逆境出人才——当时参与会议的其中一位科学家Tukey后来找到了程序员Cooley,后者在当时是一名操作ENIAC的程序员。二者分工明确,在1965年他们提出了FFT算法(当时叫做Cooley-Tukey算法),这个算法在后来被IEEE列入他们主编的“20世纪十大程序算法”之中。 FFT在信号处理领域受到了广泛的应用,直至今日它仍然被集成在大多数波谱分析仪器中作为底层算法之一。然而在信息学竞赛中,它被广大的OIer看中,拿去优化了高精度乘法的计算。它可以将朴素的高精度乘法的复杂度大幅降低到,在处理大数据时,它将比Karatsuba乘法算法更为高效…… Div2. 系数表示法与点值表示法 我们在初中时期学过一元二次方程的函数图像。一般情况下,我们都会用形如:的解析式形式来表示它。这种表示函数的方法就叫做系数表示法——自变量的某次幂前乘一个系数得到的,一个次多项式的系数表示法定义为:。 系数表示法可以直接通过值求出值,就好比生物的基因组排列,给出一个基因组,科学家就可以复原出整个生物的全貌,如果在各种函数绘制工具中输入解析式,它都唯一对应一个图像;但点值表示法就不是这样的了。它好比生物的某个性状,并且只是一个小得不能再小的特征点。比如给你两个特征:“白色毛发”和“部分呈现黑色”,不同人会做出不同的回答——动物学家会说“熊猫”、“斑马”、“美国短毛猫”一类的事物;阿宅会说:“伊雷娜”、“仆人”等等。加入其他限定词可能会使结果统一化,但是对于数学函数来说,你需要限定它的最高次数。如果你只给出了点,“求出经过点的二次函数”这样的问题显然是不合适的,因为次函数最少需要个不同的点来唯一确定。 假如我们让一个三次函数和一个四次方程相乘求卷积,得到的函数将会是一个七次函数。如果我们需要将系数转换为点值,需要取定义域上七个不相同的值进行计算,对于每次计算,要将值以不同次幂代入至多七个算式中求出值,显然时间复杂度是的。那还不如不优化 为了减少这里的复杂度,我们借助一点高一所学的奇偶函数的内容~(没学过/没学懂没关系,奇函数相当于关于原点对称、偶函数相当于关于轴对称,并且函数的取值范围也必须关于原点对称——假如能求出对应值,也必须能求出对应值)。 假如该函数是一个偶次的幂函数,幂函数的定义是。如果此处为偶数,整个函数就是一个偶函数、反之为奇函数。对于偶函数满足、奇函数。那么我们可以把原函数分解成多个偶函数和奇函数的和,例如: 函数 经过一轮拆分:。根据奇偶函数的性质:奇函数+奇函数=奇函数、偶函数+偶函数=偶函数。因此左边括号整体组成的函数是奇函数、右边括号整体组成的函数是偶函数,常数单独拆出来: 这张图可以直观看出原函数(绿线)被拆分成偶项(红线)、奇项(蓝线)和常数项(橙线)后的样子。 对于奇项,代任意,求出一个值后,第二个值直接取相反数;偶项则是相反,结果相同。当然只拆一次是不够的,里面还有很多项呢,我们试着把原函数拆分成只有一项,以递归计算。我们对奇项和偶项继续进行拆分 令,。但是此时和的取值变成了平方,相对应地,继续拆分一次,括号里的会变成。因此取相反数值不管用了(),我们急切地想要找到就算平方后也是相反数的一对数据来求值。此时高阶思维娃找到了一个东西——复数域。 Div3. 单位根 首先花一些篇幅来介绍复数的概念。我们学过:形如这样的的一元二次方程是无解的。这并不完全正确——严格来说是在实数范围内无解,这个问题自从几千年前、方程发明之初就引来了无数数学家的疑问与探索,人们找来找去就是为了能找到一个阿拉伯数字,让它的平方等于。很可惜,找不到,因为传统意义上的阿拉伯数字体系建立在实数基础上,又不在实数范围内,自然所有的尝试都会以失败告终。直到有一天,笛卡尔提出了虚数的概念,认为它是“不存在的数”、紧接着高斯使用虚数符号来表示的值,后面他又提出了“复平面”来将复数表示成平面上的一个向量。虚数这才有了立足之地。 而复数就像是实数和虚数的一次友好会面,复数域用字母表示,一个复数由实部和虚部组成。例如复数,它的实部是、虚部是。 紧接着,我们的FFT之旅就要来到下一个目的地——复平面。复平面类似于平面直角坐标系,只不过轴变成了实数、轴变成了虚数。复平面的轴因而称作实轴、轴称作虚轴,刚才的复数可以看作复平面上的一个向量。 比如说上一节遗留的式子,递归继续深入一层时,递归函数会变成。假如我们要让括号里的数是1,也就是这个函数在自变量为时的取值(事实上取成1恰好符合单位根的定义,于是就有简便的计算方式),我们就要解决的问题,而且还必须各不相同……两边同时开根号:。展开成方程组就是:,根据的数学定义,方程1解得,方程2解得。也就是:。 每次递归,函数括号中的参数的幂就会乘2。幂在数值上就是,解决次多项式的拆分需要给出个不同的值,因而递归层数满足如下关系:。因此原方程是七次方程,就需要递归三层,得到8个相异的,从而计算出8个点! 引入单位根的概念:满足的复数叫做次单位根。在复平面上,次单位根将复平面上的单位圆等分。回到上例中的四次单位根,它们在复平面上的分布如下图: 点和点恰好对应实数解,点与点对应复数解。 如果是八次()单位根,图像如下: 其中,对应复数,其余同理。由于次单位根相当于将单位圆平分为份,并且其中有一个解一定是(上图点)。联系到三角函数在单位圆中的表示,复平面单位圆上的点一定满足。因此若,则。 假如我们按逆时针方向,起始点(实轴)从0开始编号,并将八次单位根和四次单位根的图像作比较,可以导出单位根的两条性质(): (对应点关于原点对称) (单位根次数和编号同乘2,坐标相同) 特殊地,. 这下终于可以开始从一般例子出手推了。令。 按照奇偶项分为两组(这里可以直接通过的奇偶性判断),折半次数,递归层数为1——令奇项函数为,偶项函数为。(奇项提出一个避免出现小数次幂)、。将奇偶项的自变量设为以表示出原式,即未折半的函数的未知数的次数:。 函数的自变量来到了,令。该轮到单位根显神通了,令,此时的,根据上述单位根的两条性质,推出如下式子: ,根据第二条性质,次数编号同除以2,得到: ; 如果此时原式、根据第一条性质,以及特殊情况,代入,根据第二条性质,次数编号同除以2,得到: 。 正因此,当已知时,代入计算,那么当取时的值也就明确了(根据性质第二条直接求出)。和就可以将问题规模缩小一半,递归的边界就是。 Div4. IFFT与蝴蝶操作 IFFT的中文名称是快速傅里叶逆变换。有些人比如刚开始接触FFT的我认为只要敲出FFT的代码,就可以解决任何函数卷积的问题了……错了,FFT主要是将系数表示法转换为点值表示法,相当于数学考试解析式求解题题干里给你的已知点坐标!卷积之路才刚刚过半,接下来介绍如何将相乘后得到的点值表示法重新转化为系数表示法。由于FFT是系数到点值的转换、这种方式是点值到系数的转换,因而称之快速傅里叶逆变换——IFFT。 我们的FFT算法已经将两个函数的卷积按照点值形式求了出来,但是一般生活中大家还是习惯性使用解析式,也就是系数表示法表示一个函数,就需要借助IFFT将卷积的点值形式重新转化为系数形式。 假设一个函数的系数形式在经历了一次FFT后变成了其点值形式。根据FFT有:。IFFT的作用就是将变成,下面是具体操作: 简记为:根倒求和、倒乘积。 再加上,复数的乘积在复平面上有个奇妙的性质:复平面上一个向量可以看作是从实轴正半轴逆时针旋转特定的角度后得到的,这个角度称作向量的辐角,复数相乘时,得到的结果的辐角将是这两个向量的辐角之和、模长将是两个向量模长的乘积。简称辐角相加、模长相乘。除法作为乘法的逆运算,它在复平面上操作的结果是辐角相减、模长相除。因而单位根的倒数可以看作,也就是从实轴正半轴顺时针旋转的辐角大小。计算时就可以把原单位根关于实轴做一次对称变换,即虚部取相反数,也就是共轭。 对于代码的设计,尽管C++STL库提供了Complex<>复数类,但还是建议手写Complex。因为STL库的运行效率有时会很慢,会被卡掉,而且它的码量也不大,手写难度不高。强烈推荐手写结构体Complex。 递归Version: 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879#include <bits/stdc++.h>#define N 6000010using namespace std;const double PI = acos(-1.0);struct Complex { double real, imag; Complex(double r = 0.0, double i = 0.0) { real = r, imag = i; } } f[N], g[N];Complex operator +(const Complex &l, const Complex &r) { Complex res(l.real + r.real, l.imag + r.imag); return res;}Complex operator -(const Complex &l, const Complex &r) { Complex res(l.real - r.real, l.imag - r.imag); return res;}Complex operator *(const Complex &l, const Complex &r) { //(a+bi)*(c+di)=(ac-bd)+(ad+bc)i Complex res(l.real * r.real - l.imag * r.imag, l.real * r.imag + l.imag * r.real); return res;}Complex operator /(const Complex &l, const Complex &r) { //(a+bi)/(c+di)=(a+bi)(c-di)/(c^2+d^2)=[(ac+bd)+(bc-ad)i]/(c^2+d^2) Complex res((l.real * r.real + l.imag * r.imag) / (r.real * r.real + r.imag * r.imag), (l.imag * r.real - l.real * r.imag) / (r.real * r.real + r.imag * r.imag)); return res;}void FT(int len, Complex *c, int type) { // type=1时为FFT,type=-1时单位根纵坐标取相反数,为IFFT if (len == 1) return; Complex c1[len >> 1], c2[len >> 1]; // c1为偶项系数,c2为奇项系数,数组大小除以2 for (int i = 0; i <= len; i++) { // 按奇偶性分类存储 if (i % 2 == 0) c1[i >> 1] = c[i]; // 紧凑存储,c1、c2数组下标除以2 else c2[i >> 1] = c[i]; } FT(len >> 1, c1, type); // 处理偶项 FT(len >> 1, c2, type); // 处理奇项 Complex omega = Complex(cos(2.0 * PI / len), type * sin(2.0 * PI / len)); // 计算单位根 Complex k = Complex(1.0, 0.0); register Complex butterfly; for (int i = 0; i < (len >> 1); i++, k = k * omega) { butterfly = k * c2[i]; // 蝴蝶操作,记录下复数乘积(现场算太慢)便于调用 c[i] = c1[i] + butterfly; // 单位根 c[i + (len >> 1)] = c1[i] - butterfly; // 单位根性质,系数取反得到另一半 }}void IFFT(int len, Complex *c) { FT(len, c, -1);} void FFT(int len, Complex *c) { FT(len, c, 1);}int main() { int n, m; cin>>n>>m; for (int i = 0; i <= n; i++) cin>>f[i].real; for (int i = 0; i <= m; i++) cin>>g[i].real; int len = 1; while (len <= n + m) len <<= 1; // 得到最小递归层数 FFT(len, f); FFT(len, g); for (int i = 0; i <= len; i++) f[i] = f[i] * g[i]; // 点值相乘得到卷积点值 IFFT(len, f); // 卷积点值转化为系数 for (int i = 0; i <= n + m; i++) cout<<(int) (f[i].real / len + 0.5)<<' '; return 0;} 时间复杂度: 这个代码足够通过模板题有些人说不行,只需把数组开大一点点(5e6起步)就可以了……但是这个代码其实还可以继续优化,但是这下就很棘手了,本来推来推去已经够烧脑了你还要让我优化?,考虑到递归算法有些低效,浪费了一些空间和执行效率。那么我们如何把它变成一个非递归版本呢?答案是迭代! 迭代FFT与二进制优化 我们按照奇偶下标将原多项式分为了偶项和奇项,这样做的复杂度是。我们仔细观察一下抽出的系数之间下标的联系: 递归之前,系数下标: 递归一层,系数下标: 递归两层,系数下标: 递归三层,系数下标: 既然称作二进制优化,我们来看看第三层的数字写成二进制形式是怎样的:000 100 010 110 001 101 011 没有规律……别急,我们把数字倒过来念:000 001 010 011 100 101 110。诶?他们是单调递增的,再写成十进制就是:0 1 2 3 4 5 6。我们就找到规律了:递归结束时系数下标的二进制值等于原多项式的系数下标的颠倒二进制值 常规操作,我们使用进制转换来实现二进制逆序,这样的时间复杂度是的: 123456789int rev(int n) { int res = 0; int k = log2(n) + 1; for (int i = 1; i <= k; i++) { if (n & 1) res += pow(2, k - i); n >>= 1; } return res;} 借鉴了这篇题解的逆序思路,逆序的时间复杂度是的,处理数组的复杂度是的: 123456789101112131415161718192021int l,r[MAXN];int limit=1;void fast_fast_tle(complex *A,int type){ for(int i=0;i<limit;i++) if(i<r[i]) swap(A[i],A[r[i]]);//求出要迭代的序列 for(int mid=1;mid<limit;mid<<=1)//待合并区间的中点 { complex Wn( cos(Pi/mid) , type*sin(Pi/mid) ); //单位根 for(int R=mid<<1,j=0;j<limit;j+=R)//R是区间的右端点,j表示前已经到哪个位置了 { complex w(1,0);//幂 for(int k=0;k<mid;k++,w=w*Wn)//枚举左半部分 { complex x=A[j+k],y=w*A[j+mid+k];//蝴蝶效应(应为“蝴蝶操作”) A[j+k]=x+y; A[j+mid+k]=x-y; } } }} 以及r数组的读入: 12for(int i=0;i<limit;i++) r[i]= ( r[i>>1]>>1 )| ( (i&1)<<(l-1) ) ; 当然,提高组不考,如果考到,基本上那个递归版本也够用了……","categories":[{"name":"oi算法","slug":"oi算法","permalink":"https://justpureh2o.github.io/categories/oi%E7%AE%97%E6%B3%95/"}],"tags":[{"name":"算法","slug":"算法","permalink":"https://justpureh2o.github.io/tags/%E7%AE%97%E6%B3%95/"},{"name":"学术","slug":"学术","permalink":"https://justpureh2o.github.io/tags/%E5%AD%A6%E6%9C%AF/"},{"name":"oi","slug":"oi","permalink":"https://justpureh2o.github.io/tags/oi/"},{"name":"数学","slug":"数学","permalink":"https://justpureh2o.github.io/tags/%E6%95%B0%E5%AD%A6/"}]},{"title":"线性代数 简明教程 二","slug":"linear-algebra-explicit-tutorial-ii","date":"2024-02-12T00:56:44.000Z","updated":"2024-02-15T03:57:29.106Z","comments":true,"path":"linear-algebra-explicit-tutorial-ii/","link":"","permalink":"https://justpureh2o.github.io/linear-algebra-explicit-tutorial-ii/","excerpt":"","text":"pandoc测试自动部署","categories":[],"tags":[{"name":"算法","slug":"算法","permalink":"https://justpureh2o.github.io/tags/%E7%AE%97%E6%B3%95/"},{"name":"学术","slug":"学术","permalink":"https://justpureh2o.github.io/tags/%E5%AD%A6%E6%9C%AF/"},{"name":"数学","slug":"数学","permalink":"https://justpureh2o.github.io/tags/%E6%95%B0%E5%AD%A6/"},{"name":"教程","slug":"教程","permalink":"https://justpureh2o.github.io/tags/%E6%95%99%E7%A8%8B/"}]},{"title":"约瑟夫环——春晚魔术表演原理解析","slug":"magic-show-with-josephus","date":"2024-02-10T08:23:45.000Z","updated":"2024-02-23T08:17:48.754Z","comments":true,"path":"magic-show-with-josephus/","link":"","permalink":"https://justpureh2o.github.io/magic-show-with-josephus/","excerpt":"","text":"(操作没成功の尴尬,图片来自知乎) 前言 这篇文章从数学方面推导刘谦2024年央视春晚上表演的第二个魔术的秘密、分析尼格买提错误之处,并在已知信息的加持下尝试推测尼格买提手上所剩的两张半面扑克牌的牌型。有一说一撒贝宁是真的会测假 对应魔术节目:《守岁共此时》的回看请戳这里,在一小时十分整处。 魔术步骤 四张牌面向下,并打乱。 对折四张牌,并沿折痕撕开,得到两批半牌,每批四个共八个半牌 (反过来折是为了方便撕开)。将左右手的两批牌按同一个方向叠在一起。 根据自己名字的字数,从上端挨个拿出一个牌放到最底端,执行字数次。 拿起最上面三张,插进其他牌的中间(意思是这三张看作一个整体,不能放在最上面或者最下面,必须夹在其他牌中间)。 拿起最上边的牌,藏起来不要看魔术常规操作之不要看。 继续从最上边拿牌:南方人拿一张、北方人拿两张、不确定就拿三张。然后像第四步那样插进中间位置。 还是从最上边拿牌:男生拿一张、女生拿两张。然后将拿出的牌扔出去。 「见证奇迹的时刻」——每一次操作,将最上边的牌移到最下边,每次仅移动一张牌,进行七次。 「好运留下来,烦恼丢出去」——对于每次操作:第奇数次,将牌移到最下边;第偶数次,丢出去。最后直到只剩一张牌 最后拿出藏起来的牌,如果你的名字在四个字及以内、且操作无误,你会发现这两张半牌是严丝合缝的,他们可以拼成一张牌! 列数模拟 先不管你拿了哪几张牌,也不管打乱前它们的先后顺序如何——因为它们都跟魔术本身、也和我们的推导无关。我们只着眼于打乱后的牌,将它们按照上下依次编号为1~4。如下图: 1234 沿折痕撕开,假设第1号牌撕成的两张半牌编号为1和A(数字在上字母在下),八张半牌叠在一起,得到的牌堆是这样的: 1234ABCD 接下来的推导就围绕上面这个牌堆开展。 对应第三步——从上边拿出和自己名字字数相同的牌,放到最下边。假如我拿出三张,也就是编号为1、2、3的三张牌,放到最下边。牌堆变成这样: 4ABCD123 第四步——再拿出最上边三张牌,卡到中间去: CD4AB123 第五步——藏起最上边的牌,也就是编号为C的牌。 第六步——根据南北方人拿牌。因为我祖籍北方出生在南方,我这里就拿三张牌插入到中间位置(B和1之间): ABCD4123 我是男生,丢最上边的一张牌,也就是说丢出编号为A的那张(此时内心默默丢掉了两张牌): 男:BCD4123 女:CD4123 然后是见证奇迹的时刻。此时男生手里剩下7张牌、女生则是6张。这里其实无需说出那句咒语:如果你是男生,就不做操作;如果是女生,就将最上边的牌放到最下边。 男:BCD4123 女:D4123C 最后是好运留下来、烦恼丢出去。按照规则,我们要轮流进行两个操作:移动最上边的牌到最下边、丢掉最上边的牌。如此操作直到只剩下一张牌。这其中涉及到一个知识点——约瑟夫环问题 约瑟夫环问题 百度百科 约瑟夫问题 简而言之,就是从特定编号出发,每经过个数便将此时的数字挑出,剩下的数重新编号(保证起始编号相同),问最后剩下的编号是什么。这个环节的操作在这个例子下可以被抽象成:从D开始,每两次操作,丢出第二张牌。 也就是说,七个人围成一圈,“1、2、1、2……”的报数,最后剩下的是几号。这里有一个巧算的方法,适用于“1、2、1、2……”报数模型。首先找出不大于人数7的最大的2的整数幂,因为,所以令。当最终剩下个人的时候,第一个报数的就是最后一个被留下的,因此有公式:。 对于男生,最后剩下的牌就是最下边的那一个,编号3。 对于女生,剩下的是第个,同样是3。 拿出藏起来的牌C,我们开头就知道了:第三张牌被分成了3和C。也就是说它们可以拼合成同一张牌!魔术成功了! 回顾总结 不妨从一开始就观察3和C的变换规律,可以发现3号牌自从第三步结束后被移动到最下边以来就几乎没改变过位置;而前四步则是合力将C拉到了最前边好让它被顺利地挑出去。然而最为精妙的还是对“1、2、1、2……”报数约瑟夫环模型的应用。那么为什么尼格买提的操作会失败呢?看下图: 如果你是罕见的“第三性别”,想要在第七步里面丢三张牌,也是可以的,因为这样并不会改变最后一张牌3。事实上,这个魔术最多可以在第七步丢掉七张牌,这样下来就只会剩下一张牌3,全部完成之后还是可以和C配对成功的。 右上角是他的操作:他在“南方人和北方人”的操作里拿了三张牌,但是插入的时候错误将其中两张牌插到了最下边并且这两张牌和另外的那一张牌分开了(原规则是一起插到中间)。 因此这堆牌的底端变成了黑桃Q,不久之前,他藏起了一张黑桃A。所以,他最后拿出的牌是对不上的,一张是黑桃A,一张是黑桃Q。 下面是从班级群里偷的几张图,以实际证明这个理论是成功的: 当然,如果就某位“客串见证人”的失误而大做文章的话,显然是极其招人嫌恶的。刘谦本人的魔术并没有什么问题,尼格买提可能也只是太过关注自己接下来在春晚上的表现而有些分神罢了。如果这个失误真的导致2025年春晚刘谦不被总导演邀请上台的话,这种毫无底线夸大其词的舆论只会是雪上加霜,让所有人更不好过而已……事后小尼本人也道了歉,因此已经没有必要再抓住谁人的过错不放,只是从科学的角度出发,论证这个魔术的成功之处。毕竟少有节目能如此调动起屏幕内外所有人的互动热情,如此看来,刘谦的魔术也是非常成功的了。","categories":[],"tags":[{"name":"整活","slug":"整活","permalink":"https://justpureh2o.github.io/tags/%E6%95%B4%E6%B4%BB/"},{"name":"学术","slug":"学术","permalink":"https://justpureh2o.github.io/tags/%E5%AD%A6%E6%9C%AF/"},{"name":"数学","slug":"数学","permalink":"https://justpureh2o.github.io/tags/%E6%95%B0%E5%AD%A6/"}]},{"title":"线性代数 简明教程 一","slug":"linear-algebra-explicit-tutorial","date":"2024-01-20T20:45:07.000Z","updated":"2024-02-17T18:24:08.120Z","comments":true,"path":"linear-algebra-explicit-tutorial/","link":"","permalink":"https://justpureh2o.github.io/linear-algebra-explicit-tutorial/","excerpt":"","text":"线性代数 简明教程 前言 前言正文 我个人认为我自己与线性代数的渊源是极深的。差不多整一年之前,初三上册的寒假,我在启动某二字二次元风格开放世界游戏时偶然做到了一个世界解谜。与平常无脑过的难度不同,这次的解谜可谓是充满血和汗水的教训——看攻略前千万要搞清楚站位和朝向……于是一步错步步错,耗费了整整半个小时才碰巧还原到原始的状态。自此便有了用严格的数学论证来解决这种世界解谜的想法,然而苦于当时数学功底不够、那些线上线下的教程又对我这种“跳级生”极其的不友好,最终还是将它抛到脑后去了。 但是我最开始想做关于线性代数的内容却是在高一上期末那会,刚好我的竞赛内容推进到了高斯消元相关内容,因而我对线性代数的内容有了一定了解。正巧年末购书有优惠,买了一本Steven J. Leon的《线性代数》(原书第十版)自己学习。深谙零基础学生自学的痛苦的我随即就想要上一篇全网最简明易懂的线性代数教程出来,这篇教程旨在让零基础初学者也能吸收学会线性代数的相关知识点。你可以将它理解成上述《线性代数》著作的一个口语版理解和集注,我所做的就是将书中的晦涩的知识自己吸收后转化为易于读者消化的简明概述。也正是因为其趣味性的必需特点,部分科学定义可能在本教程转述时出现细微的偏颇,还请指出,但在编写过程中我会尽量将原书的科学性与本教程的趣味性、通俗性有机融合起来,从而让读者毫不费力地学习线性代数的知识内容,快乐学习。 更新记录 重置了有关渲染的插件和脚本,弃用了不美观的katex渲染。该博客目前使用观感更佳的Pandoc进行渲染。 不得不说Hexo搞这个LaTeX是真的让人头疼…… 第一节 方程组与矩阵的互相转化 假设我们有一个方程组:。首先将所有未知数提到等号左侧,常数全部移到右侧。我们暂时先忽略掉等号右边的常数项。我们将每行未知数的系数提取出来,放入矩阵的第一行,矩阵的第一行就表示方程组中第一个方程的未知数系数(没有默认为0),以此类推到下边几行,最终你会得到一个列数与未知数个数相等、行数与方程个数相等的矩阵。本例中它长成这个样子: 如此得到的矩阵叫做系数矩阵,顾名思义,它只表示了原方程组的系数,而忽略了常数项。它同时也是一个矩阵,一般地,对于一个矩阵(),它有行列。 此时,如果我们加上等号右侧的常数项,原先的矩阵会变成的。人们为了区分常数和系数,选择在书写时将常数加入到最右侧那一列,并且在最右一列的前面加上竖线分隔系数,如此得到的矩阵叫做增广矩阵。本例中的增广矩阵形式写作: 当矩阵元素不明时(通常是为了举例),我们为了简便表示矩阵本身,采用右下角元素+括号的方式。例如一个矩阵,可以写作:。 第二节 矩阵的基本运算 1. 矩阵加法 仅限构造相同的矩阵,也就是说进行加法运算的两个矩阵行列数必须相同,这样的两个矩阵是同型的。相加时同一行同一列的元素相加即可(增广矩阵同理)。 例如: 矩阵加法满足:结合律、交换律 2. 矩阵减法 矩阵减法是矩阵加法的逆运算,因此对于两个矩阵的形式要求同上,只是相同位置的元素相减而已。 矩阵减法满足:结合律、交换律 3. 标量乘法/矩阵数乘 矩阵的数乘也很简单,让矩阵中每个元素乘以这个数就可以了。 例如: 矩阵数乘满足:交换律、结合律、分配律 4. 矩阵转置 矩阵转置就是将原矩阵的行变成新矩阵的列,直观理解就是顺时针旋转90度后再水平镜像过去。转置用上标表示。 例如:,则 矩阵的主对角线(左上-右下)元素转置前后不变,且具有可逆性[]、数乘不变[]、分配律[]。 有一类特殊矩阵,它转置后恰好就是它自身。这类矩阵被称为对称矩阵,它是自转置的,即。对称矩阵的元素恰好关于主对角线对称,并且是一个的正方形矩阵。这两条性质是对称矩阵的两个基本性质。 5. 矩阵乘法 该内容将在第二章涉及。 第三节 消元 按照一般思路(就是我们在小学学的方法),我们会选择通过方程互相加减各自的倍数,达到消去未知数的目的。这种方法在矩阵上同样适用,而且它有一个贼高坤的名称:高斯消元法(Gaussian Elimination)。 回忆一下我们从出生就会用的消元原理,我们的目标就是让每个未知数都对应一个常数项,那么它的值就可以直接用常数除以系数的方式求出。矩阵中也是如此,为了能够化简出可直接求解的矩阵,我们在此引入初等行变换的概念: 交换某两行 把矩阵的某一行同乘以一个非零的数 把某行的若干倍加和到另一行 这三条很容易理解。第一条:相当于交换方程组顺序,不影响计算;第二条:相当于对某一行方程放缩某倍,它等价于原方程;第三条:相当于前两条的融合,也是消元的关键一招。这三条规则在之后的初等矩阵内容中会再次出现。 首先从一个例子讲起,让读者感受一下初等行变换的魅力: 考虑这个方程组: 按照如上所述,将它转写成增广矩阵的形式: 我们总结一下常用的消元原理,应用到矩阵上就是: 枚举每一列,选出无序组中第列系数绝对值最大的一行,并移到无序组的最上边。(变换规则一) 行通过自乘,将第列的系数变成,并标记为有序。(变换规则二) 通过加减有序组中某一行的非零倍,将之后所有行的第列系数化为。(变换规则三) 令矩阵(有序组用绿色表示) 枚举第一列,。开始时,所有行均无序。选出绝对值最大的那一项,本例中为第二行,进行移动,原矩阵变为: 第二步,自乘并标记有序,因此第一行除以,原矩阵就变成了: 第三步,将无序组的第列消成。本例中,我们让第二行减去二倍第一行;第三行直接减去第一行,得到: 枚举第二列,此时。第一步,选出第二列系数绝对值最大的那一行,移到无序组最上端。本例中无需移动,自乘,标记有序,原矩阵为: 最终的最终,第三行减倍第二行,得到我们心心念念的化简后的矩阵: 为什么把矩阵化简成这种金字塔型的形式呢?你会发现:最后一行仅有一个带系数的未知数,我们直接求,。向上一行,现在相当于常数,移到常数中与合并,也可直接求了……经过如上的反代操作,三个未知数都会被求出来。至此我们才发现这个三角形矩阵的魅力之处。 一般地,对于一个矩阵,如果它的非零系数呈阶梯形分布,则称这类矩阵为行阶梯形矩阵。将非零系数挑出来,它们组成的是一个上三角形矩阵;对应地,零项就会组成下三角矩阵。上三角矩阵通常以表示、下三角矩阵通常用表示。 原方程组有唯一解: 第四节 秩 类比一元二次方程的根存在性判别法——判别式法,即对于一元二次方程,根的个数。那么,矩阵方程是否也有类似的根存在性判别方法呢? 答案是有的,而且不止一种,这意味着“矩阵是否有解”这样的问题会有多种解决方案。现在介绍的是最为简单常用的一种——秩。 在线性代数中,一个矩阵A的列秩是A的线性独立的纵列的极大数目。类似地,行秩是A的线性无关的横行的极大数目。即如果把矩阵看成一个个行向量或者列向量,秩就是这些行向量或者列向量的秩,也就是极大无关组中所含向量的个数。 ……咱们抛掉这种看也看不懂的高级语文句法,听我给你总结: 通俗来讲,把一个矩阵化成最简形式(特指行阶梯形)后,非零行的个数就是矩阵的秩。这其实是秩的最大线性无关组的定义。再次白话总结:如果存在三个行向量(列向量一样的,保证所有向量都是行/列向量即可):。根据高中数学中立体几何的知识——和显然是共线的(就是值的最简比相同,本例中均为)像这样共线的两个向量,拉到线性代数中就说他们是线性相关的;反之是线性无关的,例如本例中和这两组向量互相不共线,它们互相都是线性无关的。 矩阵的秩用表示[、、、等均可]。 现在明白了吧,如果一个矩阵的某两行线性相关,它们都会被初等行变换第三条狠狠薄纱——在乘/除一个非零数后相减,其中一行就会被全部消成0,从方程组角度来看就是,带什么值都成立(相当于浪费了一行)。 当然上边这一段也有表述不准确之处,假设有一个增广矩阵。初等行变换第三条秒了第一、第二行,然而事情有些不对劲了…… 第二行不乐意了,它还存留这最后一点倔强,好像在说:“你总结的不对呢~真是雑鱼~”。但是明眼人都看得出来,这种事情是绝对不可能发生的,也就是无解。按照刚刚说的,这个增广矩阵的秩,可是它对应的系数矩阵的秩,就有且,于是我们就找到了矩阵无解的一个条件了。矩阵无解的充要条件是。 再考虑有无穷解的情况:无非就是出现了的情况,此时可以代任何值。与无解不同,这次的最简行阶梯形矩阵,无论是系数矩阵还是增广矩阵形式,它们的秩都是相同的,并且都浪费了至少一行方程式。我们知道:一个三元一次方程组是无法用相异的(行向量形式表示下不共线)两个方程解出唯一值的,相反,解形如:表明由确定、而又由确定,然而这俩都不确定,导致这两个数可以取无穷多的值,也就导致矩阵有无穷组解。综上:矩阵有无穷组解的充要条件是(为未知数个数)。 最后就是有唯一解:如果一切进行顺利的话,既没有全零行,也没有无解行。那么此时系数矩阵和增广矩阵的秩会相同,且等于未知数个数,即。 总结,假设一个由个未知数组成的最简行阶梯形矩阵、以及它的增广矩阵。矩阵解的个数。 例1.1.1 Delivery Mathematics 快递员的数学题 「稻妻狛荷屋的人气跨国快递员绮良良在送货途中遇到了一个难题,你作为无所不知无所不晓的旅行者自然是乐意地接下了她的委托。当你来到委托地点时,你发现这是一道解谜题目……」 稻妻号称最难的方块解谜是一组由个正方体可旋转方块组成的阵列,击打其中的某个方块会使得与之相关联的其他方块共同旋转一个特定角度。在这个谜题中,每个方块每次仅能水平顺时针旋转90度,传动方式在下图给出。问若要使所有方块同时朝向北方,需要如何击打方块?给出任意可行解,但需要保证每个方块旋转的次数不超过4(不击打也可以,相当于次数为0)。 由于钟离先生远在海那一头的璃月喝茶听评书、宵宫也正忙着制作夏日祭的烟花而无法抽身、香菱在万民堂做饭、安柏在侦察蒙德郊区、芙宁娜忙着吃蛋糕……总之没有其他人召唤物能帮你解决这个问题,你只能凭借自己的力量解开这个谜题。 图1.3.1 问题分析:首先我们要搞清楚传动规则,我们会发现当你击打了一个方块,包括它在内、再按顺时针方向数两个方块都在旋转相同的角度。这也是这道题被称作难题的原因之一,只用想象力是很难想象的出来的……于是为了用代数方法解决该问题,我们选择用四个未知数、四个方程表示每个方块操作后的状态,问题解决的标志既为四个方块的状态均为(表示北方)。 算法设计:考虑到单个方块每旋转四次就相当于一次循环,因此我们重定义方向标,从北开始,顺时针方向将方位标记为。这么做可以避免一些复杂的取模运算。接着我们根据传动规则表示每个方块的状态,令方块1-4被击打次数分别为。以方块1为例:击打自己、3号和4号都会导致1号顺时针旋转90°,再算上1号初始朝向为,得到:。其他方块以此类推,解析出的方程组对其求解即可。这样的矩阵一定有唯一解,每个未知数都以表示,将一个自然数代入值即可解出答案。 解:设方块1-4的击打次数分别为,设朝向从北方按顺时针方向分别为。 根据传动规则,有如下线性方程组: 增广矩阵形式为: (化简过程略),行阶梯形式为: 因为系数矩阵的秩与增广矩阵的秩相同且都等于未知数个数,因此矩阵有唯一解。易知的合法值满足的数学关系,此处求最小值,令,得到。 因此,最佳方案是暴击击打2号和3号方块各两次。 后日谈:有些读者可能会问,这个难道不是有无穷解吗?为什么上边说这个矩阵只有唯一解?其实这个矩阵确实只有唯一解,因为,造成它有无数组解的原因是这个自然数。我们在开头只为这个矩阵设定了四个未知数,因此矩阵只有四个元,因而有唯一解。 洛谷习题: P3389 [模板] 高斯消元法 P2455 [SDOI2006] 线性方程组 P4035 [JSOI2008] 球形空间产生器 第二章 矩阵乘法 第一节 什么是矩阵乘法 你经常能在各种线性代数的书上看到这样一串定义式:。这对于自学者(比如说我自己)其实是非常不友好的。他们在举例计算时很容易被绕进去,不仅计算速度慢不说,还很容易出错……那我在此举出一个简记方法: 将左边的矩阵的每一行看作每个未知数都代了确定值的方程、右边的矩阵每一列看作是前者方程的未知数系数。二者相乘本质上就是让未知数和系数匹配上,并计算出结果放入结果矩阵的特定位置。这个特定位置也有讲究——计算时我们需要固定一个行/列,相对应地我们需要遍历另一个矩阵的列/行,遍历的方向就是这个“特定位置”的排布方向,当遍历完一轮,开始下一轮时,这个“特定位置”的起始点将移到下一行/列,若固定一列则右移一列;反之下移一行。看以下例子来加深理解: 图2.1.1 这是固定特定列求值的例子,固定行求值留给读者自行实操。不想再做图了,我太懒了 那么什么样的矩阵才能进行乘法运算呢?答案是一个和一个的矩阵,观察规律,我们发现前矩阵的列数需要等于后矩阵的行数。根据如上概括的矩阵乘法的意义——即搭配未知数与系数。显然,当后一个矩阵的列数大于前一个矩阵的行数时,我们进行系数配对时就会发现多出几个失配的系数。矩阵乘法国不养闲人,这种单身汉显然是不可以光天化日下大摇大摆出来遛弯的。因此保证其中一个矩阵的行数等于另一个矩阵的列数后方可相乘。 类比四则运算的乘法,矩阵乘法是否也有结合律、分配律和交换律呢?很遗憾,不完全是,前二者是矩阵乘法运算所具备的性质、但最后那个交换律不是。不是所有的矩阵相乘都满足乘法交换律,举几个特例:同型零矩阵相乘、一个矩阵(可逆)和它的逆矩阵相乘,矩阵乘法满足交换律的充要条件证明过于复杂烧脑,此处不做陈述主要是我也不会证qwq……。 证明:一般矩阵不满足乘法交换律 假设一般矩阵,一般矩阵,则可以进行,因为的行数和的行数均为。得到的乘积是一个矩阵;反过来,无法进行,因为的列数不等于的行数,即。 假设。和均可进行,假设乘积为。当时,根据矩阵乘法的计算式,得到;当时,根据计算公式得。一般情况下,。得证。 矩阵和数字一样,也有幂次方的计算。特殊地,任意非零矩阵的零次幂都是一个的单位矩阵。主对角线的值全是1,其余元素均为0的矩阵叫做单位矩阵,用字母表示;零矩阵的任何非零正整数次幂都是一个零矩阵,零矩阵的元素全部是0,用字母表示。一个的单位矩阵是这样的:。在算法设计中,经常用类似于大数快速幂(位运算版本)的方式快速计算矩阵的幂次方。 例2.1.1 Akasha Browser with Irminsul Kernel 世界树搜索引擎 你作为刚刚清除了须弥世界树痼疾的英雄旅行者,突然对虚空终端的运作方式有了兴趣。你从大贤者那里了解逼问到,虚空终端实质上是一个仅显示搜索结果的前端程序,但关键词搜索功能却是基于须弥地下空间的世界树。带着这个疑问,你再次来到了世界树前,见到了小吉祥草王大人,希望能让她告诉你世界树的运作方式…… 背景知识: 一般浏览器的结果返回功能大多数依赖于矩阵运算,这里属于最简单的一种——我们只需要矩阵的乘法运算(某些情况下会用到转置)。然而随着科技的快步发展,数据量的快速增加,这种方式如今只在很小的范围内被使用(由于码量小思维简单,它有时会在个人博客的关键词搜索功能中被用到);目前广泛使用的一种是向量相似性搜索,它本质上是在一定范围内搜索与目标向量辐角最为接近的已有向量,在“矩阵的几何表示”章节中会涉及到。这里介绍的是简单匹配搜索。 问题分析:因为矩阵乘法本质上是未知数和系数的配对求值,我们需要构造一个方法来使得“搜索内容”和“已有内容”配对。并且搜索引擎总会返回与你搜索的内容最为相似的结果,搜索“比尔·盖茨”,第一条肯定是关于他个人的介绍,而绝对不可能是一则寻狗启示……因此,我们设计的矩阵必须能在经历一轮运算后能够正确返回每个关键词出现的频率(简单点说就是出现次数),这样虚空终端才能对频率进行排序,并返回频率最大的那个结果。 算法设计:不妨考虑这样几个矩阵——其中一个存储关键词、另一个存储搜索内容。比如我需要将几篇论文(为方便使用英文表示,并且假设词根相同的单词为同一个单词,即不考虑词汇变形)《Basic Structure of Elemental Monuments》(元素方碑的底层构造)、《Junior Elemental Reaction》(初等元素反应)、《Advanced Elemental Theory》(高等元素论)、《Architectural Structure in the Mausoleum of King Deshret》(赤王陵的建筑结构)以及《Advanced Sumeru Linguistic Analysis》(高等须弥语音学解析)。我们在此次挑选一些关键词存储(方便读者观察):Structure、Element、Junior和Advanced。为每篇论文编号1-5,矩阵如下图: 图例2.1.1 假如热爱学习的艾尔海森来到了教令院的大图书馆,它想测试一下这全新开发的文献查询系统,输入了Advanced一词。假设已录入数据库就是以上形式,我们如何构造一个“查询矩阵”来和数据库矩阵进行运算呢? 首先根据矩阵乘法的前提要求,这个查询矩阵必须是四行。不妨让每行代表我们的词库词语,艾尔海森输入的是Advanced——即对应数据库矩阵的第四列(未知数),我们要配对它的系数,因此它必须在第四行,才能保证系数正确匹配未知数。同理,查询矩阵的第一行对应Structure、第二行Element、第三行Junior。他输入了一个Advanced,因此我们的查询矩阵如下图: 图例2.1.2 乘法的目的是将二者匹配起来,得到的结果如下图: 图例2.1.3 返回矩阵的数字代表关键词在对应数据库项中的出现次数,也就是说,如果此时再加入一篇论文《Advanced Usage of the Word Advanced》(“Advanced”一词的进阶用法),返回矩阵的最后一行(第六行)会出现一个。经过虚空终端的一轮排序,它自然就会来到第一位的位置。如果要分别查询两个不同关键词,在查询矩阵右侧再加一列即可,返回矩阵中多出的一列就是新关键词的出现次数;如果需要同时查询两个关键词,在同一列对应位置写入即可…… 后日谈:可靠情报称——愚人众第二席执行官“博士”伙同教令院高层贤者向世界树中加入了大量带有重复词语标题的、正文中充满了强烈心理暗示的催眠文献,须弥民众所佩戴的虚空终端中写入的关键词查询算法自动按关键词出现频率返回结果、其内置的播放功能在结果返回后自动激活,播放其中内容,导致须弥大范围民众出现意识不清、报告称出现“重复经历同一天”、“既视感”等异常现象。后续调查正持续跟进中……——《蒸汽鸟报》记者 夏洛蒂 须弥的大范围“失控”已被证明是须弥民众针对教令院的一次毫无意义的武装暴动,目前已被教令院大贤者和“博士”联合镇压。主要组织者纳西妲、旅行者已被尽数羁押等候问讯。——教令院 例2.1.2 Light Novel Query 轻小说查询 八重堂的主编八重神子最近在为轻小说的事情发愁……并不是因为销量不够,正相反:八重堂最近推出了一项跨国销售项目,各种经典作品被远销往了枫丹廷。这就牵涉出一个问题——枫丹的市民们不想远离枫丹城区、横穿须弥沙漠、翻越璃月高山、躲避稻妻雷暴就为了看一看有哪些轻小说符合自己的独特口味……于是八重神子找到了见多识广的你,希望你能帮她做出一套轻小说内容检索系统。当然作为报酬给你的原石和摩拉是肯定是不会少的…… 当然,这套系统有一定要求。因为有很多轻小说为了吸引读者,取的标题和内容是完全对不上号的,神子的想法是做一套正文内容检索——每本轻小说的总字数在出版时就统计好了,但是苦于稻妻的信息存储技术不是很发达,神子希望存储在数据库矩阵里的数据尽可能小。请问该如何设计符合要求的存储算法? 问题分析:每本书中特定的词可能重复出现成百上千次(同样用英文单词表示,且同词根不同词形的两个词算作同一个单词参与计数),我们的要求是让数据尽可能小,既然总字数都已经给出了,我们不妨使用指定词出现的频率来表示这个词的出现次数(单词出现次数=全书总词数×出现频率)。这样的搜索方法叫做相对频率搜索。 算法设计:大致原理和例2.1.1里的一模一样,只是数据库矩阵存储的不再是出现总次数,而是对应词的相对频率。因而图例2.1.3可以变化为如下形式: 图例2.2.1 明显一看,第三篇文章出现Advanced的频率最高,应该优先返回。但是这个例子并不是很好(明明说了按内容搜索你还在这搜索标题),但是当加入大量的正文内容时,这个方法的优势也就体现出来了。这里由于篇幅图太大耗我洛谷高级图床空间,我也懒得写那么多字原因就不举过长的例子,本例仅作对相对频率搜索的原理的理解。 后日谈:八重堂轻小说搜索引擎被教令院照搬去做了论文的查询系统…… 第二节 初等矩阵与矩阵递推 假设存在一个的单位矩阵,对只进行一次初等行变换得到的矩阵叫做初等矩阵,通常用表示。一个矩阵的行变换和列变换都可以用初等矩阵的乘法进行。 仅交换了两行的单位矩阵称作第I类初等矩阵(只进行了初等行变换第一条),将它左乘到一个矩阵前,可以进行相应的行运算;右乘到一个矩阵后可以进行相应的列运算。比如,一个第I类初等矩阵(交换第一、二行),和一个矩阵。左乘就是(交换一、二行);右乘就是(交换一、二列)。 仅将某一行乘以一个非零倍数的矩阵叫做第II类初等矩阵(只进行了初等行变换第二条),左乘行运算、右乘列运算。例如一个第II类初等矩阵(第一行乘3)和一个矩阵。(第一行乘3);(第一列乘3)。 仅将某一行的非零倍加到另一行上的矩阵叫做第III类初等矩阵(只进行了初等行变换第三条),同样是左乘行运算、右乘列运算,但是有一点点小不同,不要根据思维定势随便写答案!例如一个第III类初等矩阵(第二行乘2加到第一行)和祖传的矩阵。(第二行的2倍加到第一行);(第一列的2倍加到第二列)。注意初等矩阵的行列变换与乘法后矩阵的行列变换,哪一行/列乘了倍数、哪一行/列被加上了! 因此我们可以不必使用高斯消元,仅使用初等矩阵乘法也可以达到将普通矩阵消元变成最简行阶梯形矩阵!而且它可以进行列运算,甚至比高斯消元法更高级一点。 接下来是我们的矩阵递推。大家都知道斐波那契数列,它的前两项均为1,此后的每一项都是前两项之和,即。大多数信息竞赛生在学习到递归算法时都会被要求写程序求解斐波那契数列的某一项,当然代码也非常的简单,如下: 1234567891011121314#include <bits/stdc++.h>using namespace std;long long fib(int n) { if (n == 1 || n == 2) return 1; return fib(n - 1) + fib(n - 2);}int main() { int n; cin>>n; cout<<fib(n)<<endl; return 0;} 这段代码其实就是照搬了上面的通项公式,但是递归有个弊端就是效率和内存,当为百万级别、甚至十亿级别时它就显得很小丑了。那么我们如何用矩阵加速计算呢?我们用斐波那契数列的递推来向读者介绍矩阵递推的操作方法: 首先我们将通项公式变成我们想要求的形式,为了便于输出,要求结果矩阵的第一个元素就是答案,因此结果矩阵就是:。又因为,并且。我们还需要保证初始矩阵在经历一轮变换前后,始终都是同型的,这里是的矩阵,操作后也应该是的矩阵。于是我们的递推矩阵应该是一个矩阵。不妨将递推矩阵的每一行从上至下分别表示为和的系数,由以上二式可得:。别急,左边还有一列未填满——我们希望每次操作都会把矩阵元素整体向左移一个位置,就好像一个滑动窗口(但不是单调队列),我们的第一列也可以求出来了。最终就是 那么求数列第项——每次右乘都相当于多求出一项,并且当只被乘了一次时,结果矩阵的第一个元素是。因此要让第项来到第一个位置,我们需要进行次乘法,也就是的第一行第一列元素。可以写出如下代码: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859#include <bits/stdc++.h>#define MOD 1000000007#define N 15using namespace std;typedef long long ll;int n = 2; // 递推矩阵行列数均为2 struct Matrix { ll mat[N][N]; Matrix() { memset(mat, 0.0, sizeof mat); // 初始化时内部变量自动置零,无需每次定义变量时再置零 } void I() { for (int i = 1; i <= n; i++) mat[i][i] = 1; // 构造2×2单位矩阵 }}; Matrix operator *(const Matrix &l, const Matrix &r) { // 重载乘法运算符,实现矩阵乘法 Matrix res; for (int k = 1; k <= n; k++) { for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { // res.mat[i][j] = (res.mat[i][j] + l.mat[i][k] * r.mat[k][j] % MOD) % MOD; // 取模用这个 res.mat[i][j] += l.mat[i][k] * r.mat[k][j]; } } } return res;}Matrix qpow(Matrix a, ll b) { Matrix res; res.I(); while (b) { if (b & 1) res = res * a; a = a * a; b >>= 1; } return res;}int main() { int a; cin>>a; Matrix A; A.mat[1][1] = A.mat[1][2] = 1; // 初始矩阵 Matrix M; M.mat[1][2] = M.mat[2][2] = M.mat[2][1] = 1; // 递推矩阵 A = A * qpow(M, a - 1); cout<<A.mat[1][1]<<endl; return 0;} 它的时间复杂度可以做到,是递推矩阵长/宽,这里是;是幂指数。因此这里的时间复杂度是:,比朴素斐波那契递推的强了不少! 例2.2.1 Lost Control! Blubberbeast's Reproduction 膨膨兽泛滥危机 由于枫丹水质的大幅改善,膨膨兽的天敌数量锐减,枫丹城区近海的膨膨兽也得到了更多的食物,进而开始大量地繁殖。水质改善的第一年,已登记的膨膨兽数量是6765头,恰好是斐波那契数列的第20项。第二年,膨膨兽数量没有变化,之后的每一年,膨膨兽数量都是前两年之和的,已知膨膨兽的平均寿命是15年、枫丹廷近海能承载的最大膨膨兽数量是90万只。那么请问15年后近海的膨膨兽数量是多少?这15年内枫丹廷是否需要向近海投放膨膨兽的天敌以遏制后者疯狂繁殖?(结果出现出现小数则向上取整) 问题分析:这是一道标准的矩阵快速幂递推问题,它基于斐波那契数列递推、却比它更高级。首先,它的初始值不再是而是,其次,从第三项起,每一项都是前两项和的一个倍数,这里是。那我们怎么构造递推矩阵来解决问题呢? 算法设计: 已知初始矩阵。根据题目描述很容易写出通项公式:。我们要保证初始矩阵经过一次递推后,得到的新矩阵与初始矩阵同型,因此根据矩阵乘法定义,我们的递推矩阵必须是一个矩阵。于是拿出祖传单位矩阵模板开始构造递推矩阵! 对于前项和的问题,前面已经给出了,因而我们的递推矩阵变成了;接下来解决倍数问题——根据通项公式,和的系数都是,我们构造递推矩阵时也要考虑到这一点,当时,递推公式展开如下:。如果第一行代表的系数、第二行代表的系数,第二列显然应该同时乘以0.85,左边一列的作用是使原矩阵整体向左移一个位置。最后我们的递推矩阵就是。直接将初始矩阵右端乘以递推矩阵的幂次方就可以了。注意因为初始矩阵的右侧是第二年的膨膨兽个数,乘以递推矩阵本身(一次方),会让第二年的膨膨兽个数移到结果矩阵的前端,要想让第一项变成第15年的个数,递推矩阵的幂必须是,即。 代码实现上,仅需将矩阵和矩阵的初始值改变就可以了。 最终结果:875076。结果小于90万,因此不需要投放天敌。 后日谈:那如果将系数改变为呢?输出的结果将是977427,接近100万了。因此但凡枫丹水质再好那么一点点,使得这个系数升高了0.1,那么枫丹廷说不定都会变成膨膨兽的第二家园了! 洛谷例题: P3390 [模板] 矩阵快速幂 P1962 斐波那契数列 P1349 广义斐波那契数列 P1939 矩阵加速(数列) P3216 [HNOI2011] 数学作业 第三章 矩阵的逆 第一节 浅谈矩阵的“逆” “逆”这个词相信你早已听说过:同余意义下存在乘法逆元,大多数矩阵也存在逆矩阵。“逆”普遍用来描述不同意义下的“倒数”的概念,倒数一般满足的性质,即本体×本体的逆=单位一。矩阵中的“单位一”是单位矩阵,也因此我们的逆矩阵需要满足这个式子:,并且这个式子倒过来也必须成立(为数不多的满足矩阵乘法交换律的情况之一)。 如果对于一个矩阵,存在另一个矩阵,使得:成立。则称矩阵是可逆的,或称之为非奇异的,矩阵是矩阵的逆矩阵,通常表示成。特殊地,单位矩阵的逆矩阵是它本身,即;零矩阵不可逆,或称之为奇异的,即不可能存在矩阵,使得。类比实数运算,的倒数永远是它本身、没有倒数,因为分母为,没有意义;,同时。 第二节 行列式 行列式是一种函数,写出来有点像矩阵的绝对值。它可以用来判断一个矩阵是否有解、也可以定量分析线性变换对原向量的影响。矩阵的行列式通常用或者是表示。这一节主要介绍行列式判断矩阵是否可逆。 矩阵的行列式为。特殊地,矩阵的行列式就是的值。当一个矩阵的行列式为时,它是奇异的、也就是不可逆的;反之则非奇异/可逆。 那我们在上边只提到了两种方阵,那对于、、的方阵又该怎么办呢?答案是分而治之——分治! 第三节 代数余子式 我们拿出祖传的矩阵,我们随机在其中挑选一位受害者。我个人看第二行第一列的元素不太顺眼,作为矩阵的定义者,我有权利将它变成自己所喜欢的样子,因此我把元素拿掉。可是拿掉以后它还是个!于是我将它所在的那一行以及那一列全部剔除,把剩下的元素按照原来的相对顺序靠拢,组成一个新的矩阵。现在整个矩阵没有元素了,看上去清爽多了~~~ 像上边这样,将阶行列式中元素()所在的第行、第列所有元素删去,剩下元素组成的新阶行列式叫做原行列式的余子式,用表示,代表它是删去原矩阵第行和第列得到的余子式。它通常将一个高阶行列式拆分为一个个低阶行列式便于计算,这其中就是用到了分治(子问题递归)的思想。 我们要计算整个矩阵的行列式,就需要拆开余子式。最终分治成多个的矩阵求其行列式并加和起来。有一个定理:当时,一个的方阵的行列式可以表示成任意行/列的余子式展开,即: 日常做题时,通常选取最多的那一行/列进行展开以减少计算量。 第四节 矩阵的逆 第一节解释清楚了逆矩阵的概念,那么如何求逆矩阵呢?首先是前提——判断矩阵是否可逆!我们引入矩阵行等价的概念: 如果一个矩阵能经过有限次初等行变换得到另一个矩阵,则称与是行等价的。比如说你交换一个矩阵的两行(初等行变换第一条)得到的矩阵本质上还是原来的矩阵,因为如果当你把变换前后的矩阵拆分成一个个行向量,它们在坐标系上的关系不变(交换两行向量不变,同乘倍数向量共线还挺押韵)。联系到第二节的初等矩阵知识,初等行变换可以转化为矩阵左乘初等矩阵,定义可以转换为如下的数学语言:如果存在矩阵和矩阵,使得成立,则称与是行等价的;相应的,初等矩阵右乘就对应两个矩阵列等价。 矩阵行等价有反身性、传递性。例如:与行等价,与行等价,则以下两条均成立: 与行等价 与行等价 相应的,若有方程组,使得。在等号两端同时乘一个符合乘法运算条件的矩阵,新的方程与先前的方程的解相同。第二个方程与第一个方程就是一组等价方程组。 当且仅当与是等价方程组时,增广矩阵与行等价。这个推论的证明需要用到一个定理:若为一个初等矩阵,则它是非奇异的,且和是同类型矩阵。 证明:根据初等矩阵的定义,它是由单位矩阵经过单次初等行变换而来。根据行变换类型的不同,分为三种情况讨论: 第一种,为第I类初等矩阵。假设它由单位矩阵交换第和第行而来,左乘同样的矩阵,进行相应行运算——右边的矩阵将交换行,因为原本就是交换行得来的。因此左乘后原式,根据逆矩阵的定义:的逆矩阵就是它本身,即,因此二者同类型,都是第I类初等矩阵。 第二种,为第II类初等矩阵。假设是的第行乘一个非零数而来,构造新的初等矩阵,若想使得,用于进行行运算的左矩阵必须要让第行乘上回到。因此的第行同乘以非零数,得到。因此二者都是第II类初等矩阵。 第三种,为第III类初等矩阵,且是的第行加上第行的倍得到的。因此构造初等矩阵,作为左矩阵,它的效果是让右矩阵的第行减去倍第行,因此,且是将第行乘加到第行得到的。二者同为第III类初等矩阵。 定理得证。 两个非奇异矩阵等价的条件是:假设为一个的方阵,所以下面三条命题等价: 是非奇异的 只有平凡解 与行等价 在矩阵运算中,的零解就是这个方程的一个平凡解。(因为实在是太显而易见了所以很平凡) 证明:首先证第一条可以导出第二条。假设为非奇异方阵,是方程的一个解。因此。因为是的一个解,因此,原式。因而原方程仅有平凡解。 再证第二条可以导出第三条。可以化简成行阶梯形矩阵,方程变为。因为严格三角形矩阵可以通过变换得到单位矩阵,所以需要证明是否是严格三角形矩阵。如果的主对角线出现了,那肯定不是严格三角形矩阵。因为阶梯形矩阵要保证每一行都比它的上一行前边的元素多,因为是方阵,到最后一行时只能全部为。此时矩阵有无数组解,因为实际上他只列出了个方程,最后一行的方程不被计入系数矩阵和增广矩阵的秩,导致。因此有无数组解;反之若的主对角线全不为,它可以被化简成单位矩阵(使用高斯消元即可)。因此与行等价、与行等价,传递得与行等价。 最后证第三条可以导出第一条。根据行等价的定义,必有。根据方才证明的结论:初等矩阵是非奇异的,根据单位矩阵的性质:单位矩阵也是非奇异的。因而也是非奇异的,且。 证毕 根据第三条,我们就可以知道一个求逆矩阵的方法了:既然,我们给等号两端同时乘一个,得到。因此又与行等价。前两个方程是一对等价方程,我们换元,假设,两个方程如下:。因此增广矩阵可以被化简为。我们只需高斯消元将分隔线左侧化成,右侧自然就是逆矩阵了。 例3.4.1 How Aranaras Measure Timeflow 兰那罗的时间观念 你在须弥冒险时,遇到了森林可爱的孩子们——兰那罗。这些小小的生物有着与世无争的纯净心灵、以及大大的胸怀。你们一同冒险,击败了桓那兰那故土的污秽化身,拯救了须弥森林。然而,在和兰那罗对话期间,除开他们奇妙的比喻之外,还有一件事情是你久久无法忘怀的——他们的时间单位。你听过最多的是“种子长成大树”、“太阳升起又落下”、“落落梅从出生到长大”、“大树长成雨林”…… 假如你们经过很长一段时间的交谈,你渐渐明确了各种时间描述词之间的数学关系,关系如下表。请你求出每个描述词所对应的时间间隔 已知大树长成雨林的时间是种子长成大树的50倍;树木从种子长成大树的期间,落落莓已经生长过整整15次了(由种子出生到果实成熟和从成熟到下一颗种子扎根生长的时间相同);兰那罗从种子长成大树期间,普通人已从黑发少年变为白发苍苍的老人了;普通人从青年到老年的时间足够让三颗种子先后成长为大树;一片树木生长成为雨林,不仅足够让个人先后从少年变为老年,而且还需要额外的60年时间完全长成一片健康的雨林。请问“大树长成雨林”、“树木从种子长成大树”、“兰那罗从种子变成大树”、“落落莓从扎根到成熟”以及“普通人从少年到老年”所经过的时间各是多少年?(四舍五入到最近整数,单位:年) 问题分析:既然各个描述词对应时长的倍数关系都已给出,我们可以两两列出方程组求解。这里我们用到矩阵的逆来方便求出方程的解。 算法设计:首先将各个描述词用未知数表示出来,再用数学关系表示出题干中各个描述词的关系,如此得到的5个方程恰好能使矩阵有唯一解。因为一般的方程可以写成的形式,所以求出的逆矩阵,再对常数项组成的列向量进行左乘即可。 解:设“大树长成雨林”、“树木从种子长成大树”、“兰那罗从种子变成大树”、“落落莓从扎根到成熟”以及“普通人从少年到老年”的时间分别为年。根据题干描述。可以得到如下关系: 整理得: 对应系数矩阵。常数矩阵,未知数矩阵。对应方程为。 两侧同时乘以得:。根据逆矩阵求法,初始矩阵为 高斯消元后,将消成形式,得:。的逆矩阵就是。 根据方程,得到,此时。 即 因此,“大树长成雨林”的时间是年、“树木从种子长成大树”需要年、“兰那罗从种子变成大树”需要年、“落落莓从扎根到成熟”需要年、“普通人从少年到老年”需要年。 最后,森林会记住一切。 第五节 行列式的性质 感谢初等矩阵的加持,我们需要记背的知识点又多了不少呢…… 我们在第三节说了,用余子式计算矩阵行列式时,需要按照同一列或者是同一行展开。为什么不能沿对角线或者是其他花里胡哨的顺序算余子式呢?下面有个引理告诉你原因: 设为的方阵,表示的代数余子式,则: 不难发现,的情况就是沿同一列的余子式展开。假如,原式就是沿第一行、从第一列到第列元素的余子式之和。而这恰好是一个矩阵的余子式展开(人家行列式就是这么算出来的,肯定是对的),因而结果等于。当时,就是上边说的花里胡哨的展开。为了证明它,我们假设一个新的矩阵。它的第行被替换成原矩阵的第行,这样的话这个余子式展开就是的正确的余子式展开,也就是说它的结果等于。然而有两行是相同的,也就是说它不可逆(最简阶梯形的最后一行全为0),因而,结果也就是。 假如,那如果有一个初等矩阵左乘它进行行变换,乘积的行列式是否也等于呢?接下来就来探究这个问题: 假如为一个的第I类初等矩阵,且是单位矩阵交换第一、二行得来的。假设为一个的方阵。那么,那么,而,所以。 推广到矩阵,假设方阵是交换一、三行得来的。那么按照第二行展开余子式就是:。 根据矩阵行列式的性质有。 因此对于的方阵,交换其中两行对行列式的影响是改变其符号。其余两类矩阵自行证明,总规律如下: ,且是第类初等矩阵且是第类初等矩阵是第类初等矩阵。 洛谷例题: P7112 [模板] 行列式求值 P4783 [模板] 矩阵求逆 第四章 向量空间 第一节 欧几里得向量空间 简称欧氏空间,表示一个维欧氏空间。我们在高中立体几何部分接触了向量在空间内的表示方法,一般来说它们都使用行向量表示一个由原点指向的向量。线性代数中为了区分,大多数时候使用列向量来表示与上边相同的行向量。 如果仅把描述成由原点指向的有向线段,显然是不太合理的。根据向量知识,一段由指向的有向线段也可以用来表示。因此对于一个列向量,它可以在对应维度空间内画出无数个起点和终点各不相同的向量图像来。如果根据这个原理,列向量表示法就失去了唯一性…… 事实不然,我们发现,无论这个向量的起点如何变化,它们的方向(辐角)、长度(模长)相同,它们可以经过平移变换成同一个向量。只要确定以上这两项的值,一个维向量也就随之确定了。 (向量可以通过平移变为向量,这两个向量是相等的,都可以用表示) 根据勾股定理可以计算出向量的长度,这叫做向量的模长,的模长一般写作,数值上等于。若是上的一个普通向量,就有。这些是我们高中时期就学习过的内容。 高中数学教材在虚数那一章还有一个选学知识(2023版)——辐角。尽管它标成“选学”,其实我们早在三角函数的几何表示里就接触过辐角了:一个起点是原点的向量可以看作是它从轴正半轴逆时针旋转得来的,这里的就是向量的辐角。它很有用——是算法中单位根操作的灵魂,被广泛用于电子设备的自然信号处理,你桌面美化包里的频谱图的底层实现就是算法。讲解见此。 我们定义向量的数乘运算:辐角不变,模长相乘。图示: () 我们定义向量的加法,参见高中物理合力与分力的知识。矢量(既有方向又有大小的量)的加法遵循平行四边形法则,平行四边形法则如下图: 即以要进行加法的两个共起点向量为平行四边形的相邻边,做出完整的平行四边形,它们的和向量的起点与前两个向量起点相同,终点是平行四边形的对角顶点。上图中。 和平行四边形法则等价的还有三角形法则: 即将其中一个向量的起点平移到另一个向量的终点处,和向量的起点是后者的起点,终点是前者的终点。上图中,注意向量的字母表示有先后顺序,因此不可颠倒变成,事实上。 在向量表示中:。因此向量相加,坐标相加。 减法则是坐标相减,将减数向量做反向同模长的反向量再进行加法运算即可。 由于矩阵可以拆分成一个个列向量和行向量,而且矩阵的加法与数乘均与刚刚介绍的向量的加法与数乘规则相同。因此矩阵具备表示向量组的条件,称之为向量空间。向量空间中定义的加法和数乘需要满足如下几条(假设为向量,为标量/常数): 好多啊ccc,其实就是需要把“加法”定义成正统的加法(满足交换律、结合律);“数乘”定义为正规的数乘(满足结合律、分配律,没有交换律)。可以发现矩阵的加法和数乘和它完美匹配!因此矩阵可以作为一个向量空间。 于是,向量空间中的元素称作向量。因为这个空间需要包罗万象,就像宇宙空间要包含我们赖以生存的地球一样……它包括我们所需要的向量,因此向量运算最基本的两种——加法与数乘运算所导出的结果必须也在向量空间内,这叫做向量空间内加法和数乘的封闭性,向量空间必定符合这个性质。如此一来,向量空间就足以作为向量所生存的“宇宙空间”了。 当然有时我们并不需要那么多空间,好比一个人住一个城市……先不提城市各项环节能否正常运作,如果只是用来溜达的,那也是太过巨大了,有些地方可能你一辈子也取不到,还不如开始就不要。向量空间其实也可以像这样压缩范围,并且压缩后的向量空间也必须是全集的子集。根据向量空间的定义,该空间内的向量做任意加法和数乘运算得到的结果都得是空间内的向量。若向量空间的子集满足加法和数乘运算的封闭性,那么是的一个子空间。特殊地,与都是的子空间,称作零子空间,其他非零且不等于的子空间称作真子空间(类比集合的空集、子集和真子集概念)。 在矩阵中,也存在零空间。它表现为矩阵方程在上的解集。我们首先验证数乘封闭性,;紧接着是加法封闭性:。封闭性得证,因此是的子空间。这种空间被称作矩阵的零空间,通常用表示的零空间。 例4.1.1 Merusea Village Portal 海露村传送门 自从你来到枫丹,知晓了水仙十字结社的秘密之后,奇怪的事情开始在你身边上演…… 你在海露村遇见了抽象派美露莘大画师玛梅赫、以及一只发条机关狗西摩尔。很不巧,玛梅赫的作画颜料用完了,于是你们前去收集更加纯净的矿物颜料,期间玛梅赫邀请你们进入一个粉色的漩涡虫洞。或许是因为你前一天冒险到深夜,在这个温暖且舒适的环境下来了困意。一闭眼,再一睁眼,迎接你的不是如同往常一般的新地下区域——而是一片温暖的、舒适的粉色幻境——你被一个人丢在这个传送通道里了! 为了不让派蒙着急,同时也为了你能尽快在下一次困意席卷前逃出这个空间,你需要确定这个传送门是否为“同维度空间卷曲型”——即传送过程中不发生维度的变化。你需要证明你身处的空间是一个三维空间的子空间,这样才能使用正确的方法逃出生天。你发现你的身高和体宽的比值是原来的一半、但是体宽不变。请证明你所在的空间是是三维空间的子空间。 问题分析:首先要根据已有的信息判断该向量空间是否为三维向量空间的子集,然后再验证加法与数乘的封闭性,只有当二者均成立时才能够证明该空间是三维空间的子空间。 算法设计:根据题干最后一句话,我们不妨将主人公设为三维坐标系原点,按照三个坐标轴来建立变换关系。比如说“身高体宽比减半”代表的是现在的轴是轴的一半,假设原身高在轴上有个单位,而现在只有两个单位,证明现在的轴被拉伸了一倍。最后关于封闭性的证明,设出几个具有普遍性的向量证明即可。 解:根据变换关系,得到该向量空间的集合形式。因此为的子集,令, 数乘:;令,,,封闭性得证。 因此,所在空间是三维空间的一个子空间。 后日谈:其实是你网卡了渲染出错了……和什么三维不三维空间没啥关系…… 第二节 基底、张成与张集 假设中有向量,那么称作向量 的线性组合。向量的所有线性组合构成的集合叫向量的张成。 我们都知道,个不共线向量唯一确定一个维平面。假如有向量:和。它们的张成就是(注:最好是验证两个向量在三维空间里的张成,既直观还符合常规认知)它们围成的维平面。方才的和的张成如下图: 如果,则称张成。用表示。有以下两条性质: 若,则为的子空间 向量平面中一组向量的张成是中包含这组向量的最小子空间 对于第一条,因为你怎么拟合平面,都不可能让你的平面比整个空间的维度更高,而且无论以什么系数搭配向量,它们所得的新向量都在整体空间内,第一条就能很简明的证明了。第二条性质,首先空间内向量的张成必为整个空间的子空间,毕竟用的都是数乘和加法,用的向量也都在空间内,总不能算一下加法向量就跑到空间外边去了吧,此外,因为数乘和加法的封闭性,任何经过这两个向量的空间都包含其张成,因此它是最小的。 和张成相对,如果张成,则是的张集。 基底,大家在高中立体几何部分学过了。当时的定义是:平面内不共线的两个向量叫做这个平面的一组基底。然而这段话可以用线性代数的语言原原本本描述出来:“在维向量空间中有个线性无关的向量,则称它们是向量空间的一组基”。线性无关的概念,之前已经简单讲过,总的来说就是向量不共线,即不存在标量,使得;线性相关则反之,指的是两个向量共线,即成立。正如在高中课堂上学的一样,给出一个维空间的一组基底,该空间上所有的向量都可以用这组基底唯一地表示出来。比如下边这个例子: 例4.2.1 Al-Ahmar's Trial 赤王的试炼 你和婕德一行人在圣显厅前击败了图谋不轨的镀金旅团,并在他们搭起的营帐里发现了一封密信。上面写着若想进入圣显厅,需先过三关试炼。为了能够一探黄金梦乡的秘密,你接下了完成三重试炼的任务,然而当你真正进入到第一重试炼时,却发现事情并没有这么简单…… 你进入了试炼场地,却发现整个世界天旋地转。最终安定下来,你发现赤王的神奇科技把你带入了一个维空间内。这还没完,四周又有整齐排列的空气墙阻挡了你的通路。经过好一顿摸索,你终于发现这是一个维空间,于是你开始建立空间坐标系,五个坐标轴分别是,假设你现在所在的地方是原点,通关点。四周的空气墙限制了你仅能沿着与向量平行的方向行动。请问如何安排前进方向使得你能够从起点到达终点? 问题分析:这个问题明显是让我们用来表示出从起点(原点)到终点的一个向量,因为这五个向量不共线,可以作为五维向量空间的一组基底。又因为基底可以唯一地表示出平面上的所有向量,考虑列方程组求解每个基向量的系数关系。 解:明显地,题中五个向量互相线性无关,因此可以作为该平面的一组基。由于向量加法和数乘运算的封闭性,且路径向量在该平面上,因此可以拆分成这些基向量的倍数和形式。 设,则有方程组,方程组的解: 因此,应在方向上移动,在方向上移动,在的反方向上移动,在方向上移动,在的反方向上移动就可以到达终点。 因此一旦选定了平面的基底,该平面上所有的向量都可以用这组基底唯一表示出来,具体操作是使待求向量,接着解方程求出系数的值即可。 基底可以表示平面内所有的向量,故维平面的基张成。 第三节 线性基 第二节里我们讲了向量空间的基底,基底其实还有一个名称叫线性基。平面中所有向量唯一对应一种基底的线性组合。在OI中常常被用于求第大异或和的问题。为了和实数四则运算的线性基区分,这种线性基下称异或线性基 一组值的异或和可以看做该空间内异或线性基的向量的异或组合,由于基底表示向量的唯一性:原集合中的数可以通过异或线性基里的基向量唯一确定。它有如下几个性质,事实上,它和普通平面内的实数线性基有相似之处: 原序列中任何元素都可以通过异或线性基内的元素异或得到 异或线性基不存在重复元素,且在保证性质一的前提下,它的元素最少 异或运算也有一个特殊性质,若,则 根据以上性质构造计算方法: 1234567891011void insert(ll x) { for (int i = 63; i >= 0; i--) { if ((x >> i) & 1) { // 要存放的数的当前位为1 if (!p[i]) { p[i] = x; // 异或线性基该位为0,二进制下该位置为1 break; // 已找到位置存放,退出循环 } x ^= p[i]; // 异或线性基该位为1,为化为下三角形矩阵形式方便计算置为0 } }} 由于一般题目中数据范围是1e18,而转换为二进制位就有位,因此数据类型最好选用无符号长长整型unsigned long long,线性基p数组至少需要60位。 有时并不是所有的插入操作都会成功,因为要保证异或线性基里的向量互相线性无关。存储操作本质上是拆分二进制位,然后将它尽量表示为已有基向量的异或和,好像除去每个人身上的共同特征,只保留人的独特个性一般。如果拆到最后再也拆不了了,证明它是独特的,可以加入其中。反之,这个数就可以被其他数通过异或运算代替,没必要加它,返回插入失败。可以有下面的代码: 123456789101112bool insert(ll x) { for (int i = 63; i >= 0; i--) { if ((x >> i) & 1) { if (!p[i]) { p[i] = x; // 异或线性基该位为0,二进制下该位置为1 break; // 已找到位置存放,退出循环 } x ^= p[i]; // 异或线性基该位为1,为化为下三角形矩阵形式方便计算置为0 } } return x; // 若被异或分解为0,则证明它可以被现有元素计算得到,为保证异或线性基元素互相线性无关,不予插入 } 如果是求一个数能否被这个异或线性基表示出来,将最后一行改为return !x;即可(能表示即不可插入,不能表示即可以插入)。若某次插入失败,证明可以被表示出来,在求最小值是要额外关注!我们在此维护一个布尔值flag = false,在插入失败后设为true表示需要特判。 线性基用于求解一组数的异或和最值问题,有下面求最值的三个例子。它们无一例外使用了贪心法: 1. 求最大值 1234567ll xorMax() { ll ans = 0; for (int i = 63; i >= 0; i--) { ans = max(ans, ans ^ p[i]); } return ans;} 为什么从高位开始遍历?我们都知道如果一个数字的某位数大于另一个数字相同位置的数(两数数量级相同,即十进制下位数相同),那么前者是大于后者的。根据异或的运算法则:“不同为,相同为”。如果ans的高位此时是0,若进行异或运算的同位数字是0,即二者相同,结果为0,不会变得更小;反之若异或运算的对应二进制位为1,当前位异或结果是1,变大了,因此;如果ans高位为1,运算数对应位为0,结果为1,不会变得更大;若运算数当前位是1异或结果为0,变小了,所以。 2. 求最小值 1234567ll xorMin() { ll ans = 0; if (flag) return 0; // 特判0 for (int i = 0; i <= 63; i++) { if (p[i]) return p[i]; }} 我们知道,可以通过任意组合(异或运算)异或线性基中的元素来得出各种新的元素,若无法被表示出来,我们找到异或线性基里最小的元素即可,因为异或线性基里的每个元素也是原序列中某些元素的异或和;反之返回。 3. 求第小值 这才是异或线性基的高级玩法 为了求第小值,首先要对异或线性基进行一轮清扫。将它高斯消元化简为最简形式,称作重构rebuild。 1234567void rebuild() { for (int i = 63; i >= 0; i--) { // 从高位开始按位扫 for (int j = i - 1; j >= 0; j--) { // 遍历右移 if ((p[i] >> j) & 1) p[i] ^= p[j]; // 保证p[i]是异或线性基里第i位最小的那个,通过不断异或可以变小 } }} 接着我们需要特判,如果每一次插入都可以成功进行,向量之间互相线性无关,也就无法表示。在求小值时,若,也就是说求最小值,明显应该返回,如果按照常规思路返回就是错误的,因为这个做法的前提是。所以如果先前的插入操作出现失败的情况,就要对进行特判,原先的实为: 1234567891011121314ll queryKMax(ll k) { if (k == 1 && flag) return 0; // 特判 if (flag) k--; // 特判0,f(k)实为f(k-1) rebuild(); // 重构异或线性基 ll ans = 0; for (int i = 63; i >= 0; i--) { if (p[i]) { // 对k进行二进制分解 if (k & 1) ans ^= p[i]; // 位为1,异或 k >>= 1; } } return ans;} 除了求值,异或线性基还可以合并,甚至于求它和另一个异或线性基的交集与并集。所以异或线性基是一种数据结构。封装在一个结构体XorBase里: 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061struct XorBase { ll p[64]; bool flag; XorBase() { flag = false; memset(p, 0, sizeof p); } bool insert(ll n) { for (int i = 63; i >= 0; i--) { if ((n >> i) & 1) { if (!p[i]) { p[i] = n; break; } n ^= p[i]; } } if (!n) flag = true; return n; } void rebuild() { for (int i = 63; i >= 0; i--) { for (int j = i - 1; j >= 0; j--) { if ((p[i] >> j) & 1) p[i] ^= p[j]; } } } ll getMin() { if (flag) return 0; for (int i = 63; i >= 0; i--) { if (p[i]) return p[i]; } } ll getMax() { ll ans = 0; for (int i = 63; i >= 0; i--) { ans = max(ans, ans ^ p[i]); } return ans; } ll MaxK(ll k) { if (k == 1 && flag) return 0; if (flag) k--; rebuild(); ll ans = 0; for (int i = 63; i >= 0; i--) { if (p[i]) { if (k & 1) ans ^= p[i]; k >>= 1; } } return ans; }}; 4. 并集 思路就是枚举异或线性基的内容,将其中元素全部加入到中。 12345678910XorBase Union(XorBase A, XorBase B) { XorBase res = B; for (int i = 0; i <= 63; i++) { if (A.p[i]) { res.insert(A.p[i]); } } return res;} 5. 交集 如果一个异或线性基里的元素插入到另一个异或线性基里会失败,则将它插入到交集异或线性基中。 123456789101112XorBase Intersect(XorBase A, XorBase B) { XorBase res; for (int i = 0; i <= 63; i++) { if (A.p[i]) { if (!B.insert(A.p[i])) res.insert(A.p[i]); } if (B.p[i]) { if (!A.insert(B.p[i])) res.insert(B.p[i]); } } return res;} 例4.3.1 DMG Bonus 核爆 作为一名资深神原玩家,你希望能在新限定五星角色初进卡池时尽快拿下全网首个999w核爆记录,以此证明自己的实力。现在你已经在游戏里做好了很多伤害加成型的食物,准备在boss战时一展身手。战斗开始时,你首先给角色吃下了基础食物(每局开始前必吃的食物),它的效果是在300秒内单角色爆发伤害增加,但是同时它有一个副作用…… 基础食物生效期内,如果角色吃下其他伤害加成型的食物,总伤害加成的百分比数值将是各种食物的伤害百分比数值的异或之和,即,表示,为异或符号。各种食物的伤害加成在下边给出,如果不吃任何加成型食品(也不吃基础食品),爆发伤害期望值为。吃完所有食物后,如果你用增伤角色施加了的爆发增伤。请问你的最大爆发伤害能否达到,即?若不能,最高伤害是多少?(令每种食物只有一份,且食物效果均可叠加,结果四舍五入到万位) 编号 加成效果 1 270% 2 200% 3 280% 4 200% 5 180% 6 150% 7 75% 问题分析:题干信息已经很明显了,这是一道异或线性基的最大和问题。根据上文所述程序计算即可。 算法实现:这里使用的是结构体封装版本的异或线性基计算代码: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081#include <bits/stdc++.h>using namespace std;typedef unsigned long long ll;struct XorBase { ll p[64]; bool flag; XorBase() { flag = false; memset(p, 0, sizeof p); } bool insert(ll n) { for (int i = 63; i >= 0; i--) { if ((n >> i) & 1) { if (!p[i]) { p[i] = n; break; } n ^= p[i]; } } if (!n) flag = true; return n; } void rebuild() { for (int i = 63; i >= 0; i--) { for (int j = i - 1; j >= 0; j--) { if ((p[i] >> j) & 1) p[i] ^= p[j]; } } } ll getMin() { if (flag) return 0; for (int i = 63; i >= 0; i--) { if (p[i]) return p[i]; } } ll getMax() { ll ans = 0; for (int i = 63; i >= 0; i--) { ans = max(ans, ans ^ p[i]); } return ans; } ll MaxK(ll k) { if (k == 1 && flag) return 0; if (flag) k--; rebuild(); ll ans = 0; for (int i = 63; i >= 0; i--) { if (p[i]) { if (k & 1) ans ^= p[i]; k >>= 1; } } return ans; }} A;int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n; cin>>n; for (int i = 1; i <= n; i++) { int x; cin>>x; A.insert(x); } cout<<(1400000 * (A.getMax() + 60 + 70) / 100)<<endl; return 0;} 运行代码,在输入框输入: 12345678727020028020018015075 结果输出:8162000.000。小于所给的。因而不能达到目标,最高伤害816万。 洛谷例题: P3812 [模板] 线性基 P4570 [BJWC2011] 元素 P4301 [CQOI2013] 新Nim游戏","categories":[{"name":"自学的数学","slug":"自学的数学","permalink":"https://justpureh2o.github.io/categories/%E8%87%AA%E5%AD%A6%E7%9A%84%E6%95%B0%E5%AD%A6/"}],"tags":[{"name":"算法","slug":"算法","permalink":"https://justpureh2o.github.io/tags/%E7%AE%97%E6%B3%95/"},{"name":"学术","slug":"学术","permalink":"https://justpureh2o.github.io/tags/%E5%AD%A6%E6%9C%AF/"},{"name":"数学","slug":"数学","permalink":"https://justpureh2o.github.io/tags/%E6%95%B0%E5%AD%A6/"},{"name":"教程","slug":"教程","permalink":"https://justpureh2o.github.io/tags/%E6%95%99%E7%A8%8B/"}]},{"title":"2023年度总结——机房管理软件的破解经验","slug":"new-year-crack","date":"2023-12-31T04:22:54.000Z","updated":"2024-02-16T03:04:53.676Z","comments":true,"path":"new-year-crack/","link":"","permalink":"https://justpureh2o.github.io/new-year-crack/","excerpt":"","text":"文中提到的核心程序代码及食用方法在文章末尾处,或者访问我的云剪贴板来复制代码 更新条目的链接 极域——世界上最弱小最单纯的机房软件 注意,极域由C/C++语言开发。对于极域的反编译工作可以基本认定为徒劳且耗费大量时间的。 开始的开始,我的脱控方式还仅限于最原始的taskkill和ntsd。这种做法不仅有时会失效,而且一旦老师发现你的机子的监控屏幕是纯黑一片、且无法控制,他就会气急败坏地冲向你对你进行一顿输出,结果自然是被班主任教训一顿、这学期的信息课停上。 令人欣慰的是:这种低级脱控方式已经在学子之间渐渐隐没不见,取而代之的是层出不穷的脱控软件,例如JYTrainer、还有本人开发的ClassX(doge)等等…… 因为本人不会那些所谓的网络IP、频道更改之类的高科技东西,另一方面实现如上的功能多半需要辅助程序(容易被反脱软件检测到进程名)。本着精简实现、不易查封的原则,我从非exe层面出发,编写了一套脱控程序供大家伙们免费使用,毕竟人生苦短,及时行乐嘛(doge)。 板块一 TD到底是啥的缩写? 你知道明明U盘里装着几个G的学习资料却无法在计算机课上给周边的同学炫耀是怎么样一种感觉吗?你知道明明想要打开小破站观看最爱的coser投稿的新擦边视频却被提示“该网站已被禁止”是什么样的感觉吗? 出于以上两种痛苦的经历,我立志要写出能够禁止极域牛马功能的脚本。就先从U盘解禁和网络解禁两个方面入手! Windows服务概述:打开任务管理器,选项卡里不仅有经典的“进程”选项、也有装机大佬们引以为傲的“性能”选项,可是我们今天的主角:“服务”选项却几乎无人问津。 类似于cmd的打开方式,服务管理器则需要在Win+R后输入services.msc来使用;你也可以通过任务管理器“服务”选项卡进入。那么什么是服务呢? Windows服务是指系统自动完成的,不需要和用户交互的过程,可长时间运行的可执行应用程序。这些服务可以在计算机启动时自动启动,可以暂停和重新启动而且不显示任何用户界面。一个词概括就是:“幕后黑手”。开头立的flag就需要通过这种方式巧妙解决。 定位到极域安装目录:会发现下面有好多TD打头的文件,而当你在服务里面搜索时,你会发现一个惊人的巧合:TDNetFilter和TDFileFilter早已在你的机器上悄然运行了很久。看到它的名字,容易知道前者禁掉了你的网络、后者ban掉了你的U盘。如何终止服务呢?这也非常的简单: 在Windows系统中,与服务有关的命令是sc。要想停止某个服务,只需安装如下模式输入指令:sc stop [NAME](NAME是服务名称)。于是我在ClassX的开头加入了如下的指令: 12sc stop tdnetfiltersc stop tdfilefilter 这样就结束了吗?然而并没有…… 板块二 可疑的程序 上一节里遗留了一个小问题:停止了服务后他就真的解禁了吗?事实并非如此:没过几秒,你的网络又会恢复到先前的状态、U盘再次被封杀。一切的一切都是因为两个不起眼的可疑程序…… ProcHelper64.exe和MasterHelper.exe——《我们俩》 有人问我当时是怎么发现的。首先需要知道,每个版本的Windows系统几乎都有一套特别的图标主题(图标存放在Shell32.dll中),现如今大部分机房电脑使用的是Win10系统,然而上述两个进程使用的是WinXP风格的图标,直接一眼丁真掏出taskkill秒了。真是实力坑队友。 因此ClassX里面还有这一段代码: 12345:ataskkill /f /t /im ProcHelper64.exetaskkill /f /t /im MasterHelper.exegoto a :a定义了一个函数a,中间是函数体,最后一行的goto a则是调用这个函数,注意goto a写在了a函数内部,起到了while (true) {...}的死循环作用。你也可以在空行出添加一段TIMEOUT /T 1,即延时一秒,因为这两个程序的复活时间大概在1秒左右(终止后一秒就会重启)。 板块三 拒绝访问什么鬼? 第一种情况:钩子程序 如果你是Win7及以下的系统,且直接使用任务管理器结束进程,那么很有可能会出现像标题这样的提示。这是因为极域启动了一个系统钩子(四川人莫笑,Hook翻译过来的确是钩子的意思)。 Windows钩子概述:类似于游戏(以及Scratch)的消息机制,Windows中存在一种事件系统,Win+R弹出运行、输入eventvwr.exe/eventvwr.msc打开事件管理器,你会看到本机所有事件的发生时间及概况。把Windows系统的事件系统比作一条河流,最上游是系统,负责抛出事件,事件信息顺流而下;把应用程序比作渔夫,它们在河岸两侧用网捞特定类型的事件,大多数情况下自行处理后再放回到河中。 对于极域来说,它在一个名叫NtTerminateProcess的系统函数上下钩,检测这个函数的传入信息,即终止对象的进程名,是否是StudentMain.exe(极域主程序),若是,就返回false,也就是失败。因而导致开头所说拒绝访问的情况,而把钩子钩在此处的,就是我们的TD圈大佬LibTDProcHook.dll。因为本人使用Win10系统,这个钩子对于Win7以后的系统都会失效,因此Win8/10/11用户可以直接用任务管理器。对于Win7系统用户,在这里使用WinAPI终止这个TD模块。 1234567891011121314151617181920212223242526272829303132#include <bits/stdc++.h>#include <windows.h>#include <tlhelp32.h>#include <processthreadsapi.h>using namespace std;DWORD GetPID(const char* proc) { PROCESSENTRY32 entry; entry.dwSize = sizeof(PROCESSENTRY32); HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); if (Process32First(snapshot, &entry) == TRUE) { while (Process32Next(snapshot, &entry) == TRUE) { if (stricmp(entry.szExeFile, proc) == 0) { HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID); DWORD pid = GetProcessId(hProc); CloseHandle(hProc); return pid; } } }}int main() { HMODULE hook = GetModuleHandle(\"LibTDProcHook64.dll\"); FreeModule(hook); HANDLE handle = OpenProcess(PROCESS_TERMINATE, FALSE, GetPID(\"StudentMain.exe\")); TerminateProcess(handle, 0); return 0;} 第二种情况:时代变了 自从学校机房的极域从2014版更新到了2020版,上述朴素解决方案已经不见效了。我也不知道从哪一年的版本开始,它给自己的服务加了一层防护,普通地运行bat脚本还木有用。但是它解决起来也简单,右键文件“以管理员模式运行”即可。 除此之外,你还可以在脚本开头加入: 1234567891011>nul 2>&1 \"%SYSTEMROOT%\\System32\\cacls.exe\" \"%SYSTEMROOT%\\System32\\config\\system\" if %errorlevel% == 0 ( echo Admin Switched!) else ( echo Level Ascending... Restart powershell -command \"Start-Process '%0' -Verb RunAs\" exit) 来实现UAC自动提权管理员! 板块四 挂起进程 有一天我的同学给我推荐了这个方法,说是用一个命令行程序Suspend来命令层面挂起极域进程实现随意脱控,亲测有效。如果使用性能监视器也可以达到相同效果。 挂起为何物? 大家可能有过这样的经历:当你用WPS做PPT或者正在用WPS演示PPT时,有时它会莫名其妙地卡掉,尤其是你画了太多墨迹注释时,看着永不停歇转动的“繁忙”鼠标图标,你也许会耐不住性子直接任务管理器结束进程,并发誓要下载一个破解版的微软Office全家桶来用。像这样,程序的卡死就是挂起的一个形式,当然,当CPU面临有限的内存分配问题时,它会优先分配运存给那些需要内存的重要程序而把不那么重要的进程挂起,表现为对用户操作无响应等。 那么你可能已经猜到了这一方法的逻辑了:我们挂起极域主进程。这样当教师端发送指令(黑屏安静、全屏广播等)时,你这边的极域接收端(学生端)就无法对指令作出响应,自然也就不会被控制。桌面监控同理,也会被影响,不同的是,教师端的监控小窗只会定格在你挂起极域前传输过来的最后一帧画面,总之瞒天过海是基本上没问题的了…… 根据上述原理,我们有两种方式来挂起一个进程(其实本来还有Win32API这种方法,留给读者自行研究): 第一种 性能监视器 你可以打开任务管理器,在“性能”一栏的左下角可以看到“性能监视器”选项(Win10),对于Win11用户,则需点击“性能”栏右上角三个点,然后选中“性能监视器”;也可以Win+R输入perfmon.exe /res直接打开(万能)。还有几种方法见百度百科。 在性能监视器中,我们在最上面“进程”列表中找到StudentMain.exe(一般来说有两个同样的进程),接着挨个右键点击“暂停进程(S)”即可。 但是这样的话,你在教师端那边的小窗口上就会显示出一个性能监视器的窗口,感觉不太完美,怎么能优化一下呢? 第二种 Suspend命令行 PS Suspend - Microsoft Learn PS Suspend微软官方下载地址 下载后的压缩文件里面有一个.cmd文件,用记事本打开: 12345chcp 65001@set suspend_targets=osu!.exe DDLC.exe@suspend.exe %suspend_targets%pause@suspend.exe -r %suspend_targets% 其实我们真正需要修改的内容是第二行:它使用bat批处理脚本设置变量suspend_targets,传入需要挂起进程的进程名称话说DDLC是真的生草……。这里我们修改参数值为StudentMain.exe: 12345chcp 65001@set suspend_targets=StudentMain.exe@suspend.exe %suspend_targets%pause@suspend.exe -r %suspend_targets% pause之后的那一行是解除挂起的代码,因为bat执行到pause语句后会等待用户输入任意字符后才继续进行,因此如果遇到紧急情况需要解除挂起,只需在命令行窗口点击任意键即可。 需要注意的是,一定要把下载好的压缩包里面的所有文件放到同一个目录下,否则缺失任何文件这个工具都是无法正常运行的。 板块五 留给2024的一个小问题 那天我在思考如何一劳永逸的结束极域进程,我打开了服务列表,在里面看到两个纯大写拼成的服务名GATESRV和STUDSRV。可惜的是那天放学,我没能来得及探究清楚这两个服务与极域的关系,目前已知的信息就是它们绝对是极域自己启动的两个服务。 这个问题就留给2024的我解决吧 // TODO 红蜘蛛软件——可曾听闻我绿蜘蛛脚本的厉害? 在本人印象中,红蜘蛛似乎就仅仅只是一个吉祥物,只有在开机后那么几秒,它拖着上世纪复古风的“高清”启动界面在我的眼前一闪而过,然后静静地躲在任务栏的小图标里,践行它大隐隐于市的人生信条…… 说实话要不是同学提醒我还真忘了机房里还有这位叫红蜘蛛的朋友,于是我着手开始破解它。红蜘蛛:我吃柠檬 1. 这玩意怎么跟2345一个德行? 知道2345全家桶的同学们肯定对它恨之入骨,尤其是那些下载了2345的同学们。2345号称天朝第一大流氓软件,在无数人的电脑中如同鬼魂一般挥之不去。捆绑安装、弹窗广告、强制修改系统文件、浏览器劫持……无奇不有,关键是它的公司甚至推出极其出生的“推广包”机制来诱惑不良商户分发2345毒瘤软件。这篇文章介绍了清除2345的一种方案。 回到本节主题上来,为什么会取这样一种怨气十足的标题呢?是因为它和2345伪装成系统文件类似,红蜘蛛属于是反向利用了系统文件来给自己加上一层保护网。 打开任务管理器,除了霸占后台程序第一行的红蜘蛛本体,下面还有两个附属程序,名叫“3000soft通用组件”,如果直接终止进程,它很快会再次冒出来。将它们展开后发现叫做checkrs.exe和rscheck.exe的程序。那么运用上边经常用到的服务搜查法,我们发现了两个命名规则极其相似的服务:appcheck2和checkapp2。 然而我事后才发现红蜘蛛官网早已自报家门了……血亏! 常规思想:我们使用sc命令结束这两个服务,然而…… // TODO 显示无法停止,那怎么办呢? 考虑到这两个进程是红蜘蛛死掉后无限重启的命根,并且这两个进程也跟红蜘蛛主程序一样杀了就会重启……很明显,根本原因就是那两个服务,但是sc命令不管用了,咋办呢?(抠头) 这时我们就需要绕道而行,既然命令不行,我们转战注册表!打开注册表管理器,定位到HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services文件夹,它有很多个子文件夹,在下面定位到appcheck2和checkapp2,它的文件结构类似于这样(这里用别的服务替代一下): (注意,这个并不是红蜘蛛的服务,是我临时找别的替代的,它们的文件名相同,只是数据不同而已) 容易发现:ImagePath项指向了服务的根文件地址,也就是俗称的万恶之源,既然每次终止组件后它会自动重启服务,那我们为何不破坏这个ImagePath,让它指向一个不存在的地址,这样它就启动不了任何东西了。在我的绿蜘蛛inf文件里如此写到: 123456789101112[Version]Signature=\"$CHICAGO$\"Provider=justpureh2o@outlook.com, 2023[DefaultInstall]DelReg=DeleteAddReg=RedSpiderService.ValueModify[RedSpiderService.ValueModify]HKLM,\"SYSTEM\\CurrentControlSet\\Services\\appcheck2\",\"ImagePath\",0,\"C:\\Windows\\SysWOW64\\rschck.exe\"HKLM,\"SYSTEM\\CurrentControlSet\\Services\\checkapp2\",\"ImagePath\",0,\"C:\\Windows\\SysWOW64\\chekrs.exe\" 然后你就可以用任务管理器终止两个通用组件,紧接着就可以终止红蜘蛛了! 由于本人目前对红蜘蛛知之甚少,可以看这篇文章了解更多! 学生机房管理助手——闻着臭吃着香 1. 不用逆向,能得到什么结论? 其实一开始我以为它和极域一样是基于C++/C开发的因此无法反编译,直到回家之后我自己下载了一个。杀毒软件报毒删除了set.exe,打开main.exe主入口程序时它突然弹出了一条C#式的通知框提示set.exe未找到。于是果断打开dnSpy开启后面的破解,反编译破解的内容将在后面涉及到。 首先看到他的文件目录↓ 其中zy文件夹中存放的是各种浏览器的exe可执行文件,猜测是覆盖现有的高版本浏览器,以便它操作注册表禁止各种功能。 有一定经验的同学想必会一眼看到可疑的yl.reg注册表文件,但是先别急着合并注册表。首先,你的机器可能已经被禁用了注册表和任务管理器;第二,这个文件里也不是你心心念念的破解注册表(虽然后面我们会利用它破解机房管理助手)。对于未知的事物,最好还是保持谨慎勿近的态度为好…… 除此之外,一个名叫jfglzs.exe的程序吸引了我,根据我多年混迹于首拼梗圈的我一秒钟就反应过来,知道它就是“机房管理助手”的首拼。我们之后的破解也围绕着这个东西进行。 第一问 任务管理器、注册表、组策略咋解 本人Win11系统,正常情况下任务栏设置上端会有一个任务管理器选项。 如果你稍微懂一点高级知识,你也许会使用Win+R,并输入taskmgr试图使用任务管理器。然而这不可能奏效,因为你会接到一则提示: 输入regedit(注册表)和gpedit.msc(组策略管理器)也是一样的道理。很少很少的高材生会使用mmc试图加载组策略,但是这样也不可能奏效。搜索资料发现,修改注册表的某些键值可以实现禁用组策略、注册表、任务管理器的功能。深度分析yl.reg时就会发现这些东西: 第一行翻译过来就是:“禁用任务管理器”,它的值被设置成了1,也就是true。这一块还有禁止更改密码、禁止切换用户的设置等等。对于组策略,它的两个值则是存放在注册表:HKEY_CURRENT_USER\\Software\\Policies\\Microsoft\\MMC中的RestrictToPermittedSnapins;和它的子目录HKEY_CURRENT_USER\\Software\\Policies\\Microsoft\\MMC\\{8FC0B734-A0E1-11D1-A7D30000F87571E3}中的Restrict_Run。如果不出意外,它们的值都是非零的,意味着组策略被禁用了。要想破解,我们就需要用一个不直接调用注册表的方式来添加/更改注册表值,这也就是下面将要提出的inf安装文件法。 INF安装文件的机制 提起绿色版软件,大家应该不会陌生,它省去了冗杂的dll等库文件,仅仅一个exe文件驱动整个程序。在绿色版软件安装时,有时就是用的inf文件安装法。一个可运行的inf文件包含几个项: 123[Version]Signature=\"$CHICAGO$\"Provider=somebody Version段包含inf文件的基本信息,其中Signature指定了文件的适用系统,常见的值有MS、WindowsNT等,这里我们使用CHICAGO获得最广泛的支持(注意美元符号和引号的书写)。 123[DefaultInstall]DelReg=DeleteAddReg=Add 这一段声明了安装时所需的函数,DelReg负责删除注册表,AddReg负责创建/修改注册表。基本语法如下: DelReg:[ROOT] [PATH] [NAME],ROOT就是注册表中HKEY开头的那些,你可以写全称,也可以写缩写形式(HK+后两个单词的首字母,HKEY_LOCAL_MACHINE=HKLM);PATH是包含指定键值的文件夹路径;NAME就是键值的名字。 AddReg:[ROOT] [PATH] [NAME] [TYPE] [VALUE],TYPE指定了注册表值的类型(0相当于缺省,默认字符串;1为DWORD值,设置十六进制值时只需两个数字一组,中间逗号分隔开,一定保证输入的十六进制为8位,一定记得写前导0!);VALUE即为键值,值为字符串时需要在前后打上半角双引号。 等号右侧的值相当于C++中的typedef,用来重命名函数,因此,在后续的安装代码中,我们的字段标识符都要与等号右侧的值相符才可,在我们的inf中,它表现为这样(inf文件的注释用分号表示): 12345678910111213[Delete]HKCU,\"Software\\Policies\\Microsoft\\MMC\",\"RestrictToPermittedSnapins\"HKCU,\"Software\\Policies\\Microsoft\\MMC\\{8FC0B734-A0E1-11D1-A7D30000F87571E3}\",\"Restrict_Run\"[Delete]HKCU,\"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\",\"DisableRegistryTools\"HKCU,\"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\",\"DisableTaskMgr\"HKCU,\"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\",\"DisableChangePassword\"HKCU,\"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\",\"DisableCMD\"[Delete]HKCU,\"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\",\"DisableSwitchUserOption\"HKCU,\"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\",\"HideFastUserSwitching\" 在记事本里编辑即可,记得保存为.inf文件,而后右键“安装”,或者在cmd里运行:InfDefaultInstall + inf文件地址(前提是你的cmd没被禁止)。 除此之外,我们发现了一些好玩的东西:yl.reg的最后几十行,将常用浏览器的起始界面通过注册表的方式修改成了它的官网,学有余力的娃们可以通过刚才介绍的AddReg函数把它的值改成你想要的值,在这里我换成了我精心制作的嘲讽页面: 1234567891011[Add]HKLM,\"SOFTWARE\\Policies\\Microsoft\\Internet Explorer\\Main\",\"Start Page\",0,\"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23\"HKLM,\"SOFTWARE\\Microsoft\\Internet Explorer\\MAIN\",\"Start Page\",0,\"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23\"HKLM,\"SOFTWARE\\Microsoft\\Internet Explorer\\MAIN\",\"First Home Page\",0,\"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23\"HKLM,\"SOFTWARE\\Wow6432Node\\Baidu\\BaiduProtect\\LockIEStartPage\",\"Start Page\",0,\"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23\"HKLM,\"SOFTWARE\\Wow6432Node\\Software\\Microsoft\\Internet Explorer\\Main\",\"Start Page\",0,\"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23\"HKLM,\"SOFTWARE\\Wow6432Node\\Software\\Microsoft\\Internet Explorer\\Main\",\"Default_Page_URL\",0,\"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23\"HKEY_USERS,\".DEFAULT\\Software\\Microsoft\\Internet Explorer\\Main\",\"Start Page\",0,\"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23\"HKEY_USERS,\".DEFAULT\\Software\\Microsoft\\Internet Explorer\\Main\",\"First Home Page\",0,\"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23\"HKEY_USERS,\"S-1-5-18\\Software\\Microsoft\\Internet Explorer\\Main\",\"Start Page\",0,\"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23\"HKEY_USERS,\"S-1-5-18\\Software\\Microsoft\\Internet Explorer\\Main\",\"First Home Page\",0,\"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23\" yl.reg——队友坑害全队的典型例子。 当一切完成之后,你就可以自由使用任务管理器了,被锁定了cmd的同学们也可以尽情使用taskkill了!诶等等,事情好像有点不对劲…… 第二问 我的taskkill去哪了 可是我的taskkill还好好地躺在System32文件夹里啊 机房管理助手一启动,所有使用taskkill的脚本/程序都会失效,属于是老阴B了。如果不逆向破解,我还真不清楚这是怎么做到的。总之你可以在网站上下载一个taskkill(对上网下载一个下来),或者顶住巨大的学习难度学习WinAPI(TerminateProcess函数)写出一个拔山盖世的C++程序来。这一节就不多赘述其他内容了…… 第三问 yl.reg到底写了啥 其实最扎眼的就是它里面写的宣(补)战(贴)名单各种脱控工具箱,说实话那些工具箱软件我基本上一个都没见过…… 这些注册表项有一个很普遍的特征,它们无一例外指向了注册表HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\Windows\\safer\\codeidentifiers\\0\\Hashes下很多以GUID形式命名的文件夹,那么这些文件夹具体起什么作用呢? 这其实是组策略管理器的黑名单,具体见此,没错,组策略可以限制指定软件的运行。但是很遗憾,这些配置全部存放在上述的注册表里面。你可以把注册表看做系统的配置文件,操作系统几乎所有配置信息、甚至包括大部分软件程序的配置都存放在注册表中。这么看来除了BIOS没别的安全地方了 如果想要禁用这些项,并不需要挨个将每个文件删去,而是看到他的其中一个父文件夹codeidentifiers。它里面有一个二进制值authenticodeenabled,它指定组策略黑名单的ID标识符,也就是codeidentifier文件夹下以数字命名的文件夹,只有当子文件夹的名称与ID标识符相同时才会启用该文件夹下的配置。因此我们釜底抽薪,直接更改authenticodeenabled的值: 12[Add]HKLM,\"SOFTWARE\\Policies\\Microsoft\\Windows\\safer\\codeidentifiers\",\"authenticodeenabled\",1,00,11,45,14 假如我掏出逆向工具,阁下又该如何应对? 正如开头所说,学生机房管理助手由C#开发,因此可以用dnSpy反编译它的可执行文件,得到源码。那么我们就开始吧! 第一框 密码是啥 正如大多数软件那样,机房管理助手对它的源代码进行了一轮套壳,也就是代码混淆。为了让代码变成我们都容易看的形式。我们使用C#脱壳软件NET Reactor Slayer进行反混淆(代码混淆工具为NET Reactor)。 123456789101112131415161718192021222324252627282930313233343536373839404142using System;using System.Security.Cryptography;using System.Text;using System.IO;public class Program{ public static void Main() { // 更改这里的内容 string string_3 = \"12345678\"; // Class6.smethod_0() string value = \"C:\\\\WINDOWS\"; string s = value.Substring(0, 8); string s2 = value.Substring(1, 8); DESCryptoServiceProvider descryptoServiceProvider = new DESCryptoServiceProvider(); descryptoServiceProvider.Key = Encoding.UTF8.GetBytes(s); descryptoServiceProvider.IV = Encoding.UTF8.GetBytes(s2); MemoryStream memoryStream = new MemoryStream(); CryptoStream cryptoStream = new CryptoStream(memoryStream, descryptoServiceProvider.CreateEncryptor(), CryptoStreamMode.Write); StreamWriter streamWriter = new StreamWriter(cryptoStream); streamWriter.Write(string_3); streamWriter.Flush(); cryptoStream.FlushFinalBlock(); memoryStream.Flush(); string string_4 = Convert.ToBase64String(memoryStream.GetBuffer(), 0, checked((int)memoryStream.Length)); // Class6.smethod_3() StringBuilder stringBuilder = new StringBuilder(); for(int i = 0; i < string_4.Length; i++) stringBuilder.Append((char)(string_4[i] - 10)); string_3 = stringBuilder.ToString(); // Class6.smethod_2() MD5CryptoServiceProvider md5CryptoServiceProvider = new MD5CryptoServiceProvider(); byte[] array2 = md5CryptoServiceProvider.ComputeHash(Encoding.Default.GetBytes(string_3)); stringBuilder.Clear(); for (int i = 0; i < array2.Length; i++) stringBuilder.Append(array2[i].ToString(\"x2\")); string str = stringBuilder.ToString().Substring(10); Console.WriteLine(str); }} 同时,机房管理助手的密码MD5文件存放在注册表HKEY_CURRENT_USER\\Software下的字符串值n里面。更改即生效! 代码环节 ClassX 使用方法:另存为.bat文件直接运行 12345678910111213141516171819202122232425262728293031@echo off >nul 2>&1 \"%SYSTEMROOT%\\System32\\cacls.exe\" \"%SYSTEMROOT%\\System32\\config\\system\" if %errorlevel% == 0 ( echo Admin Switched!) else ( echo Level Ascending... Restart powershell -command \"Start-Process '%0' -Verb RunAs\" exit)sc stop tdnetfiltersc delete tdnetfiltersc stop tdfilefiltersc delete tdfilefiltersc stop GATESRVsc delete GATESRVsc stop STUDSRVsc delete STUDSRVregedit /c /s usb_reg.regecho Unhook through Regedit:ataskkill /f /t /im MasterHelper.exetaskkill /f /t /im ProcHelper64.exeTIMEOUT /T 1goto a 绿蜘蛛 使用方法:另存为.inf文件→右键安装;任务管理器先结束进程3000soft通用组件,再结束红蜘蛛软件 1234567891011[Version]Signature=\"$CHICAGO$\"Provider=justpureh2o@outlook.com, 2023[DefaultInstall]DelReg=DeleteAddReg=RedSpiderService.ValueModify[RedSpiderService.ValueModify]HKLM,\"SYSTEM\\CurrentControlSet\\Services\\appcheck2\",\"ImagePath\",0,\"C:\\Windows\\SysWOW64\\rschck.exe\"HKLM,\"SYSTEM\\CurrentControlSet\\Services\\checkapp2\",\"ImagePath\",0,\"C:\\Windows\\SysWOW64\\chekrs.exe\" 学生机房管理助手通用破解 使用方法:另存为.inf文件→右键安装 123456789101112131415161718192021222324252627282930313233343536373839404142[Version]Signature=\"$CHICAGO$\"Provider=justpureh2o@outlook.com, 2023[DefaultInstall]DelReg=DeleteAddReg=Add[Delete] ; 大坏蛋,放开那个组策略管理器!HKCU,\"Software\\Policies\\Microsoft\\MMC\",\"RestrictToPermittedSnapins\"HKCU,\"Software\\Policies\\Microsoft\\MMC\\{8FC0B734-A0E1-11D1-A7D30000F87571E3}\",\"Restrict_Run\"[Delete] ; 注册表和任务管理器我来接手,你可以卷铺盖走人了!HKCU,\"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\",\"DisableRegistryTools\"HKCU,\"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\",\"DisableTaskMgr\"HKCU,\"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\",\"DisableChangePassword\" HKCU,\"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\",\"DisableCMD\"[Delete] ; 我就要切换用户!HKCU,\"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\",\"DisableSwitchUserOption\"HKCU,\"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\",\"HideFastUserSwitching\"[Delete] ; 如果把我桌面搞乱了张伟会清理掉我的文件滴HKCU,\"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\",\"DesktopProcess\"[Add] ; 加点料才香~HKLM,\"SOFTWARE\\Policies\\Microsoft\\Windows\\safer\\codeidentifiers\",\"authenticodeenabled\",1,00,11,45,14HKLM,\"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\",\"NoConfigPage\",1,00,00,00,01HKLM,\"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\",\"NoDevMgrPage\",1,00,00,00,01[Add] ; 嘲讽一波这sb管理助手,关键你就算换成自己的网页学校的破网也加载不出来(笑)HKLM,\"SOFTWARE\\Policies\\Microsoft\\Internet Explorer\\Main\",\"Start Page\",0,\"https://justpureh2o.github.io/misc/\"HKLM,\"SOFTWARE\\Microsoft\\Internet Explorer\\MAIN\",\"Start Page\",0,\"https://justpureh2o.github.io/misc/\"HKLM,\"SOFTWARE\\Microsoft\\Internet Explorer\\MAIN\",\"First Home Page\",0,\"https://justpureh2o.github.io/misc/\"HKLM,\"SOFTWARE\\Wow6432Node\\Baidu\\BaiduProtect\\LockIEStartPage\",\"Start Page\",0,\"https://justpureh2o.github.io/misc/\"HKLM,\"SOFTWARE\\Wow6432Node\\Software\\Microsoft\\Internet Explorer\\Main\",\"Start Page\",0,\"https://justpureh2o.github.io/misc/\"HKLM,\"SOFTWARE\\Wow6432Node\\Software\\Microsoft\\Internet Explorer\\Main\",\"Default_Page_URL\",0,\"https://justpureh2o.github.io/misc/\"HKEY_USERS,\".DEFAULT\\Software\\Microsoft\\Internet Explorer\\Main\",\"Start Page\",0,\"https://justpureh2o.github.io/misc/\"HKEY_USERS,\".DEFAULT\\Software\\Microsoft\\Internet Explorer\\Main\",\"First Home Page\",0,\"https://justpureh2o.github.io/misc/\"HKEY_USERS,\"S-1-5-18\\Software\\Microsoft\\Internet Explorer\\Main\",\"Start Page\",0,\"https://justpureh2o.github.io/misc/\"HKEY_USERS,\"S-1-5-18\\Software\\Microsoft\\Internet Explorer\\Main\",\"First Home Page\",0,\"https://justpureh2o.github.io/misc/\"; TODO 再给你多附赠几个浏览器hhHKCU,\"Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\CurrentVersion\\AppContainer\\Storage\\microsoft.microsoftedgedevtoolsclient_8wekyb3d8bbwe\\MicrosoftEdgeMain\",\"Start Page\",0,\"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23\" ; Edge 浏览器主页","categories":[],"tags":[{"name":"整活","slug":"整活","permalink":"https://justpureh2o.github.io/tags/%E6%95%B4%E6%B4%BB/"},{"name":"学术","slug":"学术","permalink":"https://justpureh2o.github.io/tags/%E5%AD%A6%E6%9C%AF/"},{"name":"破解","slug":"破解","permalink":"https://justpureh2o.github.io/tags/%E7%A0%B4%E8%A7%A3/"}]},{"title":"DC Doujin 2023 EP1 一触即发正式发布","slug":"dcdep1-release","date":"2023-12-03T05:02:42.000Z","updated":"2024-02-23T08:17:48.754Z","comments":true,"path":"dcdep1-release/","link":"","permalink":"https://justpureh2o.github.io/dcdep1-release/","excerpt":"","text":"","categories":[],"tags":[{"name":"DC Doujin","slug":"DC-Doujin","permalink":"https://justpureh2o.github.io/tags/DC-Doujin/"},{"name":"DCD同人","slug":"DCD同人","permalink":"https://justpureh2o.github.io/tags/DCD%E5%90%8C%E4%BA%BA/"},{"name":"新闻","slug":"新闻","permalink":"https://justpureh2o.github.io/tags/%E6%96%B0%E9%97%BB/"}]},{"title":"信竞初等数论导论","slug":"number-theory-junior","date":"2023-11-25T17:37:52.000Z","updated":"2024-02-17T18:23:16.969Z","comments":true,"path":"number-theory-junior/","link":"","permalink":"https://justpureh2o.github.io/number-theory-junior/","excerpt":"","text":"引入 如果说数论是数学体系中专门用来研究数字性质的一个分支,那么初等数论则是对整数的性质进行系统性的探讨与研究。千万不要因为其中的“初等”二字小瞧这初等数论尽管名称和学习难度上都没有高等数论那么有逼格,就像初等数学之于高数,数论的所有内容均筑基于此。其中欧几里得证明的算数基本定理(一切合数都可被分解为有限个质数的乘积)在质数筛、GCD(以及LCA)计算、无理数证明等问题上均有用武之地。可以说高等数论奠基于初等数论。它同时也是初学者接触数论的必经之路。 Part1. 前置知识 Div1. 数论有关定理 算术基本定理:每一个合数都可以被分解为有限个质数的乘积。即对于任意合数,都存在: ,其中为质数。 推论一:正整数的正因数集合为: 推论二:正整数的正因数个数为: 推论三:正整数的所有正因数之和为 质数分布定理:区间中,当时,质数个数。 费马小定理: 若是一个质数,则(为同余符号)。 欧拉定理(费马小定理扩展): 若(与互质),则有,其中为欧拉函数。 Div2. 同余 同余,顾名思义,两个数分别除以一个正整数后得到相同的余数。即。但是它的定义给出了这样一句话:“对于正整数和,若(能被整除),则称和对模同余,记作”。当然以上两种说法是等价的。 同余具有以下三种基本性质: 反身性:对于任何正整数, 对称性:即对于,有 传递性:若,且,有 当然,它可以延申到计算机的模运算(毕竟出现了)。模运算有三种基本运算: 加运算: 减运算: 乘运算: 还有两个推论: 幂运算: 求和运算: 同余消去原则: 若同余号两端的项相等,且都与模互质,则可以同时消去 举例:,如果,则。 Part2. 质数 质数的判断:除了它自身以及以外,不存在其他正整数使得。 Div1. 质数判断 试除法: 这是三种方法中,唯一一种能做到100%正确的质数判断方法。对于给定数,遍历所有间的正整数,若出现则证明它不是质数,因为质数只能被1以及它本身整除。 123456bool isPrime(int n) { for (int i = 2; i * i <= n; i++) { if (n % i == 0) return false; } return true;} 复杂度: 适用范围:普及、提高 试除法の大胜利! 费马素性检验: 是上述费马小定理的实际运用,它与常规算法思想有所不同:它主张在中随机选取一个数。若出现与费马小定理不符的情况,那么一定为合数;若每次均符合定理,称为 费马伪素数 ,因为它很大概率是一个质数。 1234567891011bool isPrime(int n) { if (n <= 2) return false; int k = 10; while (k--) { srand(time(0)); int a = rand() % (n - 2) + 2; if (__gcd(a, n) != 1) return false; if (qpow(a, n - 1, n) != 1) return false; } return true;} 复杂度:,其中为随机数检验次数,是因为使用了快速幂算法。 适用范围:提高T2及以下(慎用) 为什么用该方法判断的质数 大概率 是个质数呢?不妨测试一下561(3)、1105(5)、1729(7)(括号内为它的最小因子),你会发现函数的返回值均为true,即都为质数。可见这个算法不是100%正确的,这些“漏网之鱼”被称为“Carmichael数”。它们极其罕见,一亿范围内仅255个。也因如此,你可以通过打表特判的方式抠掉这些特例(你保证记得住就行)。2016年中国物流工人余建春给出了一个Carmichael数的判断准则,这个标准目前在国际上得到了广泛认同。 对于优化,你可以在函数起始点加入类似于if (n % 2 == 0 || n % 3 == 0) return false;的特判,进一步降低复杂度。 Miller-Rabin算法: 该算法同样无法保证结果100%准确,慎用! MB算法实质上是对费马素性检验算法的效率和准确度优化。算法流程如下: 将分解为的形式,其中为奇数 从中选取整数,称为“基数” 计算的值,若结果为或,则可能为质数,继续检验 若结果不等于或,计算、、……的值,若结果等于,则可能为质数,继续检验 若都不等于,则一定是合数。称为强费马证据。 当然,它同样有特例,称为强伪质数,如2047(23)、3277(29)、4033(39)等(括号内为它的最小因子)。 Div2. 质数筛 常见的质数筛法有:试除法、埃氏筛、线性筛。 试除法:从质数定义出发,即存在一个正整数,对于任意间的正整数,总有成立。代码实现只需枚举间所有正整数,并让对其取余。若取模运算出现则代表它不为质数,没有出现则为质数。 123456bool isPrime(int n) { for (int i = 2; i * i <= n; i++) { if (n % i == 0) return false; } return true;} 复杂度: 适用范围:普及T2及以下 这里所展示的试除法代码实际上经过一轮优化。若严格根据质数定义,第二行的循环上限应为。考虑到如下性质:,若,则一定有。因此可以将循环上限压缩至。 埃氏筛:全称叫埃拉托斯特尼筛法,老哥生活在2200年前的古希腊,不借助望远镜就计算出了地球的周长(与真实值偏差仅0.96%)、同时他也是第一位根据经纬线绘制出世界地图的人、也是最先提出将地球根据南北回归线分为“五带”的大人物。他提出的筛法核心思想如下: 第一步:列出从2开始的一列连续数字;第二步:选出第一个质数(本例中为2),将该质数标记,将数列中它的的所有倍数划去;第三步:若数列中的末项小于它前一项的平方,则质数已全部筛出;否则返回第二步。 12345678void get(int n) { for (int i = 2; i <= n; i++) { if (!vis[i]) { prime[cnt++] = i; } for (int j = 2; i * j <= n; j ++) vis[i * j] = true; }} 其中,prime数组存储质数,vis数组用于标记(即上文中“划去数字”),变量cnt则存储中质数的个数。 复杂度: 适用范围:普及T2及以下 但是继续观察算法发现:我们其实无需将所有的倍数删去,只需删去前一步得出的质数的所有倍数即可。 这与前文介绍的埃氏法核心相符。因此将循环迁移至条件判断中即可: 12345678void get(int n) { for (int i = 2; i <= n; i++) { if (!vis[i]) { prime[cnt++] = i; for (int j = i + i; j <= n; j += i) vis[j] = true; } }} 优化复杂度: 适用范围:普及T3及以下 线性筛/欧拉筛:实质是埃氏筛的线性优化。因为在埃氏筛中,有些数字被重复筛了多次(例如30会被2、3、5筛到)。本着线性优化的原则,我们需要找到一个方法,使得每个合数仅被筛选一次。主要思想如下: 我们发现,线性筛和埃氏筛均使用了质数的倍为合数的结论。我们只需要保证每一个数仅被它自身的最小质因数筛出即可。即对于数字,是一个合数,且只会被筛出。 123456789void get(int n) { for (int i = 2; i <= n; i++) { if (!vis[i]) prime[cnt++] = j; for (int j = 1; prime[j] <= n / i; j++) { vis[prime[j] * i] = true; if (i % prime[j] == 0) break; } }} 复杂度: 适用范围:普及、提高 例题: P5736 【深基7.例2】质数筛 P5723 【深基4.例13】质数口袋 Part3. 因数 因数定义: 对于一个数,若存在一个正整数使得,则称是的因数。 Div1. 因数分解法 试除法:万能暴力解法。即遍历间的所有数,若可以整除,则和均为的因数。特殊情况:为整数时,因数仅有本身,因此需特判。 123456789101112vector<int> get(int n) { vector<int> ret; for (int i = 2; i * i <= n; i++) { if (n % i == 0) { ret.push_back(i); ret.push_back(n / i); } if (n % (i * i) == 0) ret.pop_back(); } sort(ret.begin(), ret.end()); return ret;} 复杂度: 适用范围:普及T1 Div2.最大公约数 辗转相除法: 又是我们大名鼎鼎的欧几里得老先生提出的一套公约数算法,整个算极其简洁:核心只有一行,即: 两个数的最大公约数等于其中较小的数字和二者之间余数的最大公约数 可以写出: 123int gcd(int a, int b) { return b ? gcd(a, a % b) : a; } 但是为什么呢?我们可以通过以下方法证明: 假设如下关系:。其中被除数,除数,商,余数。则。 首先证明充分性:令、,即二者有相同因子。 代入初始除法算式得: 接着由于加减乘法的封闭性,即一个整数进行加减乘运算得到的结果同样是一个整数。可以得出:。即()与有共同因子。 接下来证必要性。令、 Stein算法: 上一个方法的明显缺点在于,它处理大质数的效率并不好(但总体来说是很好的),因为它使用了取余运算,这会减慢一些速度。可以理解,生在2000多年前——一个没有电脑和OI的古希腊社会,这个算法已经足够兼顾常规效率和手推难度了。但是步入21世纪,加快的生活节奏毒瘤数据使得人们对更快算法的需求空前高涨。Stein算法便应运而生。 算法流程如下: 任意给定两个正整数,先判断它们是否都是偶数,若是,则用2约简,若不是,则执行第二步。 若两数是一奇一偶,则偶数除以2,直至两数都成为奇数。再以较大的数减较小的数,接着取所得的差与较小的数,若两数一奇一偶,仍然偶数除以2,直至两数都成为奇数。再次以大数减小数。不断重复这个操作,直到所得的减数和差相等为止。 两数相等时,第一步中约掉的若干个2与第二步中最终的等数的乘积就是所求的最大公约数。 123456789101112131415161718192021222324int gcd(int a, int b) { int p = 0, t; if (!(1 & a) && !(1 & b)) { a >>= 1; b >>= 1; p++; } while (!(1 & a)) a >>= 1; while (!(1 & b)) b >>= 1; if (a < b) { t = a; a = b; b = t; } while (a = ((a - b) >> 1)) { while (!(1 & a)) a >>= 1; if (a < b) { t = a; a = b; b = t; } } return b << p;} 这个算法的优点在于:它大大优化了大质数的运算。但可惜的是,它的代码量膨胀了8倍,因此不太建议赛时使用。毕竟C++都给你内置了__gcd()函数嘛,干嘛不偷个懒? Div3. 最小公倍数 我们可以简单概括成一句话: 两个数的最小公倍数等于这两个数的乘积与这两个数最大公约数的商 即: 凭啥呀? 我们假设两个数和有最大公约数,则,且。并且和一定互质(若不互质,和的最大公约数就不会是,而是一个比大的值)。 由乘法交换律,可知: 消去得:。因为、互质,所以或者即为两个数的最小公倍数。得证。 例题: P1075 [NOIP2012 普及组] 质因数分解 P2424 约数和 (需要逆向思维) Part4. 欧拉函数相关 Div1. 欧拉函数推导 问:论牧师欧拉有多么的高产 答:平均每年800页数学论文你说高不高产嘛 欧拉函数,记作。表示中与互质的数的个数,即,满足的的总个数即为的值。举个例子,,因为在中,和均与互质。特殊地,。 欧拉函数有如下计算公式:若可被表示为(算术基本定理分解式)的形式,则。 推导思想即为用减去所有中所有与不互质的数。在计算机上实现,首先需要分解质因数。思路如下:首先抛出第一个质因数,那么将中所有的的倍数删去,因而可以保证筛出的数一定是的质因子,否则他们将存在最大公约数。那么能被整除的数的个数(也就是以内的倍数个数)为——其中的中括号代表整除。 因此我们离解出欧拉函数就进了一步了,我们的过渡式子就是。 好耶 别急着好耶,我们可以发现一个小小的推导谬误(可能并不是很容易发现)。当我们用去筛数时,使用的算式仍然是。对于形如的数,会被重复筛去多次,导致多减,最终结果会小于。有些抽象,我们来看这张图: 容斥原理 易知中可被整除的数字共有个,能被整除的数字共有个。但是如果说能被和整除的数字共有个,显然不合常理,因为、、都既能被整除,也能被整除,如果不加排除,他们将会被减去2次。因此需要补偿损失,正确的计算方法是(仅计算能被和整除的数的总个数): 能被整除的:个 能被整除的:个 同时被和整除的:个 总个数:个(就是被绿圈和橙圈捆住的的数的个数) 那么对于、、整除问题,中间的被重复加了3次,需减去两次平衡收支。此即容斥原理的简单思想表示。 回到欧拉函数推导上来:过渡公式中的容斥问题可以解决一部分了。对于可同时被两个不同质数整除的数(例如、),我们加上它的总个数。 得到。 当然这又有一个小问题没完没了了是不是?:对于的公倍数,会被先减去3次,然后被上一步的操作加上3次,总体不加不减。还是回到上图:中间的会被每个颜色的圈先减去一次、共3次,上一步的补偿操作,可以看作又被橙绿圈(橙圈和绿圈的交集)、蓝绿圈、蓝橙圈一共加上了3次。减3次加3次相当于没动,为了让它被算上,我们需要加上它,对于则是全部减去(因为括号外有减号需要变号,不要忘记是由一系列不合规的数字个数相减得来的)。得到我们的过渡态3: 又是如上的容斥判断,这里我们省去讨论。将最终的产物合并得到:!(我不会合并,但是你可以把括号拆开看看是不是上述形式。总之,欧拉牛逼!) ,好耶!终于可以好耶了…… Div2. 欧拉函数代码实现 主要是如果压成一个Div会非常的长,因此这里新开一个Div2 我们明确了欧拉函数的推导,接下来就是整理思路写代码的时间了!我们也只需跟着原始思路走就可以了。再次回忆一下:首先我们需要筛出质因数,除去它的所有倍数,再用公式代入就可以了。 1234567891011long long eular(int n) { long long res = n; for (int i = 2; i * i <= n; i++) { if (n % i == 0) { res = res * (i - 1) / i; while (n % i == 0) n /= i; } } if (n > 1) res = res * (n - 1) / n; return res;} 时间复杂度: 适用范围:All Clear Div3. 欧拉函数推论 若为质数,则 让我们回到欧拉函数的定义上去:是中与互质的数的个数(特殊地,)。那么对于这个质数,有多少数与它互质呢? 很显然,答案是个!因为的质因子只有本身,若不止一个质因子,很显然它不是一个质数。因此。 假设是一个质数,(或),且的值已知,那么 凭啥呀? 因为已经是一个质数,换句话说:在这个条件下是的一个质因子。在计算时,就已经作为一个质因子以的形式乘进去了。此时可以写作 那么函数值多乘了一个 我们发现:(2)式中包含了(1)式,只是头上乘以了。因而得到 假设是一个质数,(或),且的值已知,那么 这东西长得和性质2很相似,唯一不同的是不再是的一个质因子了。但是变成了的质因子。因此我们计算的值时,不仅需要在头部乘上,而且还需要将乘进去: 因为,所以得到性质3,即。 这三个性质将作为重点性质出现在欧拉函数筛法中。 Div4. 欧拉函数线性筛 我们已经接触了简单的欧拉函数计算方法,那么又该如何解决形如:“给定一个正整数,求的值”的问题呢? 考虑继续使用上面的朴素算法,时间复杂度将会是。明显无法满足需求,更何况,每个数与每个数之间的值之间有一种推导关系,使得我们无需每次重新计算值,而是用已经求出的来线性推出的值。 欧拉函数涉及到质因子的拆分,我们又需要在线性时间内求各种质数。自然而然想到了先前所学的线性筛: 12345678910111213int primes[N];bool st[N];int cnt = 0;void sieve(int n) { for (int i = 2; i <= n; i++) { if (!st[i]) primes[++cnt] = i; for (int j = 1; primes[j] * i <= n; j++) { st[primes[j] * i] = true; if (i % primes[j] == 0) break; } }} 我们运用这段代码可以得出范围内所有的质数,用st[N]数组可以筛出所有的合数。也就是说对于筛出的合数,我们能够得知组成它的质因子是什么,比如st[primes[j]*i]=true;这一行代码。接着套用上述三种性质,我们可以得出值。 此时我们就需要新建一个phi[N]数组来存储每个数的值,并且在代码中三个地方加入对于三种性质的公式: 1234567891011121314151617181920212223typedef long long ll;ll primes[N];bool st[N];int cnt = 0;ll phi[N];void phi_sieve(int n) { for (int i = 2; i <= n; i++) { if (!st[i]) { primes[++cnt] = i; phi[i] = i - 1; } for (int j = 1; primes[j] * i <= n; j++) { st[primes[j] * i] = true; if (i % primes[j] == 0) { phi[primes[j] * i] = phi[i] * primes[j]; break; } phi[primes[j] * i] = phi[i] * (primes[j] - 1); } }} 没错我开了long long防止爆int 时间复杂度: 适用范围:普及&提高 对于开头提出的求和问题,遍历phi[1]到phi[n]的所有值求和即可。 Div5. 欧拉定理 若正整数与互质,则有 对于它的证明,百度百科中如此写到: 取的缩系,故也为的缩系。有 通俗来讲就是这样: 在中取所有与互质的数,很容易知道这样的共有个(根据欧拉函数定义得来)。它们都与互质。 给这列数同时乘上,得到。它们也都和互质,并且各不相同。 提出括号里乘了次的,得到以下关系式: 那么根据同余号两端的消去原则(左右两端两个项相同且与模互质),可以消去。得到,欧拉定理得证。 特殊地,如果是一个质数,有。这被称作费马小定理(先前的费马素性检验就是基于这个原理编写的)。 真不知道明明可以写得通俗点为什么非得省那点空间写看起来那么高深莫测的专业术语,真的是只写给自己看的。 Div6. 降幂算法 尤其对于绿题以上的题目,题面中可能出现“答案可能很大,请对大质数取余”的字样。这意味着题目可能涉及到大规模的幂运算,需要我们用简便的方法计算幂。对于一般的题目,我们使用快速幂。 快速幂:快速幂思想如下: 我们将指数分解为若干的和(二进制表示),例如:,因为。因而不必将连续乘11次,效率大幅提升。 1234567891011typedef long long ll;int qpow(int a, int k, int p) { int res = 1; while (k) { if (k & 1) res = (ll) res * a % p; a = a * a % p; k >>= 1; } return res;} 时间复杂度: 适用范围:基本All Clear 欧拉降幂:上面方法一个缺点在于无法处理过大的指数,在处理类似于的计算时将会疯狂掉san。接下来介绍一种使用上面讲到的欧拉定理来解决大指数幂运算的方法。 欧拉降幂核心公式:(又称 扩展欧拉定理 ) 也就是说:我们只需要算出的值,再用快速幂算法,将作为新指数带入计算即可。当然,这里的可能会爆long long,因此可以选择使用字符串进行高精度计算。 12345678910111213141516171819202122232425262728293031323334353637383940414243typedef long long ll;ll primes[N];bool st[N];int cnt = 0;int qpow(int a, int k, int p) { int res = 1; while (k) { if (k & 1) res = (ll) res * a % p; a = a * a % p; k >>= 1; } return res;}ll eular(int n) { ll res = 0; for (int i = 2; i <= n; i++) { if (!st[i]) { primes[++cnt] = i; res = res * (i - 1) / i; while (n % i == 0) n /= i; } for (int j = 1; i * primes[j] <= n; j++) { st[i * primes[j]] = true; if (i % primes[j] == 0) break; } } if (n > 1) res = res * (n - 1) / n; return res;}int edp(int a, string k, int p) { ll phi = eular(p); int drop = 0; for (int i = 0; i < k.length(); i++) { drop *= 10; drop += k[i] % phi; } drop += phi; return qpow(a, drop, p);} 其中eular(int n)函数用于计算欧拉函数的值、edp(int a, string k, int p)用于计算降幂后的指数、qpow(int a, int k, int p)是快速幂算法。 时间复杂度: 适用范围:所有 扩展欧拉定理可谓是欧拉定理的一般形式,它的定义如下:对于任意正整数、、,满足: $a^k $ 其中第二个式子就是欧拉降幂的核心公式。 扩展欧拉定理的证明见这里。因为太复杂了我不会证 例题: P2158 [SDOI2008] 仪仗队 (欧拉函数板子) P1447 [NOI2010] 能量采集(上一个问题的变式) P1226 [模板] 快速幂 P5091 [模板] 扩展欧拉定理 (欧拉降幂) P4139 上帝与集合的正确用法 (欧拉降幂+递归) Part5. 同余方程的解法 这里会涉及到一元线性同余方程,一元线性同余方程组和高次同余方程的算法解法。 Div.1 裴蜀定理 很多人会把他读成裴除(chú)(比如我的某位好友),这个名词正确的读法是裴蜀(shǔ)。或者可以直接改称作“贝祖定理”,它的提出者艾蒂安·裴蜀估计怎么也没想到后人居然连他的名字都读不对(想想如果这种事情发生到你身上会怎么样)。你也可以读他名字的法语发音(显得你很优雅且有文化)。 切入正题,裴蜀定理表述为:对于任意正整数,,总有整数、,使得,其中等价于,是数论中最大公约数的表述方式。 首先可以知道且,因为和都具有约数,让他们分别乘上另两个数和并不会改变这一约数。所以假设,有。在这里,。 Div2. 扩展欧几里得(EXGCD) 加了“扩展”二字是不是感觉逼格上来了? 扩展欧几里得算法用于求出线性同余方程的解。线性同余方程,即形如的方程,我们需要求出的值。 回忆一下欧几里得算法的核心思路:。 再看看刚刚讲到的裴蜀定理,发现。根据余数的定义,有:。 那么我们的任务就是求出这里的和值,因此拆开括号,整理出和的系数:。观察裴蜀定理的形式:,我们得出的式子中,变成了。因此每次递归时需要将的值减去。 既然我们设计的是一个递归算法,我们就必须明确它的递归出口。根据欧几里得算法,当时,。我们把和代入发现:,得到,此时可取任意整数值,。这里我所取的解是。 最后,因为这本质上还是一个欧几里得算法,所以返回是有必要的(事实上exgcd算法返回的将作为推导式中的参与运算)。我们可以写出如下函数。 12345678910int exgcd(int a, int b, int &x, int &y) { if (!b) { x = 1; y = 0; return a; } int d = exgcd(b, a % b, y, x); y -= a / b * x; return d;} 时间复杂度: 但是,题目中一般不会给出裴蜀定理那样的形式,而是形如的形式,让你求出的值,并且上述方法仅求出了一元线性同余方程的一组特解,如果题目中让你求出最小正整数解呢?接下来就是解决上述问题的方法: 1. 同余—等式互转(自己起的名字): 在上面的介绍中,我们遇到了一个问题:如何将这样的同余式变为这样的二元一次不定方程的裴蜀定理形式呢? 考虑到同余方程的定义(或者你可以把以下关系死记住),得到。接着由余数定义,得到,移项得到:。提出负号,令,则。它有解的充要条件是。经过如上变换后就变成了裴蜀定理的形式,可以直接用exgcd求解和。 2. 最值解问题: 二元一次不定方程通解的证明 Div3. 中国剩余定理(CRT) 又称孙子定理(但我认为还是中国剩余定理听起来更有实力一些),最早见于《孙子算经》中“物不知数”问题,首次提出了有关一元线性同余方程的问题与解法。 对于一元线性同余方程:,可以构造以下方法求出通解。 首先,令。 然后,令,即除了外所有的乘积。 接着,令为在模意义下的逆元,即。 所以,的通解为:。 Div4. Baby Step Giant Step算法(BSGS) 这个算法用于解决一元高次同余方程问题,模意义下的对数也可以求。又称“北上广深算法”(想出这种名字的人真是人才)。 高次同余方程长成这个样子: 发现跑到了指数上边真是变态呢。这种问题显然没公式解,于是苦恼的人们只得选择一条略显暴力的求解道路,即搜索。严格来说,BSGS所使用的是双搜索,其中的一个变量的搜索步长会长于另一个变量的搜索步长,因而得名“大步小步算法”。或者叫北上广深/拔山盖世算法! 朴素BSGS(与互质):不妨令,原式为。根据消去原则,两边同乘得。 接下来我们对同余号右侧的部分求值,再任命一个固定的值,使得左侧模的值等于右侧模的值。为了快速比对左右侧的值,我们选择将右侧预先计算出来的值存入一个哈希表中,让(键为,对应值为)。接着就是选择值,计算并比对了。 关于哈希表冲突,我们希望找到的最小值,因而需要尽可能大。每次冲突即代表一个更大的值被发现了。因此无需处理冲突问题。 对于的选择。可以发现有个可能的取值,有个。取时最佳。因此代码就可以写出来了。 123456789101112131415161718ll bsgs(ll a, ll b, ll m) { unordered_map<ll, ll> hash; ll bs = 1; int t = sqrt(m) + 1; for (int B = 1; B <= t; B++) { bs *= a; bs %= m; hash[b * bs % m] = B; } ll gs = bs; for (int A = 1; A <= t; A++) { auto iter = hash.find(gs); if (iter != hash.end()) return A * t - it->second; gs *= bs; gs %= m; } return -1;} 时间复杂度: 扩展BSGS(和不互质): 例题: P1082 [NOIP2012 提高组] 同余方程 (exgcd) P5656 [模板] 二元一次不定方程 (exgcd) P1495 [模板] 中国剩余定理(CRT)/ 曹冲养猪 P1516 青蛙的约会 (CRT+exgcd) P3846 [TJOI2007] 可爱的质数/ [模板] BSGS P2485 [SDOI2011] 计算器 (欧拉降幂+乘法逆元+BSGS) P3306 [SDOI2013] 随机数生成器 (等比数列推导+BSGS) P4195 [模板] 扩展 BSGS/exBSGS Part6. 乘法逆元 乘法逆元定义如下(注意和矩阵求逆不是一个东西): 若,且与互质,则是在模条件下的乘法逆元,记作 简单来说乘法逆元就是模意义下的的倒数。 费马小定理求逆元:大部分题目会给出一个质数模数,因而互质是可以保证的。此时我们的乘法逆元就是使式子成立的值,考虑到模数为质数,可以带回开头所说的费马小定理中。 得到,由于与互质,消去得:,所以乘法逆元为。 123int inv(int a, int p) { return qpow(a, p - 2, p);} 扩展欧几里得求逆元:这是万能的方法,对任意模数均成立。它不像上面费马小定理那样限制模数必须是质数,因而只要时间充裕,都建议使用这种求逆元的方式。 因为,运用同余-等式互转可以得到。符合exgcd的形式。 12345678910111213141516int exgcd(int a, int b, int &x, int &y) { if (!b) { x = 1; y = 0; return a; } int d = exgcd(b, a % b, y, x); y -= a / b * x; return d;}int inv(int a, int m) { int x, y; exgcd(a, m, x, y); return (x + m) % m;} 递推求逆元: 例题: P3811 [模板] 模意义下的乘法逆元 (递推求逆元) 来张弔图 Part7. 矩阵相关 矩阵,是一个按照长方排列的实数或复数集合。它最早用来表示方程组中的系数和常数,简单理解就是它将元一次方程组中的系数,按照未知数的顺序依次挑出它们的系数组合为矩阵的某一行。元一次方程的矩阵有列,而行数则取决于方程组中方程的个数。 Div1. 初等行变换 考虑这个方程组: 按照如上所述,将它转换为系数矩阵(只有的系数)就是: 你也可以写成增广矩阵(与系数矩阵相比多了一列常数,即等号右边的常数,这里用竖线隔开)的形式: 不难看出第一列代表了的系数,第二列和第三列是和的系数。那么如果需要求解这个矩阵(得到方程组的解),我们应该通过初等行变换将它变成方便我们求解的模式。初等行变换内容如下(最好用方程组消元的思想简化理解): 交换某两行 把矩阵的某一行同乘以一个非零的数 把某行的若干倍加和到另一行 假设我们有一个元线性方程组,如何设计算法使计算机能够快速求出它的解呢。我们需要引入三角矩阵的概念: 顾名思义,系数排列看起来像一个三角形的矩阵,叫做三角矩阵。分为上三角矩阵和下三角矩阵。前者的非零系数均分布在对角线的右上方、后者都在左下方,例如矩阵:就是一个上三角矩阵(这里是增广矩阵)。通常用字母表示,求解线性方程组时经常化为这种形式方便求解:本例中当最后一个未知数(见最后一行)已知时,可以通过向上代入求解每一行中待求的未知数值。 那么如何将一个一般矩阵转换为上三角矩阵呢?答案是前面介绍过的初等行变换!步骤如下: 枚举每一列,选出无序组中第列系数绝对值最大的一行,并移到无序组的最上边。 行通过自乘,将第列的系数变成,并标记为有序。 通过加减有序组中某一行的非零倍,将之后所有行的第列系数化为。 文字还是太抽象,我们来举个例子: 令矩阵(有序组用绿色表示) 枚举第一列,。开始时,所有行均无序。选出绝对值最大的那一项,本例中为第二行,进行移动,原矩阵变为: 第二步,自乘并标记有序,因此第一行除以,原矩阵就变成了: 第三步,将无序组的第列消成。本例中,我们让第二行减去二倍第一行;第三行直接减去第一行,得到: 枚举第二列,此时。第一步,选出第二列系数绝对值最大的那一行,移到无序组最上端。本例中无需移动,自乘,标记有序,原矩阵为: 最终的最终,第三行减倍第二行,得到我们心心念念的上三角矩阵: 我们假设从左到右,分别为、、的系数,竖线右侧为常数。矩阵可以改写成方程组的形式: 根据最后一行,显然。将代入2式,解得,以此类推,由下向上代入解出的值即可,本例的唯一解是:。 然而心细的你估计发现了疏漏之处:“求一元二次方程时都要先检验根是否存在(判别式法)再来作答,你这里怎么没有讨论根的分布情况呢?” 事实上,矩阵的解的分布确实不止一种情况,这里是矩阵有唯一解的情况。类比高中立体几何求平面法向量的情景,我们通常都要令某个坐标为或者是其他方便于计算的值,这里就是矩阵有无数组解的经典例子。要想系统分析矩阵方程解的数量情况,我们需要引入秩的概念。 Div2. 秩 在上一节中我们通过初等行变换求出了矩阵的解,然而并不是所有矩阵都能轻而易举求出唯一解,因为它可能无解、也有可能无唯一解(默认最高次数为一)。类比一元二次方程中的判别式法,矩阵是否也有判断根存在性的方法? 答案是:有滴!在矩阵运算中,我们使用秩来描述矩阵的一些关于解的个数的关系。秩被定义为:将矩阵通过初等行变换后形成的梯形矩阵中非零行的个数。试看如下例子: 定义一个的矩阵: 经过初等行变换后出现了这样的情况: (第二行减去乘3的第一行,第一行乘2减去第三行) 第二行变成了纯的一行,一、三行说什么都无法消成一个未知数的形式。如果写成方程组就是: 它有无数组解,原因是:矩阵的秩与矩阵增广矩阵的秩相等且小于了它的阶。简单来说就是你用两个方程去求三个未知数的值(初一内容),当然是有无数多组解。 规定对于矩阵,它的秩用表示(、、均可)。因此令方程组的阶增广矩阵秩为,系数矩阵的秩为。矩阵有无数组解的条件就是(严格来说:有无数组解的充要条件是) 看第二个例子: 定义增广矩阵:;它的系数矩阵:。 增广矩阵变换后:;系数矩阵: 根据定义,得到,,此时。方程组无解。因而矩阵无解的充要条件是。简单理解起来就是方程组中的两个方程起了冲突,矩阵被省去的其中一步变换是:,第一行和第三行相当于要你求解如下的方程组:。显然矛盾,因此矩阵无解。 加上第一节里面的结论,我们总结出了矩阵解分布的三种情况(方程组的增广矩阵为、系数矩阵为,阶为): 当时,矩阵有唯一解 当时,矩阵有无数解 当时,矩阵无解 因此就有了一套组合算法: 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364#include <bits/stdc++.h>#define N 110#define NO_SOLUTION -1#define INFINITE 0#define SOLVE_OK 1using namespace std;typedef long long ll;double mat[N][N];int n;double eps = 1e-6; int solve() { int rank = 0; for (int c = 0, r = 0; c < n; c++) { int t = r; for (int i = r; i < n; i++) { if (fabs(mat[i][c]) > fabs(mat[t][c])) t = i; } if (fabs(mat[t][c]) < eps) continue; for (int i = c; i <= n; i++) swap(mat[r][i], mat[t][i]); for (int i = n; i >= c; i--) mat[r][i] /= mat[r][c]; for (int i = r + 1; i < n; i++) { if (fabs(mat[i][c]) > eps) { for (int j = n; j >= c; j--) { mat[i][j] -= (mat[r][j] * mat[i][c]); } } } r++; rank = r; } if (rank < n) { for (int i = rank; i < n; i++) { for (int j = 0; j < n + 1; j++) { if (fabs(mat[i][j]) > eps) return NO_SOLUTION; } } return INFINITE; } for (int i = n - 1; i >= 0; i--) { for (int j = i + 1; j < n; j++) { mat[i][n] -= mat[i][j] * mat[j][n]; } } return SOLVE_OK;} int main() { cin>>n; for (int i = 0; i < n; i++) { for (int j = 0; j < n + 1; j++) cin>>mat[i][j]; } int res = solve(); if (res != SOLVE_OK) cout<<res<<endl; else for (int i = 0; i < n; i++) { if (fabs(mat[i][n]) < eps) mat[i][n] = fabs(mat[i][n]); printf(\"x%d=%.2lf\\n\", i + 1, mat[i][n]); } return 0;} 时间复杂度: 以后上大学解高次线性方程就可以用这段程序秒了。 Div3. 矩阵基本运算 1. 加法: 注意类比元一次方程组的加减消元,两个矩阵相加意味着同一位置的元素相加。需要注意:只有同型的矩阵才有加法运算(同型即行数列数相等)。 可以知道,四则运算的加法交换律和结合律仍然适用于矩阵加法。 2. 减法: 加法的逆运算,让矩阵同一位置的元素相减即可。也是仅限于同型矩阵之间才可做减法。 3. 数乘: 即矩阵中每个元素都跟数字相乘。符合乘法交换律和结合律 矩阵的加法、减法和数乘合称为矩阵的线性运算 4. 转置: 矩阵的转置矩阵用表示。 直观来讲就是将原矩阵旋转一下(行和列互换)。满足如下性质: (转置一次后再转置一次还是原来的矩阵) (常数转置后就是它本身) (上一条是它的特殊形式,类比两数乘积的幂) 5. 共轭: 矩阵的共轭矩阵用表示。 类比共轭复数的定义:实部不变、虚部取相反数。矩阵共轭变换就是将矩阵中的所有复数变为其共轭形式。 6. 共轭转置: 矩阵的共轭转置矩阵记作、、或。 字面意思,先取共轭,再转置。它具备转置矩阵的三条性质。 Div4. 矩阵乘法 只有一个矩阵的行数和另一个矩阵的列数相等时才可进行乘法运算。 例如一个矩阵和一个矩阵。记它们的乘积。则中的某个元素。并且是一个的矩阵。 因此 它满足结合律、分配律,但是大多数情况下不满足交换律。交换律不成立可以看到下面这个例子: 首先根据定义,矩阵的行列数取决于做乘法的两个矩阵和的行列数,比如矩阵和矩阵相乘,得到一个矩阵,但是将它颠倒顺序,让一个矩阵与矩阵相乘,结果将是一个矩阵,和前者行列数相反。 对于结果是正方形矩阵的,可以自己随便设置两个矩阵进行计算。但是部分矩阵仍然可以进行交换律运算:矩阵乘一个单位矩阵/数量矩阵[/]、矩阵乘它的伴随矩阵()。 Div5. 其他常用类型的矩阵 1. 零矩阵:顾名思义,由组成的矩阵称作零矩阵。零矩阵不可逆,且任何符合条件的矩阵与一个零矩阵的积均为零矩阵。 2. 单位矩阵:形如的矩阵被称作单位矩阵,通常用字母或表示。单位矩阵指仅对角线系数为、且其他系数为的矩阵。阶矩阵与它的逆矩阵相乘得到的结果就是一个阶单位矩阵,即。 3. 数量矩阵:形如的矩阵叫数量矩阵,可以看作实数与单位矩阵进行数乘运算后的结果,通常表示成。矩阵与一个数量矩阵的乘积满足乘法交换律。 4. 逆矩阵:如果存在一个矩阵和单位矩阵,使得,则称矩阵可逆,是的逆矩阵,也可记作。单位矩阵的逆矩阵是它本身;零矩阵不可逆。阶矩阵可逆的充要条件是。 5. 对称矩阵:转置矩阵与自身相等的矩阵叫做对称矩阵,特征是所有元素关于对角线对称,例如:。对称矩阵必为方形矩阵,反之不一定成立,对于一个方形矩阵,必定是对称矩阵。 Div6. 矩阵的几何表示 平面直角坐标系上,一个向量可以被表示成的形式,即。 计算机中,用两个不共线向量和能够表示整个平面直角坐标系。运用一点高中数学的空间几何知识,这里的和被称作基底(当然,如果需要描述三维空间坐标系,则需要三个不共线的基底向量)。于是我们使用矩阵来描述这个平面直角坐标系就是非常简洁明了且优雅的了。 假设我们常规想法中的平面直角坐标系是,经过一轮线性变换后得到的新坐标系是:。用一张图看一下变换后的坐标系: 如果在最开始的坐标系中有一个向量,我们如何在新的坐标系中表示它呢?再根据我们高中数学所学,只需要算出的值即可。因为是轴的基底,相当于上的一个单位,我们求新向量时只需求出在新的参考系中的新值和值,因而直接用方向的系数乘以一个单位即可,在这里就是,得到。 抽象之后变成: 例题: P3389 [模板] 高斯消元法 (上三角矩阵的转换) P2455 [SDOI2006] 线性方程组 (前一道题的升级版) Part8. 组合计数 StarterDiv1. 阶乘概述 阶乘,数学中用表示,表示的值,即 特殊地,。 StarterDiv2. 常用排列总结 1. 排列数:数学中用表示(,老教材记作,)。表示从个数中选择个进行排列,公式为: 为啥呢?,有弔图为证↓ 2. 组合数:假设有个物品,从中任选出个排成一组,叫做组合;所有可能的选法总数叫做组合数。用表示,计算公式为:。简记为:乌鸦坐飞机 弔图×2↓ GZ表示就凭这几张图他能速通整个组合数的内容 StarterDiv3. 二项式定理 学过初中的大家都知道:,这是完全平方和公式。高中的一些牛逼娃还知道完全立方和公式,也就是:。这些式子其实都是可以由二项式定理套出来的。 二项式定理定义式如下: 这里出现的。是不是突然发现它和组合数公式的共同之处喽?但是这一章并不会用它,只是作补充知识的说…… 有这三条就够了,接下来进入组合计数的内容。 Div1. 高考娃狂喜——组合数计算 一个小栗子: 宇宙榜一大学阿福大学的榜一博士后导师黑虎阿福给你出了一道难题: 给你两个正整数和(),让你求出的值。 你:“这还不简单?” 阿福: “好的,我这里将设为,设为,请你求解。” 你: “WTF?” 于是你决定用程序来代替人脑,阿福教授也做出了一定让步,让你求出的值。但是不幸的是,人类的计算机科学水平自从2024之后就被来自几光年外的八体星人文明发出的“侄子一号(NEPHEW 1)”探测僚机锁定了,因此你需要设计一个高效的计算方式,而不是妄想着用2077年的赛博机器运行暴力计算,来解决这个问题。 一旦你的运行时间超过一秒,阿福教授就会使用战技“乌鸦坐飞机”对你造成大量阶乘伤害。已经学习了阶乘的你想必已了解了它的威力,所以还是老老实实推导公式吧! 递推版: 组合数递推公式:。 分析思路类似于动态规划问题:我们要从个物品中挑选个出来,求组合数。 上图中,若包含这个红色物体,那么我们只需再从剩下的个物体里挑选,因为红色物体自身占据了个位置中的其中一个,因此留给其他物体的总名额就只有个,因此该情况下组合数:;同样地,若不包含红色物体,从剩下的个物体中选出个,因为在该情况下红色的物体不计入组合,因此剩余名额还是个,组合数就是。最后,因为从个物体里选,只有包含红色和不包含红色两种情况(就好像你的双亲,不是你的母亲就是你的父亲),因此可以做到不重不漏。所以总组合数就是。 12345678910111213141516171819202122#include <bits/stdc++.h>#define N 2010using namespace std;int c[N][N];void Csieve(int p) { for (int i = 0; i < N; i++) { for (int j = 0; j <= i; j++) { if (!j) c[i][j] = 1; else c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % p; } }}int main() { int a, b, p; cin>>a>>b>>p; Csieve(p); cout<<c[a][b]<<endl; return 0;} 时间复杂度: 适用于的大部分情况。 预处理版: 但是众所周知,递归有两大痛点:对于主观思维来说,是边界问题;对于客观条件来说,是内存。递归过程中CPU里储存了大量的未运行或者待返回的函数实例,当和的值增大时,尽管它能在时间方面表现出色,但是内存就不那么理想了,反而会显得臃肿至极。当题目中给出时,建议用这种方法。 12345678910111213141516171819202122232425262728293031323334353637#include <bits/stdc++.h>#define N 100010using namespace std;typedef long long ll;int fact[N], infact[N];int qpow(int a, int b, int p) { int res = 1; while (b) { if (b & 1) res = (ll) res * a % p; a = (ll) a * a % p; b >>= 1; } return res;}int inv(int a, int p) { return qpow(a, p - 2, p);}int C(int a, int b, int p) { return ((fact[a] % p) * (infact[b] % p)) % p * infact[a - b] % p;}int main() { int a, b, p; cin>>a>>b>>p; fact[0] = infact[0] = 1; for (int i = 1; i <= N; i++) { fact[i] = (ll) fact[i - 1] * i % p; infact[i] = (ll) infact[i - 1] * inv(i, p) % p; } cout<<C(a, b, p)<<endl; return 0;} 时间复杂度: 适用范围,且均在int范围内的大部分情况。 Lucas定理优化版: 定理如下:(为质数)。证明在此(建议直接背结论)。 12345678910111213141516171819202122232425262728293031323334353637383940414243444546typedef long long ll;int p;int qpow(int a, int b) { int res = 1; while (b) { if (b & 1) res = (ll) res * a % p; a = (ll) a * a % p; b >>= 1; } return res;}int inv(int a) { return qpow(a, p - 2);}int C(int a, int b) { int res = 1; for (int i = 1, j = a; i <= b; i++, j--) { res = (ll) res * j % p; res = (ll) res * inv(i) % p; } return res;}ll lucas(int a, int b) { if (a < p && b < p) return C(a, b); return (ll) C(a % p, b % p) * lucas(a / p, b / p) % p;}int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t; int n, m; cin>>t; while (t--) { cin>>n>>m>>p; cout<<lucas(n + m, n)<<endl; } return 0;} 时间复杂度: 其本质是套用定理计算,因为是模意义下的除法,因而我们使用逆元来操作除法。 适用范围,在long long范围内的大部分情况。 高精度版(选修): 什么?你厌倦了组合数后面挂着的模?不妨试试高精度版的组合数计算吧!它适用于作业上的题目求解!(虽然前面几种也可以,毕竟手算的题数据很小取不取模都一样)是不是心动了呢? 常规思路来说,我们的组合数公式经过一轮分式化简可以得到:。因此我们可以实现高精度的乘除法来计算这个炒鸡长的算式,但是这样不仅效率低下,手写和调试的难度也会增加。我们急切地想知道如何简化成一种高精度算法。 我们看到了Part1里面讲的算术基本定理,将组合数转化为的质数乘积分解式,最后我们只需要解决质数头顶的指数即可。我们使用以下这个公式: 。 用它可以计算出中的个数。 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162#include <bits/stdc++.h>#define N 10010using namespace std;typedef long long ll;vector<int> num;ll primes[N], sum[N];bool st[N];int cnt = 0;void prime_sieve(int n) { for (int i = 2; i <= n; i++) { if (!st[i]) primes[++cnt] = i; for (int j = 1; i * primes[j] <= n; j++) { st[i * primes[j]] = true; if (i % primes[j] == 0) break; } }}int get(int a, int p) { int res = 0; while (a) { res += a / p; a /= p; } return res;}vector<int> mul(vector<int> a, int b) { vector<int> res; int t = 0; for (int i = 0; i < a.size(); i++) { t += a[i] * b; res.push_back(t % 10); t /= 10; } while (t) { res.push_back(t % 10); t /= 10; } return res;}int main() { int a, b; cin>>a>>b; prime_sieve(a); for (int i = 1; i <= cnt; i++) sum[i] = get(a, primes[i]) - get(b, primes[i]) - get(a - b, primes[i]); vector<int> res; res.push_back(1); for (int i = 1; i <= cnt; i++) { for (int j = 1; j <= sum[i]; j++) { res = mul(res, primes[i]); } } for (int i = res.size() - 1; i >= 0; i--) cout<<res[i]; cout<<endl; return 0;} 时间复杂度: 适用范围,在int范围内。 有了这段代码,我们就可以完成开头阿福教授的原问题了(不模不限数据)! Div2. 世界上最OI的IDE——Catalan数 当你翻开Catalan数的介绍文章,并大学特学了一番,感觉自己完全掌握了这神奇的数列,正当你兴致勃勃地打开题库搜索到一道Catalan数的题目正准备大展身手时,你会发现,面对这神奇的题干,不同于往常秒模板题的你,你甚至完全看不出来它和Catalan数有任何的关系,而且很有可能,你其实连Catalan数究竟是什么东西都不知道! 苏子愀然,正襟危坐而问客曰:“何为其然也?” 其实还真不能让那些博客背上黑锅,这种现象与Catalan数本身的应用有很大的关系。 Catalan数,或者习惯叫卡特兰数、明安图数,是组合数学中常用的特殊数列。数列如下:“”,它是一个无穷数列,数与数之间看起来似乎也没什么太大联系……其实它和斐波那契数列有类似之处,它们不具有特定的数学意义(只是斐波那契的递推方法简单得多罢了),只是一个十分普遍的数学规律。所以学习时应该挂靠于例子本身而不是一味依赖于定义所写,那我们就开始吧: 用最经典的例子写出来就是: 给你一个的网格,你将从原点开始移动。对于每次移动,你只能向上/向右一格(坐标/坐标加一),但是需要保证你总向右走的次数不少于向上走的次数,问从原点到有多少种不同的合法路径? 假设你某时刻走到了点,根据题目要求,意味着需要保证。我们拟合一条经过点的正比例函数,不难看出它的斜率。对于这个的网格,所有的点都在整数刻度上。我们接着画出直线的图像,然后尽可能画几条不合法的路径出来比对一下,你会发现:不合法的路径与直线至少有一个交点,合法路径一定与没有交点。用一张图来直观体会一下: 终点,其中红线为不合法路径,蓝线为合法路径。不难发现,不合法的路径与绿线()都有至少一个交点,因为它们在某次移动后的端点与原点拟合而成的正比例函数的斜率,因此不是合法路径。 那么如何来计算合法和不合法路径的条数呢?直接求出合法路径不好求,规律不好找,因此我们计算出总路径数量,减去不合法数量即是合法路径数量。 可以看到,无论选择什么样的路径,在不左移、不下移的前提下,到达,你都只能移动次(小学内容,把横线和竖线平移到一块数格子),其中右移次、上移次。转化一下,就是在次移动中选出次进行右移操作,总数就是。 因为所有路径,包括合法的和不合法的路径都最终抵达了,难以将内鬼剔除出来。我们选择将不合法路径关于判定线对称过去,它们的新终点将是,也就是。根据上面的推导方法,这里就是在轮移动中挑出次右移操作,于是不合法路径的数量就是:,合法路径数量是:。 (至于为什么用右移次数而不是上移次数,是因为上移受到限制,这意味着你可以一直右移到而无需担心条件限制;但是你就不能先一直上移到,因为这不符合题目要求) 扩展:如果题干中指明向右走的次数不少于向上走的次数,则只需将判定线上下平移为即可。 那这些又和宇宙第一IDE有什么关系呢 应用场景一:括号匹配 将向右走转化为左括号“(”,向上走转化为右括号“)”。对于每一次输入,检查一下左括号输入次数是否永不小于右括号输入次数。若是,当输入最后一个右括号,使左右括号数量相同时,即为匹配成功;若不是,且左括号个数大于右括号个数,则表明括号等待补全;若不是,且左括号个数小于右括号个数,即立即宣布失配。 应用场景二:合法进出栈序列计数问题 假设一个初始为空的栈,有次操作,次进栈,次出栈,请问合法进出栈序列总数(空栈不出)是多少? 答案就是Catalan数,自行套公式计算。 应用场景三:圆的不相交弦计数问题 假设一个圆周上分布着偶数个点,对这些点两两连线,使相连的线不相交的所有方案数。其中一个合法解如下图: 聪明如你,答案还是Catalan数!那么如何转化为已知问题求解呢? 我们将出发点标记为左括号“(”,从出发点引出去的线与其他线/点的所有交点标记为右括号“)”。当所有点两两连接完毕时,根据场景一的模型,一旦左右括号失配即代表不合法,否则合法。因此这个问题也就变成了:给定个左括号和右括号,求出使左右括号匹配的排列个数。在这里,如果问题无解,将会是这样: 例题: P3807 [模板] 卢卡斯定理/Lucas 定理 P5014 水の三角(修改版) (Catalan数公式变形推导)","categories":[{"name":"oi算法","slug":"oi算法","permalink":"https://justpureh2o.github.io/categories/oi%E7%AE%97%E6%B3%95/"}],"tags":[{"name":"算法","slug":"算法","permalink":"https://justpureh2o.github.io/tags/%E7%AE%97%E6%B3%95/"},{"name":"学术","slug":"学术","permalink":"https://justpureh2o.github.io/tags/%E5%AD%A6%E6%9C%AF/"},{"name":"OI","slug":"OI","permalink":"https://justpureh2o.github.io/tags/OI/"},{"name":"数论","slug":"数论","permalink":"https://justpureh2o.github.io/tags/%E6%95%B0%E8%AE%BA/"}]},{"title":"一命已出,前来还愿","slug":"thanks","date":"2023-11-12T01:42:41.000Z","updated":"2024-02-23T08:17:48.754Z","comments":true,"path":"thanks/","link":"","permalink":"https://justpureh2o.github.io/thanks/","excerpt":"","text":"2023.11.11 21:10","categories":[],"tags":[{"name":"原神","slug":"原神","permalink":"https://justpureh2o.github.io/tags/%E5%8E%9F%E7%A5%9E/"}]},{"title":"Latex常用符号大全","slug":"latex-symbols","date":"2023-11-12T01:23:35.000Z","updated":"2024-02-23T08:17:48.754Z","comments":true,"path":"latex-symbols/","link":"","permalink":"https://justpureh2o.github.io/latex-symbols/","excerpt":"","text":"Part1. 运算符 Div1. 基本运算 加号:,键盘上有 减号:,键盘上有 乘号(叉乘): \\times 乘号(数量积/点乘): \\cdot 除号: \\div 开方/N次方根: \\sqrt[N]{ABC} 乘方/N次幂: A^N 下标: A_N 分数: \\frac{A}{B} 等于号:,键盘上有 约等号: \\approx 加粗 \\thickapprox 不等号: \\neq 恒等号/定义为: \\equiv 大于号: \\gt 小于号: \\lt 大于等于: \\geq 小于等于: \\leq 远大于: \\gg 远小于: \\ll 正负: \\pm 负正: \\mp Div.2 几何表示 垂直: \\perp 平行: \\parallel 角/无标记角: \\angle 角/标记角: \\measuredangle 一般全等: \\cong 相似: \\sim,加粗 \\thicksim 三角形: \\triangle 正方形: \\square 圆: \\odot 向量: \\vec_{AB} 或 \\overrightarrow{AB} Div.3 集合 属于: \\in 不属于: \\notin 子集: \\subseteqq 真子集: \\varsubseteqq 或 \\subsetneqq 真子集/直线在平面上: \\subset 正整数集: N^* 或 N_+ 并集: \\cup 交集: \\cap 补集: \\complement{_U^A} Div.4 逻辑符号 因为: 所以: 存在: \\exists 不存在: \\nexists 任意/对于所有: \\forall 空集: \\varnothing 逻辑或: \\cup 或 \\lor 逻辑与: \\cap 或 \\land 逻辑非: \\lnot 充分条件/右双箭头: \\Rightarrow 大小写敏感 必要条件/左双箭头: \\Leftarrow 大小写敏感 充要条件/双向双箭头: \\Leftrightarrow 大小写敏感 Div.5 高级数学 成正比: \\propto 定积分: \\int_{a}^{b} 多重积分: \\iint_{a}^{b} 及 \\iiint_{a}^{b} 导函数/上撇号: \\prime 求和: \\sum_{i=1}^{n} 求积: \\prod_{i=1}^{n} 字母数位/平均数: \\overline{ABCD} 整除符号: \\mid 新定义运算符: \\oplus 及 \\otimes 及 \\ominus 扰动值: \\tilde{K} 高德纳箭头/上箭头: 3\\uparrow \\uparrow 2 Div.6 常数 无穷大/无限: \\infty 圆周率: \\pi 普朗克常数: \\hbar 或 \\hslash Div.7 注音 一声: \\bar{e} 二声/法语闭音符: \\acute{e} 三声: \\check{e} 四声/法语重音符: \\grave{e} 字母双点/德语特殊字母/特殊拼音: \\ddot{u} 特殊发音符: \\tilde{a} 抑扬符: \\hat{a} Div.8 希腊/希伯来字母 小写希腊字母 \\alpha \\beta \\chi \\delta \\epsilon \\eta \\gamma \\iota \\kappa \\lambda \\mu \\nu o \\omega \\phi \\pi \\psi \\rho \\sigma \\tau \\theta \\upsilon \\xi \\zeta 变量希腊字母 \\digamma \\varepsilon \\varkappa \\varphi \\varpi \\varrho \\varsigma \\vartheta 大写希腊字母(仅展示大小写字母样式有差别者) \\Delta \\Gamma \\Lambda \\Omega \\Phi \\Pi \\Psi \\Sigma \\Theta \\Upsilon \\Xi 希伯来文字母 \\aleph \\beth \\daleth \\gimel","categories":[],"tags":[{"name":"latex","slug":"latex","permalink":"https://justpureh2o.github.io/tags/latex/"}]},{"title":"DC Doujin 2023 EP1 先行预告","slug":"dcd2023ep1-trailer","date":"2023-11-05T04:32:52.000Z","updated":"2024-02-23T08:17:48.754Z","comments":true,"path":"dcd2023ep1-trailer/","link":"","permalink":"https://justpureh2o.github.io/dcd2023ep1-trailer/","excerpt":"","text":"DC Doujin 2023,点击访问。 DC Doujin将在11月带来他的第一部视频作品“一触即发 A Cusp Before It Rings”。这个视频,对日常学校干饭的情景进行真实再现。其中由木稿比你铁饰演的受伤学生受到热烈关注,其原型是初中部的一位学生,我们将其镜头化,力求最真实地表现出其强烈的反差感。 禁止用于商业用途,转载请注明出处 DC Doujin。 Copyright © 2023 DC Doujin, JustPureH2O. All Rights Reserved.","categories":[],"tags":[{"name":"DC Doujin","slug":"DC-Doujin","permalink":"https://justpureh2o.github.io/tags/DC-Doujin/"},{"name":"DCD同人","slug":"DCD同人","permalink":"https://justpureh2o.github.io/tags/DCD%E5%90%8C%E4%BA%BA/"},{"name":"新闻","slug":"新闻","permalink":"https://justpureh2o.github.io/tags/%E6%96%B0%E9%97%BB/"}]},{"title":"《原神》枫丹语言考究","slug":"fontainish-research","date":"2023-11-05T02:59:02.000Z","updated":"2024-02-23T08:17:48.754Z","comments":true,"path":"fontainish-research/","link":"","permalink":"https://justpureh2o.github.io/fontainish-research/","excerpt":"","text":"起因 这天月假,当我正为即将到来的水神池子疯狂做任务屯原石时,在列表里看到了一个悬赏整整30原石的世界任务。本着不放过任何一个给原石的任务的宗旨,我来到了秋分山西侧,白淞镇东北方向的海边房屋处。只见一位男子全身掩埋在海沙之下、动弹不得,面前摆放着一只散发香味的甜甜花酿鸡。我看他精神失常,满嘴都是“新型美容方式”的胡话又哭又闹,呜呜呜呜,好可怜呀。于是我决定帮他一把……找出了幕后黑手,此时他举起一个木牌,只见上面用老米祖传的架空文字写了一些东西,随着剧情推进,我们得知这是“抗议”(protest)。枫丹作为两个月前才开放的新国家,其文学文化充满乐子的xxs神明固然吸引了我。于是我决定用手头上有限的图片资料,整理出一份类似于枫丹语言图鉴的资料来。以便后期深入探究枫丹的风土人情。 初探 这是在上一部分中提到的,写有“抗议”(protest)的木牌,其中各个字母的对应关系已经标注出来了(相信不用标注也看得出来)。不难发现,最后一个字母与倒数第四个字母是相同的,恰巧对应上protest中字母t的位置。某种方面上证明了这一猜测的正确性,但是鉴于这抽象到与原英文字母完全不搭边的枫丹字体(很水体)实在是太过亮眼,我的内心还是有一点怀疑和否定的。那么我们将这七个字母挨个抽取出来,放到别的语境中去转译,不就可以验证它的准确性了吗? 其实也无需这么麻烦,读完前面的大佬对提瓦特通用语的解析。我们惊奇地发现,这很水体居然与提瓦特通用语的字母如出一辙: 图片来源于:哔哩哔哩,语颂源,【原神考据】提瓦特通用文 当然也有一些变化,比如哪里可能突然多出来一横、又或者是将圆弧形的笔画变得棱角分明。图中的S和E就是两个典型例子。考虑到可能是手写体带来的美化、钝化等,我接下来去到了枫丹的主城区中,分别在蒸汽鸟报社、卡郎代沙龙前拍下了这几张图片(因为他们离锚点非常的近,不需要跑图)。 蒸气鸟报社——板报 蒸气鸟报社——招牌 卡郎代沙龙——招牌 我们根据已经解译出来的提瓦特通用语字母进行对拍,发现蒸汽鸟报社的招牌上写着:LOISEAU DE VAPEUR。明显是法语,但是其中的VAPEUR和英语的VAPOR(蒸气)非常相似,因此对拍基本无误。但是由于我本人不懂法语,解释不了第一个词,只能求助于度娘。度娘也是给我甩了一个解释:鸟。并纠正了一个小错误:LOISEAU应为L'OISEAU。完美契合蒸汽鸟报社的招牌。 同理,卡郎代沙龙的门牌上写着:CARITAT。推测其原型是18世纪的姓氏德·卡里塔,孔多塞侯爵(Nicolas de Caritat)的妻子便是18世纪的一位著名沙龙主人。 最后放出蒸汽鸟报社门前牌子上的翻译: Exploring the manufacture of security machinery 探秘发条机关(守卫机器)的制造流程 Joyous tour through the aquatic workshop 水下工坊快乐一日游游记 Exclusive compilation of the past top duellists 旧时顶级决斗代理人的独家专访合集 Interview with the deboard restaurant artists 采访德波饭店的艺术家们 Iridescene tour and the new trend of music 虹彩巡游之旅,以及新派音乐","categories":[],"tags":[{"name":"学术","slug":"学术","permalink":"https://justpureh2o.github.io/tags/%E5%AD%A6%E6%9C%AF/"},{"name":"原神","slug":"原神","permalink":"https://justpureh2o.github.io/tags/%E5%8E%9F%E7%A5%9E/"},{"name":"枫丹","slug":"枫丹","permalink":"https://justpureh2o.github.io/tags/%E6%9E%AB%E4%B8%B9/"}]},{"title":"常用算法模板","slug":"common-algo-templates","date":"2023-10-28T06:11:51.000Z","updated":"2024-02-23T08:17:48.754Z","comments":true,"path":"common-algo-templates/","link":"","permalink":"https://justpureh2o.github.io/common-algo-templates/","excerpt":"","text":"1. Trie树(字典树) 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051#include <bits/stdc++.h>#define N 10010using namespace std;int son[N][70], idx = 0, cnt[N];int map(char c) { // 字符映射到对应数字 if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'z') return c - 'a' + 11; if (c >= 'A' && c <= 'Z') return c - 'A' + 37;}void insert(char s[]) { // 插入一个字符串 int len = strlen(s); int p = 0; // 指针 for (int i = 0; i < len; i++) { // 遍历字符串中每一个字符 int u = map(s[i]); // 映射到数字 if (!son[p][u]) son[p][u] = ++idx; p = son[p][u] // 更新指针,指向下一个节点 } cnt[p]++;}bool query(char s[]) { // 查询一个字符串 int len = strlen(s); int p = 0; for (int i = 0; i < len; i++) { // 遍历+查找 int u = map(s[i]); if (son[p][u]) p = son[p][u]; else return false; } return cnt[p];}int count(char s[]) { // 对指定字符串计数 int len = strlen(s); int p = 0; // 可以用 if (query(s)) 代替下边的遍历查找 for (int i = 0; i < len; i++) { int u = map(s[i]); if (son[p][u]) p = son[p][u]; else return 0; } return cnt[p];} 并查集 123456789101112131415161718192021#include <bits/stdc++.h>#define N 10010using namespace std;int p[N];int find(int x) { // 查找父节点+路径压缩 if (p[x] != x) p[x] = find(p[x]); return p[x];}void merge(int a, int b) { // 合并两个集合 p[find(a)] = find(b);}bool query(int a, int b) { // 查询两个节点是否在同一个集合中 return find(a) == find(b);} 单调队列 123456789101112131415161718192021#include <bits/stdc++.h>#define N 10010using namespace std; struct Node { int idx; // 下标 int val; // 数值 } nodes[N];deque<Node> q;void peak(int k) { // 查找区间最值,n为数组大小,k为区间大小,即区间中有k个元素 for (int i = 1; i <= N; i++) { // while (!q.empty() && nodes[i].val <= q.back().val) q.pop_back(); // 查找区间最小值,将大于号改为小于号 while (!q.empty() && nodes[i].val >= q.back().val) q.pop_back(); // 当新进元素大于队尾元素,删除队尾直到队尾大于新元素,或者直到队列为空 q.push_back(nodes[i]); // 将新进元素压入队尾 if (i - q.front().idx == k) q.pop_front(); // 滑出队头元素所在区间,弹出队头 if (i >= k) cout<<q.front().val<<endl; } } 单调栈 12345678910111213141516171819202122#include <bits/stdc++.h>#define N 10010using namespace std; struct Node { int idx; // 下标 int val; // 数值 } nodes[N];stack<Node> stk;int ans[N];void NGE(int k) { // 查找下一个更大的元素,即NGE问题 for (int i = 1; i <= N; i++) { // while (!stk.empty() && nodes[i].val < stk.back().val) // NSE问题,下一个更小的元素,仅改变大于小于号 while (!stk.empty() && nodes[i].val > stk.top().val) stk.pop(); // 将栈顶比当前更小的元素弹出 if (stk.empty()) ans[i] = 0; // 查无 else ans[i] = s.top(); // 顶为最大 stk.push(nodes[i]); // 压入当前 } } 单源最短路径 朴素Dijkstra 12345678910111213141516171819202122232425262728#include <bits/stdc++.h>#define N 10010#define INF 0x3f3f3f3fusing namespace std;// 对于稠密图,使用邻接矩阵存图int g[N][N], dist[N];bool st[N];int n; void dijkstra() { memset(dist, INF, sizeof dist); // 初始化距离,开始时均为正无穷,或者为-1 dist[1] = 0; // 起点最短路径就是0 for (int i = 1; i <= n; i++) { int t = -1; for (int j = 1; j <= n; j++) { if (!st[j] && (t == -1 || dist[j] < dist[t])) t = j; // 循环所有未确定距离的点,找出最小值 } st[t] = true; // 标记访问 for (int j = 1; j <= n; j++) { dist[j] = min(dist[j], dist[t] + g[t][j]); // 间接的路径:从起点经t再连接到j点 } }} 单源最短路径 堆优化Dijkstra 1234567891011121314151617181920212223242526272829303132333435363738394041424344#include <bits/stdc++.h>#define N 10010#define INF 0x3f3f3f3fusing namespace std;// 对于稀疏图,使用接表存图int head[N], e[N], w[N], ne[N];int idx = 0;void add(int a, int b, int x) { idx++; e[idx] = b; w[idx] = x; ne[idx] = head[a]; head[a] = idx;}int dist[N];bool st[N];int n;typedef pair<int, int> PIR; // 二元组存储点序号-距离 priority_queue<PIR, vector<PIR>, greater<PIR> > heap; void dijkstra() { memset(dist, INF, sizeof dist); // 初始化距离,开始时均为正无穷,或者为-1 heap.push((PIR) {1, 0}); // 初始点入队,序号为1距离为0 while (!heap.empty()) { // 堆不空时 PIR t = heap.top(); // 优先队列,队头元素总为未确定点中最近的一个 int id = t.first, dis = t.second; if (st[id]) continue; for (int i = head[id]; ~i; i = ne[idx]) { int j = e[i]; // 边终点 if (dist[j] > dis + w[i]) { dist[j] = dis + w[i]; // 更新最短距离 heap.push((PIR) {j, dist[j]}); // 更新的点压入优先队列 } } }} 背包类动态规划 01背包 想象你在一个绝版手办售卖会上。这里的每种手办由于需要保证它的稀有程度,活动主办方提前向卖家商议了一个计策:即保证每种老婆 手办有且只能有一个。这样他们就可以开出天价 (但要保证在物价局划定的价格上限内) (爆long long也没问题!)。那么作为一个资深 御宅 手办收藏家的你,自然不会错过这次难得的机会,你出门时偷偷拿走了麻麻の钱包,发现里面有元现金(假定你不知道麻麻の银行卡密码),那么你可以买到手办的最大价值是多少? 1234567891011121314151617181920#include <bits/stdc++.h>#define N 100010using namespace std;int w[N], v[N], dp[N];// 价值 占地 容量上限为N时最大价值 int main() { for (int i = 1; i <= n; i++) { // 对于每个物品,从1到n for (int j = c; j >= v[i]; j--) { // 倒着循环,c为容量上限,防止做减法时减为负数内存异常 dp[j] = max(dp[j], dp[j - v[i]] + w[i]); // 状态递推(一维压缩) // 若不选该物品,则状态的剩余容量仍然为j,若选择则为j-v[i],相应的需要加上物品价值 } } cout<<dp[c]; return 0; } 但是最后还是被麻麻发现力(悲 背包类动态规划 完全背包 这种问题类似于西方魔幻小说里的情节:一位勇士无意间闯进了古代君王的藏宝阁,受金钱和权力的蛊惑。看着地上不尽的金币与皇冠,他拿出了一个麻袋。他想要在麻袋规定的最大容量内装尽可能最大价值的物品,超出规定容量,这个袋子很可能破掉,导致财宝落入山谷、沼泽等任何危险的地方。这位勇士十分谨慎,他不希望总重量超过额定重量,那么他能装的最大物品价值是多少? 12345678910111213141516171819202122232425#include <bits/stdc++.h>#define N 100010using namespace std;int w[N], v[N], dp[N];// 价值 占地 容量上限为N时最大价值 int main() { // 完全背包,即每个物品数量有无限个,可以自由装配 for (int i = 1; i <= n; i++) { // 对于每个物品,从1到n for (int j = v[i]; j <= c; j++) { // 正着循环,与01背包相反,c为容量上限 // 由于计算当前状态需用到dp[j-v[i]]状态,若升序循环,这个状态总会在前几步被算出 dp[j] = max(dp[j], dp[j - v[i]] + w[i]); // 状态递推(一维压缩) // 若不选该物品,则状态的剩余容量仍然为j,若选择则为j-v[i],相应的需要加上物品价值 // dp[i][j] = max(dp[i - 1][j], dp[i][j - v[i]] + w[i]) // 若不选择当前物品,最大价值为dp[i-1][j],即前一个/i-1个物品,容量上限为j (j<=c)时的最大价值 // 若选择当前物品,最大价值为dp[i][j-v[i]]+w[i],因为每种物品可以放入无限个,放入第i个物品后仍然可以继续放入相同物品直到超出容量上限j } } cout<<dp[c]; return 0; } 然而我们的勇士痴迷于装入财宝,忽视了高悬在他头顶的致命机关,随着绳子断裂,我们的勇士就此葬身于这个隐蔽的藏宝阁中,带不走任何一枚金币。因此我们的最大价值应该是 因此我们应该拒绝这种来历不明的诱惑,青少年反诈,从我做起! 背包类动态规划 多重背包 《竞赛班传奇》 第一部,第一幕 人物:“和蔼可亲滴”福建籍物理竞赛教练 茂华;“偷奸耍滑的”山东老家OIer 国祯;“热心尽职喜欢让同学们多多预习物理知识的”物理课代表曹牧 茂华上场,开玩笑的语气说 茂华: 电荷量滴单位是~库 仑,符号C(写下一个大C),艹! 全班哄笑,国祯猥琐的笑,茂华眉头一蹙,表情严肃,严肃语气 茂华: 国祯!还在那里笑,曹牧,检查一下国祯有没有记笔记! 曹牧起身走向国祯,其他人目光盯着曹牧,国祯将物理书翻开,指着笔记处,曹牧低头查看,然后抬头 曹牧: 他写了,但是…… 严肃的,急速的,愤怒之极的,气震寰宇的,振聋发聩的,势如破竹的,响彻云霄的,如雷贯耳的,不共戴天的,耳机党爆炸的,外放党社死的 茂华: 站起来!没写笔记! 国祯吓一跳,乖乖站起,曹牧缓缓退回,众人起哄国祯,茂华声音略小 茂华: 在这里偷奸耍滑是会被刷出去滴。到时候你竞赛搞不好,高考也考滴西撇,看你到时候怎么办! 国祯: (解释的语气)我没有偷奸耍滑! 茂华语气有所缓和 茂华: 那你把这道题解出来,你就可以坐下了 题面: 给定个物品,背包最大容量。对于第种物品,给定每个种物品的大小,价值,以及个数,试求出背包可以装下物品的最大价值。 国祯小嘴一撇,这还不简单?他立马拿起了一支0.5mm的黑色签字笔在草稿纸上飞速演算。得益于他积累了一坤年的OI知识,2分钟后,在众人惊异的目光中,国祯自信满满地拿出了写有正确答案的草稿纸。他将右手伸得十分用力,好像要把草稿纸怼到茂华脸上一样,他的嘴角浮现出一抹byd笑容。 只见茂华呆立原地,嘴巴微张,如同按下了暂停键。3秒钟的寂静过后,下课铃如同国祯的战鼓一般敲响,宣告这次对决以国祯的大比分取胜而落下帷幕。茂华直立的双腿尴尬的向门口转去,颤抖的双唇之间轻飘飘冒出了两个字:“下课”。随后咬紧嘴唇,一步一步踱向门外。 国祯如获新生。在众人崇拜和惊诧的目光中,他迷失了自我,他快步走向一体机,熟练地打开希沃白板,好像已经练习过成千上万遍似的,将一句话加粗写在了白板上: 通常情况下,多重背包的思路是将一堆A物品拆分成n个A物品,每个物品只能使用一次,便可转化为01背包问题 他不管大家是否了解01背包的含义,他此刻只想在众人面前分享打败茂华的喜悦感,以及打败茂华所需要的知识,这又何尝不是一种爱屋及乌的思想呢? 第二天,当上午的物理课准时来到,茂华却没有准时跨进教室的门。通常情况下,他每次课前都会提前2分钟来到教室里对同学进行题目过关。 1分钟后,茂华挟着几本不合身份的普及组信息竞赛导论及考纲,昂首阔步地走进了一班教室。他大声说着:“通常情况下。这是国祯同学昨天下课后给你们上的课里的一句原话!” 原来茂华前一天下课后并没有跑回办公室又哭又闹大发牢骚,而是现场网购了信息竞赛教程,准备在第二天的物理课上给国祯单独上节课:学生是永远无法击败老师滴! 他打开了浏览器,输入一行神秘的IP地址,按下回车,一个界面清爽的网站跳了出来。顶端用紫色的大写字母写着MHOI四个大字。 “牛逼吧,这是我连夜赶工自创的网站,”他笑着打开了题目列表中的第一道题,标题: 国祯接招 。国祯轻蔑地瞥了一眼,题干还是昨天那样,一模一样,“看好了国祯,”他指向下排的一行小字,“数据范围:!看你那吃了食的小脑袋还能不能算出这道题目。” 显然,茂华是有备而来,国祯倒吸一口冷气。手工计算绝对是行不通了,但是对于竞赛班的高思娃国祯,绝对是有两把刷子的,毕竟正如茂华所说:“偷奸耍滑耍小聪明早就被刷下去了”。 面对如此巨大的物品总数,一些牛逼娃想到了用二进制拆分表示物品个数的方法。尽管换汤不换药,本质还是一个01背包问题,但是经过祖先们灵魂的注入,茂华是肯定不敢把你踢出竞赛班滴。 假设原有10个价值为2的物品,将10分为1+2+4+3,等同于有4个不同的01物品,价值分别为12=2,22=4,42=8,32=6,即2,4,8,6 国祯很快在VSCode上写出了一段教科书式的、注释易懂的模板代码,这次就算是物竞数竞化竞生竞的人也可以轻易看懂了: 123456789101112131415161718192021222324252627282930313233343536373839404142434445#include <bits/stdc++.h>#define N 100010using namespace std;int w[N], v[N], dp[N];// 价值 占地 容量上限为N时最大价值 int idx = 0;// 记录数组下标 int main() { int n, c; cin>>n>>c; for (int i = 1; i <= n; i++) { int a, b, s; // v w n // 即体积,价值,个数 cin>>a>>b>>s; int k = 1; // 记录2的幂,初始值为2的0次幂,即1 //if (s == 0) s = INF; // 当题目中说数量0时默认为无限次时可以使用,这其实已经属于混合背包(多重+完全)的范畴 while (k <= s) { // 个数可以继续被分解 s -= k; // 更新个数 idx++; // 新的下标 v[idx] = a * k; // 分解后该物品的大小 w[idx] = b * k; // 分解后该物品的价值 k *= 2; // k更新为2的下一个幂 } if (s) { // 若无法被完全分解,剩下一部分 idx++; // 记录新的下标 v[idx] = a * s; // 大小 w[idx] = b * s; // 价值 } } // 01背包模板 for (int i = 1; i <= n; i++) { for (int j = c; j >= v[i]; j--) { dp[j] = max(dp[j], dp[j - v[i]] + w[i]); } } cout<<dp[c]; return 0; } 国祯长舒一口气,这次他又获得了胜利。评测点加载了几秒。国祯定住了,#10号点出现一个大大的。国祯感觉堕入了万丈深渊,只见茂华狂笑了起来,带动全班其他同学的笑容,一班霎时被笑声吞没。国祯盯着评测信息,的运行时间让他更为疑惑,莫非茂华手动写了一个错误答案? 国祯尴尬的转向各位同学,其他同学瞬间停止了笑容。先前还在交头接耳的同学们如同机器一般齐刷刷的转向国祯,给人一种惊悚透骨的感觉。他们异口同声张开了嘴,在茂华扭曲的笑容下,说出了让国祯后悔了一辈子的话来: “三年OI一场空,不开long long见祖宗!” 背包类动态规划 混合背包 混合背包,顾名思义。它混合了多种背包,实际应用中这一类问题比较有现实意义。主要思路是,将分属于各个类型背包的物品用几个条件判断语句写出来,然后分别套用各类背包的解决方案进行求解。 123456789101112131415161718192021#include <bits/stdc++.h>#define N 100010using namespace std;int w[N], v[N], dp[N];// 价值 占地 容量上限为N时最大价值 int main() { for (int i = 1; i <= n; i++) { if (A) { // 01背包物品,写01背包模板 } if (B) { // 完全背包物品,写完全背包模板 } if (C) { // 其他…… } } return 0; }","categories":[],"tags":[{"name":"算法","slug":"算法","permalink":"https://justpureh2o.github.io/tags/%E7%AE%97%E6%B3%95/"},{"name":"学术","slug":"学术","permalink":"https://justpureh2o.github.io/tags/%E5%AD%A6%E6%9C%AF/"},{"name":"OI","slug":"OI","permalink":"https://justpureh2o.github.io/tags/OI/"}]},{"title":"国祯文集","slug":"gz-articles","date":"2023-10-26T09:29:45.000Z","updated":"2024-02-23T08:17:48.754Z","comments":true,"path":"gz-articles/","link":"","permalink":"https://justpureh2o.github.io/gz-articles/","excerpt":"","text":"曾茂华到底有多六 ——By 国祯 曾茂华是中国当代著名的科学家和教育家,他以“慈父”、“良师”、“学者”等称号闻名于世。 1:曾茂华的蠢行为 曾茂华的蠢行为: 他在大学期间参加了一个乐队,并担任主唱。然而,不幸的是,由于自己的疏忽,他犯下了一件愚蠢的事情——用刀砍掉了对方的手指头。这件事让他成了学校里的头号人物之一。从那以后,他再也不敢做任何愚蠢的事情了。这是因为他害怕自己会被开除出乐队或者成为众矢之的的对象。如果他继续做出这些错误的举动,那么他会失去自己的乐队成员资格,甚至还会遭到开除。所以,为了避免发生这样的悲剧,他必须要记住:永远不要犯错! 2:为什么他会做出这种愚蠢的事情? 曾茂华的蠢行为发生在他身上,是因为他自己没有意识到他自己的愚蠢。他不知道怎么做才能让事情变得更好,他只想走捷径,而不是去努力做好事情。这种心态会导致他做出错误的决定,因为他会忽略一些重要的信息,或者选择性地记住某些信息。当我们看到一个人犯了下述三种类型的罪时,我们通常就能预测到这个人会再犯同样的问题:1. 根本不会思考问题2. 一味追求便利3. 盲目模仿别人 3: 该如何面对这个问题? 要想解决问题,首先要认识到自己的行为是愚蠢的。只有当你明白自己做了什么蠢事时,才能够改变你的行为来避免这种错误。其次,不要让别人知道你所犯下的错误。这并不是因为你不想坦白自己所犯错误,而是因为这样会给别人带来困扰。最后,如果你真的想要解决这个问题,可以尝试通过一些有趣的方式来实现它。例如,你可以去找一位专业人士帮助你分析一下这件事情,或者试着去找到一个愿意与你分享观点和建议的人。总之,如果你认为自己的行为很蠢,那么就要大胆地承认出来。只有敢于直面自己的无知,才能真正地改善自己的生活。 曾茂华先生不仅对科学领域做出了巨大贡献,而且为国家培养出一批优秀的人才。这些人中不乏有牛顿这样伟大的人物,也有王选这样杰出的人物。","categories":[],"tags":[{"name":"整活","slug":"整活","permalink":"https://justpureh2o.github.io/tags/%E6%95%B4%E6%B4%BB/"},{"name":"国祯","slug":"国祯","permalink":"https://justpureh2o.github.io/tags/%E5%9B%BD%E7%A5%AF/"},{"name":"文章","slug":"文章","permalink":"https://justpureh2o.github.io/tags/%E6%96%87%E7%AB%A0/"}]},{"title":"CSP-J 2023 游记","slug":"journey-to-the-cspj2023","date":"2023-10-24T08:21:36.000Z","updated":"2024-02-23T08:17:48.754Z","comments":true,"path":"journey-to-the-cspj2023/","link":"","permalink":"https://justpureh2o.github.io/journey-to-the-cspj2023/","excerpt":"","text":"又名:《第一次考就被小学生薄纱的一集》 本次考场:绵阳东辰国际学校 第一节 赛前准备 插一句:CSP-J 2023没有设置赛前试机环节(包括CSP-S,成都绵阳都这样),个人推测可能是由于开放自选Windows和Linux系统带来的结果。如果你听见诸如:不要操作电脑,违者将作作弊处理 的话时,请将你按捺不住的双手安稳的放在双腿上,避免出现意料之外的事来。 然而赛前试机仍然是必要的一环(但是如果考场纪律有要求那就算了),因为这样可以让选手对机器有一个初步的了解。因为我本人习惯使用Win+E打开文件系统管理器,用Win+V记录剪切板数据,可是这些功能在考场电脑上都无法使用,进行赛前试机不仅可以避免因赛时临时发现无法使用某些功能而带来的苦恼心态爆炸点+1,而且还可以将IDE环境调整到个人喜欢的状态(例如缺省源代码,相当于每次新建代码不用重新打头文件)。选手可以不占用正式比赛时间完成一些个性化操作,方便赛时操作,其重要性不言而喻。 当然,开赛前乱猜试题PDF密码是极其无意义且几乎不可能成功的一件事,更不要使用暴力破解密码工具破解文件(相信守规矩的你也不会将这种工具带进考场里来),这么做不仅会被当做作弊者处理,而且造成的数据丢失也只能由你自己负责。 第二节 开赛之初 考场下发的PDF文件带有密码保护,输入时请务必瞪大眼睛区分大小写字母O、o与数字0;小写字母l、大写字母I与数字1,并且将其中的特殊字符认真核对一遍。本次考试,我有幸将密码中的数字0写成了小写字母o,于是浪费了宝贵的2分钟时间改正密码(真实情况是监考老师在黑板上书写密码时字迹不规范导致的混淆)。因此需要认真看好你的密码。 就我认为:在一开始就仔细写好文件重定向输入输出是极其重要的,因为随着考试时间的推进,你的思考重点将从细节性问题变为如何拿到更多的分数上骗分。你就会忽略重新写上两行重定向IO的代码,因而可能Au->Cu,光荣AFO。为了引起你的注意,使用极长的注释双斜线是可行的,我本人习惯打上断点。例如: 12//////////////////////////////////////////////// freopen(\"uqe.in\", \"r\", stdin);//////////////////////////////////////////////// freopen(\"uqe.out\", \"w\", stdout); 将比 12//freopen(\"uqe.in\", \"r\", stdin);//freopen(\"uqe.out\", \"w\", stdout); 显眼得多——尤其是当你喜欢为每行代码写上包含心血的易懂注释时。事后你可以通过长按Ctrl+逗号(Dev-C++)的方式快速且安全的删除这些斜线。 不仅如此,看好输入输出文件名也是一个非常重要的细节,建议直接复制粘贴。对于标准样例,直接选中PDF文字再复制一般都不是一个明智的做法,手动输入也是可行的,但是对拍有时会比较繁琐(例如普及组T3的样例)。这边传授一个方便的做法:选中代码左侧序号,在WPS中直接右键菜单点击消除文字即可(本次考试我就是使用的这个方便技巧快捷复制样例数据)。最好找张纸记下来,后面会讲到原因。 顺利解锁了PDF文件,你要做的第一件事就是将四道题全部读熟。对整场比赛的题目有大致的规划,有可能你先前做题时做过与T4极其相似的题目,那么放弃显然是一个很不划算的决策。将题目读熟,大概判断一下算法实现,评估自己哪些题能做好,哪些题要放一放/完全放弃。知己知彼方能百战百胜。 赛初的状态基本上决定了你整场比赛的表现,因此在赛初就做好一切细节方面的完全准备,对你的信心增长是非常重要的! 第三节 赛中时期 那么你现在拿到了第一题(信心题)。一般来说,CSP的复赛,算法很少裸露地出现在题目之中,前两题近似看作数学题。保证你的数学思维在线,因为第一题的思路可能千奇百怪,如果你一段时间没有思路(对于第一题大概是5~15分钟),可以考虑先做其他题目。刷新一下思维定势,有可能T1的灵感就乍现于其他题目之中。 在符合时间规划的前提下尽可能多去造hack数据,写出一段代码(尤其是T3放大模拟时)后,千万保证没有任何逻辑问题。当然,不是所有人都能只看代码就能检查的出其中的逻辑漏洞。因此你需要多造hack数据。hack数据多数情况下包括这几个要素:方程的特殊解、极端值/边界值、大数据(int越界)。在规划好的时间内想尽办法为你的代码多挑几根刺出来,你的代码才能更加趋近于满分解。 千万不要看你旁边的人!!! 除非S组巨佬闯进了J组蒟蒻区,否则千万不要在比赛中途去看任何人的任何行为。一方面,你的行为可能被视作交谈作弊喜提CCF全国通报、禁赛3年大礼包;另一方面,如果你抱着嘲笑别人的心态去观察别人,那么你的脸很可能就会被你自己打烂。我在考试时因为瞧不起隔壁的一位小学生,当他开始疯狂敲代码时,我自己的心态就爆炸了——把所有人,不分男女、年龄高低,都当作你的敌人,轻视则死。同时这也给你带来一部分紧张感,会使你的发挥更佳。 给自己适当的放松与勉励,要相信,上天不是无故给你这个周末不用冒着风雨大太阳上补习班的珍贵机会(对于高中生,则是周六不用坐在教室里上正课的机会)。当你完全确认你的代码已经完美无瑕时,告诉自己:同学们都还在悲催的上着课,我却在外边快乐的敲着代码。如此一来可以起到调整心态的作用。 别激动到顺手关了PDF文件。如果你还记得或者是在草稿纸上写了密码,那无所谓;但是如果你没写,你的处境就非常尴尬,这时你可以举手找老师再要,但这绝对对你的心态是一个不小的打击。 第四节 赛末时期 经历三个半小时的不懈奋斗,比赛终于迎来最后的半小时。无论你的完成情况如何,一定要用这最后的时间好好检查一下你的代码。瞄一眼你是否有与下面类似的代码: 12freopen(\"uqe2.in\", \"r\", stdin); // 危freopen(\"uqe2.out\", \"w\", stdout); // 爆零警告 这段代码的主人是个懒人无疑了,如果你把CCF提供的附加样例复制了出来。切记最后把文件名里的序号删除,否则你就可以AFO了。 或者以下的代码: 1234#include <Windows.h>//其他的代码if (system(\"fc uqe.out uqe.ans\")) cout<<\"WA\"<<endl;else cout<<\"AC\"<<endl; 这位同学也是个Windows爱好者受害者无疑了,CCF明文规定了测试用系统为NOI Linux。因此不存在Windows.h这个头文件,如果你忘记删除了,那一定是个大大滴CE。正式比赛时,用bits/stdc++.h万能头即可(Windows和Linux通用)。我有一个考S组的朋友,因为忘记删除这个对拍头文件而喜提一个0分,直接亏大发。 不要忘记将你的重定向取消注释。你连读入输出都没有了,属实是可以AFO了。最后三分钟,请将你的蹄子挪开键盘鼠标。否则可能会越改越慌,不妨好好回想一下这周老师留了什么作业,你缺了哪些课需要去补,总之不要再动你的鼠标键盘了!如果实在是不放心编译问题,按一下F11,通过即可。保证你的工作目录下只留.cpp文件,所以将你复制的样例文件和编译的exe文件全部删除。 第五节 考试结束 请你千万保持冷静,不要习惯性地把机器关机了。CCF明文规定:由关机造成的数据损失,责任由考生自负。只需要把你的IDE关闭就好。 回家后,把周一要交的作业补好。别再谈考试的事情了,让你自己有个好心情。毕竟不管你的表现怎么样,它都过去了不是吗?","categories":[],"tags":[{"name":"CSP-J","slug":"CSP-J","permalink":"https://justpureh2o.github.io/tags/CSP-J/"},{"name":"赛后总结","slug":"赛后总结","permalink":"https://justpureh2o.github.io/tags/%E8%B5%9B%E5%90%8E%E6%80%BB%E7%BB%93/"}]},{"title":"人物传记·FRC(搬运)","slug":"biography-to-frc-delivery","date":"2023-07-29T13:17:19.000Z","updated":"2024-02-23T08:17:48.754Z","comments":true,"path":"biography-to-frc-delivery/","link":"","permalink":"https://justpureh2o.github.io/biography-to-frc-delivery/","excerpt":"","text":"本文转载自:【F444 の 光荣历史•其二】人物传记·FRC 作者:Lucas2011 一、简介 曾就读于东辰「教学8班·行政11班」与我同班(两个都是哦),是我初中阶段最好的朋友。现就读于七林9班,在高中数学竞赛的道路上越走越远。喜好有Minecraft、原和一些神奇的卡牌游戏。有批判性思维,不从众,但是对自己的观点有强烈的自信,不拿出证据证明他是错的的话他绝对不会善罢甘休(但是在学校里证据真的很难找awa)。特别喜欢讲故事,经常编一些东西以假乱真,甚至到了剩下的5个人异口同声的问他“真的吗?”这种地步。 二、外号来源 FRC又知名为天皇陛下,冯进村等等(反正都是从“日本天皇”衍生出来的)。那么这个外号是从哪里来的呢?据传说(主要大家基本都快忘了,经过讨论认定了这个最终版本),一次中午回寝,大家在激烈的讨论历史课上刚刚讲的日本明治维新相关的内容,FRC为了让大家认真的听他的观点,就说“我是天皇陛下…”,于是这个外号就传开了。四舍五入这个外号是他自己取的 三、关于学习 相信不用我多说了,能进七林九班的都不是什么善茬。但是我还是附上一次8年级(大概)的月考成绩图: 月考成绩图 ∆天皇稳居第一,高第二名十多分 除了学习,其实我更想说的是他的批判性思维。这一点可能和其他寝室不同,我们寝室常常谈论一些时政内容或者类似的需要表达自己的观点并证明的内容。在这样的环境下,小蝴蝶、我、天皇和其他公民(ffy经常偷听我们聊天但是不说话,sbffy)都能有一套自己的论证思路并相互交融,我不认为这对逻辑思维能力的发展没有帮助。 四、关于游戏 分成两个部分吧,原和Minecraft。 原神 应该是初三下学期才入的坑,算比较晚的。他入坑在我看来应该是被逼无奈,实在和他的好朋友们没有共同话题才入的坑。但是他入坑后特别肝,现在应该55级了吧(思考) 由于他B我官(他B服,我官服,我们两个之间已经隔了一道厚障壁力(悲),所以基本没怎么联过机,但是后来他朋友送了他一个官服号,就和我玩过一两次(主要O是养成类游戏,那个号上什么也没有)。 他狂热地厨纳西妲,所以就在这里放两张纳西妲的游戏截图吧(太随性了awa): 1 2 3 ∆这个应该是他草神的面板(翻了10分钟聊天记录才找到qwq Minecraft 自从我认识他(在军训的时候)他就玩mc,还记得当时我们因为2个木板合成几个木棍而吵架(他说“两个木板合成两个木棍”,我说是4个,事后他便获得了“cloud player”这个称号,不过现在已经没什么人喊了)。 和他在信息技术课上(常规课和社团课)玩过1.12匠魂,1.18原版和空岛,1.18.2匠魂等等(甚至为了这个去学了C++并考了校队,走上一条OI不归路 他记忆力很好,所有模组相关的合成表我都直接问他,像什么《匠魂宝典》都是他读,读完了就把有用的属性提炼出来给我说。 当然,我主要负责生电和指令嘛(撅嘴 下面是一些游戏截图: 4 5 6 ∆这些都是匠魂的存档,空岛的没怎么截图 五、自述 由于天皇现在在七林扫荡,找不到他人,所以这个部分先咕掉(*≧ω≦) 当然,天皇是不会被放过的(早柚音 六、他人刻画 这个部分应该是最精彩的部分(确信 天皇为什么叫天皇我也不知道,开始他看起来比较可爱但后面就越来越猥琐,有着非常智慧的大脑,比较喜欢理性分析问题,然后感性处理问题(指看心情),好玩做事比较冲动喜欢玄学,求知欲旺,又不的问题,一定会细心请教不是不擅长运动比较懒惰,口才很好喜欢讲故事,有点贪睡眠质量良好呼噜声特别大特别情况下被刺激会暴怒。 冯氏、本名瑞辰。传闻天地初开之时,天下五分,雷占其四而天皇独占其一,是为一人之下,万人之上矣。遂有天皇之名(语出《sl经典语录》)数学之王(官方限定)在数学方面卓有天赋。为人和善。初极狭,才通人。口才极佳,善于讲故事。京中有善口技者,为寝室建设作出卓越贡献,但会在晚上使用声波武器,对寝室成员们进行精神攻击0.o 这个事件后面会讲(应该 不可避免的偏题了qwq 总之感觉就是比我nb但是心术大不正(离谱 的那种学神 话题莫名其妙的回来了awa 天皇陛下,不知道为什么,每次看到他抱着自己家的柴犬的照片时,总有一种兄弟情深的感觉。 感觉他严肃正经起来很有学霸的气息,但是一旦下了课,我总能在校围栏旁的草丛附近发现他的身影。 尤其喜爱捉某些昆虫(指蝴蝶),采摘水果(指东辰的桃子和杏),能夹,yin叫起来比大部分人(除开胡睿杰)更像女的。 自从他脸上受伤留下一道光荣印记以来,他的笑容比之前猥琐了指数倍。 但是对于他的智力,无可置疑的是他确实实力无限,他和那些闷头整天坐在教室里学习的娃的最大区别就是:他深谙劳逸结合的重要性,平时也会和同学打成一片,尤其喜欢叫外号,据个人无数据的不完全统计——他最钟爱的外号包括guozhen、sb飞飞鱼、小蝴蝶、草绿等。 不知道怎么请到的神奇人物 就看起来傻不拉叽,但十分聪明的一个人。奇奇怪怪,但很喜欢作为上课的气氛担当。就是说至于用书签削学校的转基因农作物,抓些小虫养在教室这种行为,我的评价是👍。讲真的,聪明人还是聪明人,还是有亿点离谱的。","categories":[],"tags":[{"name":"生活","slug":"生活","permalink":"https://justpureh2o.github.io/tags/%E7%94%9F%E6%B4%BB/"},{"name":"传记","slug":"传记","permalink":"https://justpureh2o.github.io/tags/%E4%BC%A0%E8%AE%B0/"},{"name":"初中同学","slug":"初中同学","permalink":"https://justpureh2o.github.io/tags/%E5%88%9D%E4%B8%AD%E5%90%8C%E5%AD%A6/"},{"name":"搬运","slug":"搬运","permalink":"https://justpureh2o.github.io/tags/%E6%90%AC%E8%BF%90/"},{"name":"整活","slug":"整活","permalink":"https://justpureh2o.github.io/tags/%E6%95%B4%E6%B4%BB/"}],"author":"Lucas2011"}],"categories":[{"name":"开发记录","slug":"开发记录","permalink":"https://justpureh2o.github.io/categories/%E5%BC%80%E5%8F%91%E8%AE%B0%E5%BD%95/"},{"name":"博客搭建","slug":"博客搭建","permalink":"https://justpureh2o.github.io/categories/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/"},{"name":"oi算法","slug":"oi算法","permalink":"https://justpureh2o.github.io/categories/oi%E7%AE%97%E6%B3%95/"},{"name":"题解","slug":"题解","permalink":"https://justpureh2o.github.io/categories/%E9%A2%98%E8%A7%A3/"},{"name":"自学的数学","slug":"自学的数学","permalink":"https://justpureh2o.github.io/categories/%E8%87%AA%E5%AD%A6%E7%9A%84%E6%95%B0%E5%AD%A6/"}],"tags":[{"name":"博客","slug":"博客","permalink":"https://justpureh2o.github.io/tags/%E5%8D%9A%E5%AE%A2/"},{"name":"前端","slug":"前端","permalink":"https://justpureh2o.github.io/tags/%E5%89%8D%E7%AB%AF/"},{"name":"后端","slug":"后端","permalink":"https://justpureh2o.github.io/tags/%E5%90%8E%E7%AB%AF/"},{"name":"开发记录","slug":"开发记录","permalink":"https://justpureh2o.github.io/tags/%E5%BC%80%E5%8F%91%E8%AE%B0%E5%BD%95/"},{"name":"算法","slug":"算法","permalink":"https://justpureh2o.github.io/tags/%E7%AE%97%E6%B3%95/"},{"name":"oi","slug":"oi","permalink":"https://justpureh2o.github.io/tags/oi/"},{"name":"dp","slug":"dp","permalink":"https://justpureh2o.github.io/tags/dp/"},{"name":"学习笔记","slug":"学习笔记","permalink":"https://justpureh2o.github.io/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"},{"name":"题解","slug":"题解","permalink":"https://justpureh2o.github.io/tags/%E9%A2%98%E8%A7%A3/"},{"name":"整活","slug":"整活","permalink":"https://justpureh2o.github.io/tags/%E6%95%B4%E6%B4%BB/"},{"name":"C#","slug":"C","permalink":"https://justpureh2o.github.io/tags/C/"},{"name":"qexo","slug":"qexo","permalink":"https://justpureh2o.github.io/tags/qexo/"},{"name":"学术","slug":"学术","permalink":"https://justpureh2o.github.io/tags/%E5%AD%A6%E6%9C%AF/"},{"name":"数学","slug":"数学","permalink":"https://justpureh2o.github.io/tags/%E6%95%B0%E5%AD%A6/"},{"name":"教程","slug":"教程","permalink":"https://justpureh2o.github.io/tags/%E6%95%99%E7%A8%8B/"},{"name":"破解","slug":"破解","permalink":"https://justpureh2o.github.io/tags/%E7%A0%B4%E8%A7%A3/"},{"name":"DC Doujin","slug":"DC-Doujin","permalink":"https://justpureh2o.github.io/tags/DC-Doujin/"},{"name":"DCD同人","slug":"DCD同人","permalink":"https://justpureh2o.github.io/tags/DCD%E5%90%8C%E4%BA%BA/"},{"name":"新闻","slug":"新闻","permalink":"https://justpureh2o.github.io/tags/%E6%96%B0%E9%97%BB/"},{"name":"OI","slug":"OI","permalink":"https://justpureh2o.github.io/tags/OI/"},{"name":"数论","slug":"数论","permalink":"https://justpureh2o.github.io/tags/%E6%95%B0%E8%AE%BA/"},{"name":"原神","slug":"原神","permalink":"https://justpureh2o.github.io/tags/%E5%8E%9F%E7%A5%9E/"},{"name":"latex","slug":"latex","permalink":"https://justpureh2o.github.io/tags/latex/"},{"name":"枫丹","slug":"枫丹","permalink":"https://justpureh2o.github.io/tags/%E6%9E%AB%E4%B8%B9/"},{"name":"国祯","slug":"国祯","permalink":"https://justpureh2o.github.io/tags/%E5%9B%BD%E7%A5%AF/"},{"name":"文章","slug":"文章","permalink":"https://justpureh2o.github.io/tags/%E6%96%87%E7%AB%A0/"},{"name":"CSP-J","slug":"CSP-J","permalink":"https://justpureh2o.github.io/tags/CSP-J/"},{"name":"赛后总结","slug":"赛后总结","permalink":"https://justpureh2o.github.io/tags/%E8%B5%9B%E5%90%8E%E6%80%BB%E7%BB%93/"},{"name":"生活","slug":"生活","permalink":"https://justpureh2o.github.io/tags/%E7%94%9F%E6%B4%BB/"},{"name":"传记","slug":"传记","permalink":"https://justpureh2o.github.io/tags/%E4%BC%A0%E8%AE%B0/"},{"name":"初中同学","slug":"初中同学","permalink":"https://justpureh2o.github.io/tags/%E5%88%9D%E4%B8%AD%E5%90%8C%E5%AD%A6/"},{"name":"搬运","slug":"搬运","permalink":"https://justpureh2o.github.io/tags/%E6%90%AC%E8%BF%90/"}]} \ No newline at end of file diff --git a/css/Readme.html b/css/Readme.html new file mode 100644 index 0000000000..e077c75278 --- /dev/null +++ b/css/Readme.html @@ -0,0 +1,22 @@ +

样式文件说明

+

样式拆分说明

+

方案是对 https://blog.skk.moe/post/improve-fcp-for-my-blog/ +的开源实现

+

first.styl

+

首屏样式, 内含 首屏基础样式、 cover、 navbar、 +首屏search、首屏暗黑模式、首屏字体 等样式, +首屏样式采用硬编码的方式写在HTML中.

+

内联硬编码自动化方案 see:scripts/helpers/first-style/index.js

+

style.styl

+

异步加载样式, 除首屏样式外的其他样式, 最终生成 /css/style.css +异步加载.

+

暗黑模式样式说明

+

暗黑模式样式被拆分为首屏暗黑模式样式和异步暗黑模式样式,其中在 +source/css/ 文件夹下:

+

_first/dark_first.styl : 包含 首屏暗黑模式样式 的 暗黑模式 CSS 变量 +和 强制覆盖样式

+

_style/_plugins/_dark : 异步暗黑模式样式文件夹

+

_style/_plugins/_dark/dark_async.styl : 包含 异步暗黑模式样式 的 +暗黑模式 CSS 变量

+

_style/_plugins/_dark/dark_plugins.styl : 包含 异步暗黑模式样式 的 +强制覆盖样式

diff --git a/css/collapsible.css b/css/collapsible.css new file mode 100644 index 0000000000..86b64bc536 --- /dev/null +++ b/css/collapsible.css @@ -0,0 +1,60 @@ +.collapsible { + margin: 5px 0; + padding: 0 15px; + border: 1px solid #E5E5E5; + position: relative; + clear: both; + border-radius: 3px; +} + +.collapsible .collapsible-title { + background: #E5E5E5; + margin: 0 -15px; + padding: 5px 15px; + color: #353535; + font-weight: bold; + font-size: 13px; + display: block; + cursor: pointer; +} + +.collapsible .collapsible-title:before { + font-weight: bold; +} + +.collapsible.collapsed .collapsible-title:before { + content: "展开 "; +} + +.collapsible.expanded .collapsible-title:before { + content: "隐藏 "; +} + +.collapsible .collapsible-content { + padding-top: 0; + padding-bottom: 0; + margin-top: 0; + margin-bottom: 0; + -moz-transition-duration: 0.3s; + -webkit-transition-duration: 0.3s; + -o-transition-duration: 0.3s; + transition-duration: 0.3s; + -moz-transition-timing-function: ease-in-out; + -webkit-transition-timing-function: ease-in-out; + -o-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; +} + +.collapsible.collapsed .collapsible-content { + overflow: hidden; + max-height: 0; +} + +.collapsible.expanded .collapsible-content { + max-height: 3000px; + overflow: hidden; +} + +.collapsible .collapsible-content p:first-child { + margin-top: 0 !important; +} \ No newline at end of file diff --git a/css/first.css b/css/first.css new file mode 100644 index 0000000000..64d003d4ca --- /dev/null +++ b/css/first.css @@ -0,0 +1,1842 @@ +#safearea { + display: none; +} +.post-story + .post-story { + content-visibility: auto; + contain-intrinsic-size: 10px 500px; +} +:root { + --color-site-body: #f4f4f4; + --color-site-bg: #f4f4f4; + --color-site-inner: #fff; + --color-site-footer: #666; + --color-card: #fff; + --color-text: #444; + --color-block: #f6f6f6; + --color-inlinecode: #c74f00; + --color-codeblock: #fff7ea; + --color-h1: #3a3a3a; + --color-h2: #3a3a3a; + --color-h3: #333; + --color-h4: #444; + --color-h5: #555; + --color-h6: #666; + --color-p: #444; + --color-list: #666; + --color-list-hl: #30ad91; + --color-meta: #888; + --color-read-bkg: #e0d8c8; + --color-read-post: #f8f1e2; + --color-copyright-bkg: #f5f5f5; +} +* { + box-sizing: border-box; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + outline: none; + margin: 0; + padding: 0; +} +*::-webkit-scrollbar { + height: 4px; + width: 4px; +} +*::-webkit-scrollbar-track-piece { + background: transparent; +} +*::-webkit-scrollbar-thumb { + background: #3dd9b6; + cursor: pointer; + border-radius: 2px; + -webkit-border-radius: 2px; +} +*::-webkit-scrollbar-thumb:hover { + background: #ff5722; +} +html { + color: var(--color-text); + width: 100%; + height: 100%; + font-family: HYJiangJunJ, "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Menlo, Monaco, monospace, sans-serif; + font-size: 16px; +} +html >::-webkit-scrollbar { + height: 4px; + width: 4px; +} +html >::-webkit-scrollbar-track-piece { + background: transparent; +} +html >::-webkit-scrollbar-thumb { + background: #3dd9b6; + cursor: pointer; + border-radius: 2px; + -webkit-border-radius: 2px; +} +html >::-webkit-scrollbar-thumb:hover { + background: #ff5722; +} +body { + background-color: var(--color-site-body); + text-rendering: optimizelegibility; + -webkit-tap-highlight-color: rgba(0,0,0,0); + line-height: 1.6; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +body.modal-active { + overflow: hidden; +} +@media screen and (max-width: 680px) { + body.modal-active { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + } +} +a { + color: #2092ec; + cursor: pointer; + text-decoration: none; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +a:hover { + color: #ff5722; +} +a:active, +a:hover { + outline: 0; +} +ul, +ol { + padding-left: 0; +} +ul li, +ol li { + list-style: none; +} +header { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; +} +img { + border: 0; + background: none; + max-width: 100%; +} +svg:not(:root) { + overflow: hidden; +} +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + height: 0; + border: 0; + border-radius: 1px; + -webkit-border-radius: 1px; + border-bottom: 1px solid rgba(68,68,68,0.1); +} +button, +input { + color: inherit; + font: inherit; + margin: 0; +} +button { + overflow: visible; + text-transform: none; + -webkit-appearance: button; + cursor: pointer; +} +@supports (backdrop-filter: blur(20px)) { + .blur { + background: rgba(255,255,255,0.9) !important; + backdrop-filter: saturate(200%) blur(20px); + } +} +.shadow { + box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); +} +.shadow.floatable { + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +.shadow.floatable:hover { + box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); +} +#l_cover { + min-height: 64px; +} +.cover-wrapper { + top: 0; + left: 0; + max-width: 100%; + height: 100vh; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + flex-wrap: nowrap; + -webkit-flex-wrap: nowrap; + -khtml-flex-wrap: nowrap; + -moz-flex-wrap: nowrap; + -o-flex-wrap: nowrap; + -ms-flex-wrap: nowrap; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + align-items: center; + align-self: center; + align-content: center; + color: var(--color-site-inner); + padding: 0 16px; + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + position: relative; + overflow: hidden; + margin-bottom: -100px; +} +.cover-wrapper .cover-bg { + position: absolute; + width: 100%; + height: 100%; + background-position: center; + background-size: cover; + -webkit-background-size: cover; + -moz-background-size: cover; +} +.cover-wrapper .cover-bg.lazyload:not(.loaded) { + opacity: 0; + -webkit-opacity: 0; + -moz-opacity: 0; +} +.cover-wrapper .cover-bg.lazyload.loaded { + animation-delay: 0s; + animation-duration: 0.5s; + animation-fill-mode: forwards; + animation-timing-function: ease-out; + animation-name: fadeIn; +} +@-moz-keyframes fadeIn { + 0% { + opacity: 0; + -webkit-opacity: 0; + -moz-opacity: 0; + filter: blur(12px); + transform: scale(1.02); + -webkit-transform: scale(1.02); + -khtml-transform: scale(1.02); + -moz-transform: scale(1.02); + -o-transform: scale(1.02); + -ms-transform: scale(1.02); + } + 100% { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } +} +@-webkit-keyframes fadeIn { + 0% { + opacity: 0; + -webkit-opacity: 0; + -moz-opacity: 0; + filter: blur(12px); + transform: scale(1.02); + -webkit-transform: scale(1.02); + -khtml-transform: scale(1.02); + -moz-transform: scale(1.02); + -o-transform: scale(1.02); + -ms-transform: scale(1.02); + } + 100% { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } +} +@-o-keyframes fadeIn { + 0% { + opacity: 0; + -webkit-opacity: 0; + -moz-opacity: 0; + filter: blur(12px); + transform: scale(1.02); + -webkit-transform: scale(1.02); + -khtml-transform: scale(1.02); + -moz-transform: scale(1.02); + -o-transform: scale(1.02); + -ms-transform: scale(1.02); + } + 100% { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } +} +@keyframes fadeIn { + 0% { + opacity: 0; + -webkit-opacity: 0; + -moz-opacity: 0; + filter: blur(12px); + transform: scale(1.02); + -webkit-transform: scale(1.02); + -khtml-transform: scale(1.02); + -moz-transform: scale(1.02); + -o-transform: scale(1.02); + -ms-transform: scale(1.02); + } + 100% { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } +} +.cover-wrapper .cover-body { + z-index: 1; + position: relative; + width: 100%; + height: 100%; +} +.cover-wrapper#full { + height: calc(100vh + 100px); + padding-bottom: 100px; +} +.cover-wrapper#half { + max-height: 640px; + min-height: 400px; + height: calc(36vh - 64px + 200px); +} +.cover-wrapper #scroll-down { + width: 100%; + height: 64px; + position: absolute; + bottom: 100px; + text-align: center; + cursor: pointer; +} +.cover-wrapper #scroll-down .scroll-down-effects { + color: #fff; + font-size: 24px; + line-height: 64px; + position: absolute; + width: 24px; + left: calc(50% - 12px); + text-shadow: 0 1px 2px rgba(0,0,0,0.1); + animation: scroll-down-effect 1.5s infinite; + -webkit-animation: scroll-down-effect 1.5s infinite; + -khtml-animation: scroll-down-effect 1.5s infinite; + -moz-animation: scroll-down-effect 1.5s infinite; + -o-animation: scroll-down-effect 1.5s infinite; + -ms-animation: scroll-down-effect 1.5s infinite; +} +@-moz-keyframes scroll-down-effect { + 0% { + top: 0; + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } + 50% { + top: -16px; + opacity: 0.4; + -webkit-opacity: 0.4; + -moz-opacity: 0.4; + } + 100% { + top: 0; + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } +} +@-webkit-keyframes scroll-down-effect { + 0% { + top: 0; + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } + 50% { + top: -16px; + opacity: 0.4; + -webkit-opacity: 0.4; + -moz-opacity: 0.4; + } + 100% { + top: 0; + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } +} +@-o-keyframes scroll-down-effect { + 0% { + top: 0; + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } + 50% { + top: -16px; + opacity: 0.4; + -webkit-opacity: 0.4; + -moz-opacity: 0.4; + } + 100% { + top: 0; + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } +} +@keyframes scroll-down-effect { + 0% { + top: 0; + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } + 50% { + top: -16px; + opacity: 0.4; + -webkit-opacity: 0.4; + -moz-opacity: 0.4; + } + 100% { + top: 0; + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } +} +.cover-wrapper .cover-body { + margin-top: 64px; + margin-bottom: 100px; +} +.cover-wrapper .cover-body, +.cover-wrapper .cover-body .top, +.cover-wrapper .cover-body .bottom { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + align-items: center; + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; + max-width: 100%; +} +.cover-wrapper .cover-body .bottom { + margin-top: 32px; +} +.cover-wrapper .cover-body .title { + font-family: HFSnakylines, "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Helvetica, monospace; + font-size: 3.125rem; + line-height: 1.2; + text-shadow: 0 1px 2px rgba(0,0,0,0.1); +} +.cover-wrapper .cover-body .subtitle { + font-size: 20px; +} +.cover-wrapper .cover-body .logo { + max-height: 120px; + max-width: calc(100% - 4 * 16px); +} +@media screen and (min-height: 1024px) { + .cover-wrapper .cover-body .title { + font-size: 3rem; + } + .cover-wrapper .cover-body .subtitle { + font-size: 1.05rem; + } + .cover-wrapper .cover-body .logo { + max-height: 150px; + } +} +.cover-wrapper .cover-body .m_search { + position: relative; + max-width: calc(100% - 16px); + width: 320px; + vertical-align: middle; +} +.cover-wrapper .cover-body .m_search .form { + position: relative; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + width: 100%; +} +.cover-wrapper .cover-body .m_search .icon, +.cover-wrapper .cover-body .m_search .input { + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +.cover-wrapper .cover-body .m_search .icon { + position: absolute; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + line-height: 2.5rem; + width: 32px; + top: 0; + left: 5px; + color: rgba(68,68,68,0.75); +} +.cover-wrapper .cover-body .m_search .input { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + height: 2.5rem; + width: 100%; + box-shadow: none; + -webkit-box-shadow: none; + box-sizing: border-box; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + font-size: 0.875rem; + -webkit-appearance: none; + padding-left: 36px; + border-radius: 1.4rem; + -webkit-border-radius: 1.4rem; + background: rgba(255,255,255,0.6); + backdrop-filter: blur(10px); + border: none; + color: var(--color-text); +} +@media screen and (max-width: 500px) { + .cover-wrapper .cover-body .m_search .input { + padding-left: 36px; + } +} +.cover-wrapper .cover-body .m_search .input:hover { + background: rgba(255,255,255,0.8); +} +.cover-wrapper .cover-body .m_search .input:focus { + background: #fff; +} +.cover-wrapper .list-h { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: horizontal; + -moz-box-orient: horizontal; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + align-items: stretch; + border-radius: 4px; + -webkit-border-radius: 4px; + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} +.cover-wrapper .list-h a { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -webkit-flex: 1 0; + -ms-flex: 1 0; + flex: 1 0; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + font-weight: 600; +} +.cover-wrapper .list-h a img { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + border-radius: 2px; + -webkit-border-radius: 2px; + margin: 4px; + min-width: 40px; + max-width: 44px; +} +@media screen and (max-width: 768px) { + .cover-wrapper .list-h a img { + min-width: 36px; + max-width: 40px; + } +} +@media screen and (max-width: 500px) { + .cover-wrapper .list-h a img { + margin: 2px 4px; + min-width: 32px; + max-width: 36px; + } +} +@media screen and (max-width: 375px) { + .cover-wrapper .list-h a img { + min-width: 28px; + max-width: 32px; + } +} +.cover-wrapper { + max-width: 100%; +} +.cover-wrapper.search .bottom .menu { + margin-top: 16px; +} +.cover-wrapper.search .bottom .menu .list-h a { + white-space: nowrap; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: horizontal; + -moz-box-orient: horizontal; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + align-items: baseline; + padding: 2px; + margin: 4px; + color: var(--color-site-inner); + opacity: 0.75; + -webkit-opacity: 0.75; + -moz-opacity: 0.75; + text-shadow: 0 1px 2px rgba(0,0,0,0.05); + border-bottom: 2px solid transparent; +} +.cover-wrapper.search .bottom .menu .list-h a i { + margin-right: 4px; +} +.cover-wrapper.search .bottom .menu .list-h a p { + font-size: 0.9375rem; +} +.cover-wrapper.search .bottom .menu .list-h a:hover, +.cover-wrapper.search .bottom .menu .list-h a.active, +.cover-wrapper.search .bottom .menu .list-h a:active { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + border-bottom: 2px solid var(--color-site-inner); +} +.cover-wrapper.dock .menu, +.cover-wrapper.featured .menu, +.cover-wrapper.focus .menu { + border-radius: 6px; + -webkit-border-radius: 6px; +} +.cover-wrapper.dock .menu .list-h a, +.cover-wrapper.featured .menu .list-h a, +.cover-wrapper.focus .menu .list-h a { + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + align-items: center; + padding: 12px; + line-height: 24px; + border-radius: 4px; + -webkit-border-radius: 4px; + border-bottom: none; + text-align: center; + align-content: flex-end; + color: rgba(68,68,68,0.7); + font-size: 1.5rem; +} +@media screen and (max-width: 500px) { + .cover-wrapper.dock .menu .list-h a, + .cover-wrapper.featured .menu .list-h a, + .cover-wrapper.focus .menu .list-h a { + padding: 12px 8px; + } +} +.cover-wrapper.dock .menu .list-h a i, +.cover-wrapper.featured .menu .list-h a i, +.cover-wrapper.focus .menu .list-h a i { + margin: 8px; +} +.cover-wrapper.dock .menu .list-h a p, +.cover-wrapper.featured .menu .list-h a p, +.cover-wrapper.focus .menu .list-h a p { + font-size: 0.875rem; +} +.cover-wrapper.dock .menu .list-h a.active, +.cover-wrapper.featured .menu .list-h a.active, +.cover-wrapper.focus .menu .list-h a.active { + background: var(--color-card); + backdrop-filter: none; +} +.cover-wrapper.dock .menu .list-h a.active i, +.cover-wrapper.featured .menu .list-h a.active i, +.cover-wrapper.focus .menu .list-h a.active i, +.cover-wrapper.dock .menu .list-h a.active i+p, +.cover-wrapper.featured .menu .list-h a.active i+p, +.cover-wrapper.focus .menu .list-h a.active i+p { + color: #3dd9b6; +} +.cover-wrapper.dock .menu .list-h a.active img+p, +.cover-wrapper.featured .menu .list-h a.active img+p, +.cover-wrapper.focus .menu .list-h a.active img+p { + color: var(--color-text); +} +.cover-wrapper.dock .menu .list-h a:hover, +.cover-wrapper.featured .menu .list-h a:hover, +.cover-wrapper.focus .menu .list-h a:hover { + background: var(--color-card); +} +.cover-wrapper.dock .top { + margin-bottom: 48px; +} +.cover-wrapper.dock .menu { + background: rgba(255,255,255,0.5); + position: absolute; + bottom: 0; + max-width: 100%; +} +.cover-wrapper.dock .menu .list-h { + flex-wrap: nowrap; + -webkit-flex-wrap: nowrap; + -khtml-flex-wrap: nowrap; + -moz-flex-wrap: nowrap; + -o-flex-wrap: nowrap; + -ms-flex-wrap: nowrap; + margin: 4px; +} +.cover-wrapper.dock .menu .list-h a+a { + margin-left: 4px; +} +@media screen and (max-width: 500px) { + .cover-wrapper.dock .menu .list-h { + overflow-x: scroll; + } + .cover-wrapper.dock .menu .list-h::-webkit-scrollbar { + height: 0; + width: 0; + } + .cover-wrapper.dock .menu .list-h::-webkit-scrollbar-track-piece { + background: transparent; + } + .cover-wrapper.dock .menu .list-h::-webkit-scrollbar-thumb { + background: #3dd9b6; + cursor: pointer; + border-radius: 0; + -webkit-border-radius: 0; + } + .cover-wrapper.dock .menu .list-h::-webkit-scrollbar-thumb:hover { + background: #ff5722; + } +} +@supports (backdrop-filter: blur(20px)) { + .cover-wrapper.dock .menu { + background: rgba(255,255,255,0.5); + backdrop-filter: saturate(200%) blur(20px); + } +} +.cover-wrapper #parallax-window { + position: absolute; + width: 100%; + height: 100%; + background: transparent; +} +.parallax-mirror { + animation-delay: 0s; + animation-duration: 0.5s; + animation-fill-mode: forwards; + animation-timing-function: ease-out; + animation-name: fadeIn; +} +@-moz-keyframes fadeIn { + 0% { + opacity: 0; + -webkit-opacity: 0; + -moz-opacity: 0; + filter: blur(12px); + } + 100% { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } +} +@-webkit-keyframes fadeIn { + 0% { + opacity: 0; + -webkit-opacity: 0; + -moz-opacity: 0; + filter: blur(12px); + } + 100% { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } +} +@-o-keyframes fadeIn { + 0% { + opacity: 0; + -webkit-opacity: 0; + -moz-opacity: 0; + filter: blur(12px); + } + 100% { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } +} +@keyframes fadeIn { + 0% { + opacity: 0; + -webkit-opacity: 0; + -moz-opacity: 0; + filter: blur(12px); + } + 100% { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } +} +@media (prefers-color-scheme: dark) { + :root { + --color-mode: 'dark'; + } + :root:not([color-scheme]) { + --color-site-body: #121212; + --color-read-bkg: #1f1f1f; + --color-read-post: #262626; + --color-site-bg: #1f1f1f; + --color-site-inner: rgba(238,238,238,0.871); + --color-site-footer: rgba(170,170,170,0.871); + --color-card: #262626; + --color-text: rgba(238,238,238,0.871); + --color-block: #434343; + --color-codeblock: #1f1f1f; + --color-inlinecode: #d56d28; + --color-h1: rgba(255,255,255,0.871); + --color-h2: rgba(255,255,255,0.871); + --color-h3: rgba(255,255,255,0.6); + --color-h4: rgba(255,255,255,0.6); + --color-h5: rgba(255,255,255,0.6); + --color-h6: rgba(255,255,255,0.6); + --color-p: rgba(217,217,217,0.871); + --color-list: rgba(217,217,217,0.871); + --color-list-hl: #63e0c4; + --color-meta: rgba(191,191,191,0.871); + --color-link: rgba(191,191,191,0.871); + --color-copyright-bkg: #21252b; + } + :root:not([color-scheme]) img { + filter: brightness(70%) !important; + } + :root:not([color-scheme]) .blur { + background: rgba(31,31,31,0.9) !important; + } + :root:not([color-scheme]) .white-box.blur { + background: rgba(38,38,38,0.9) !important; + } + :root:not([color-scheme]) .nav-main .u-search-input { + background: var(--color-card) !important; + } + :root:not([color-scheme]) #l_main .article .prev-next>a { + background: var(--color-block) !important; + } + :root:not([color-scheme]) #l_main .article .prev-next>a:hover { + background: var(--color-site-bg) !important; + } + :root:not([color-scheme]) .article blockquote { + background: var(--color-block) !important; + } + :root:not([color-scheme]) .article-title a { + color: var(--color-h1) !important; + } + :root:not([color-scheme]) details>summary { + color: var(--color-p) !important; + background: var(--color-site-bg) !important; + } + :root:not([color-scheme]) details { + border: 1px solid var(--color-site-bg) !important; + background: var(--color-site-bg) !important; + } + :root:not([color-scheme]) #u-search .modal, + :root:not([color-scheme]) #u-search .modal-header, + :root:not([color-scheme]) #u-search .modal-body { + background: var(--color-card) !important; + } + :root:not([color-scheme]) #u-search .modal-body .modal-results .result:hover { + background: var(--color-block) !important; + } + :root:not([color-scheme]) .u-search-input:hover { + background: var(--color-block) !important; + } + :root:not([color-scheme]) .u-search-input:focus { + background: var(--color-site-body) !important; + } +} +[color-scheme='dark'] { + --color-site-body: #121212; + --color-read-bkg: #1f1f1f; + --color-read-post: #262626; + --color-site-bg: #1f1f1f; + --color-site-inner: rgba(238,238,238,0.871); + --color-site-footer: rgba(170,170,170,0.871); + --color-card: #262626; + --color-text: rgba(238,238,238,0.871); + --color-block: #434343; + --color-codeblock: #1f1f1f; + --color-inlinecode: #d56d28; + --color-h1: rgba(255,255,255,0.871); + --color-h2: rgba(255,255,255,0.871); + --color-h3: rgba(255,255,255,0.6); + --color-h4: rgba(255,255,255,0.6); + --color-h5: rgba(255,255,255,0.6); + --color-h6: rgba(255,255,255,0.6); + --color-p: rgba(217,217,217,0.871); + --color-list: rgba(217,217,217,0.871); + --color-list-hl: #63e0c4; + --color-meta: rgba(191,191,191,0.871); + --color-link: rgba(191,191,191,0.871); + --color-copyright-bkg: #21252b; +} +[color-scheme='dark'] img { + filter: brightness(70%) !important; +} +[color-scheme='dark'] .blur { + background: rgba(31,31,31,0.9) !important; +} +[color-scheme='dark'] .white-box.blur { + background: rgba(38,38,38,0.9) !important; +} +[color-scheme='dark'] .nav-main .u-search-input { + background: var(--color-card) !important; +} +[color-scheme='dark'] #l_main .article .prev-next>a { + background: var(--color-block) !important; +} +[color-scheme='dark'] #l_main .article .prev-next>a:hover { + background: var(--color-site-bg) !important; +} +[color-scheme='dark'] .article blockquote { + background: var(--color-block) !important; +} +[color-scheme='dark'] .article-title a { + color: var(--color-h1) !important; +} +[color-scheme='dark'] details>summary { + color: var(--color-p) !important; + background: var(--color-site-bg) !important; +} +[color-scheme='dark'] details { + border: 1px solid var(--color-site-bg) !important; + background: var(--color-site-bg) !important; +} +[color-scheme='dark'] #u-search .modal, +[color-scheme='dark'] #u-search .modal-header, +[color-scheme='dark'] #u-search .modal-body { + background: var(--color-card) !important; +} +[color-scheme='dark'] #u-search .modal-body .modal-results .result:hover { + background: var(--color-block) !important; +} +[color-scheme='dark'] .u-search-input:hover { + background: var(--color-block) !important; +} +[color-scheme='dark'] .u-search-input:focus { + background: var(--color-site-body) !important; +} +@media screen and (max-width: 500px) { + [color-scheme='dark'] .l_header .m_search { + background: var(--color-site-bg) !important; + } +} +@font-face { + font-family: 'HYJiangJunJ'; + src: url("https://justpureh2o.cn/fonts/HYJiangJun-J.ttf"); + font-weight: 'normal'; + font-style: 'normal'; + font-display: swap; +} +@font-face { + font-family: 'HFSnakylines'; + src: url("https://justpureh2o.cn/fonts/HFSnakylines.ttf"); + font-weight: 'normal'; + font-style: 'normal'; + font-display: swap; +} +.l_header { + position: fixed; + z-index: 1000; + top: 0; + width: 100%; + height: 64px; + background: var(--color-card); + box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); +} +.l_header.auto { + transition: opacity 0.4s ease; + -webkit-transition: opacity 0.4s ease; + -khtml-transition: opacity 0.4s ease; + -moz-transition: opacity 0.4s ease; + -o-transition: opacity 0.4s ease; + -ms-transition: opacity 0.4s ease; + visibility: hidden; +} +.l_header.auto.show { + opacity: 1 !important; + -webkit-opacity: 1 !important; + -moz-opacity: 1 !important; + visibility: visible; +} +.l_header .container { + margin-left: 16px; + margin-right: 16px; +} +.l_header #wrapper { + height: 100%; + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} +.l_header #wrapper .nav-main, +.l_header #wrapper .nav-sub { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + flex-wrap: nowrap; + -webkit-flex-wrap: nowrap; + -khtml-flex-wrap: nowrap; + -moz-flex-wrap: nowrap; + -o-flex-wrap: nowrap; + -ms-flex-wrap: nowrap; + justify-content: space-between; + -webkit-justify-content: space-between; + -khtml-justify-content: space-between; + -moz-justify-content: space-between; + -o-justify-content: space-between; + -ms-justify-content: space-between; + align-items: center; +} +.l_header #wrapper .nav-main { + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +.l_header #wrapper.sub .nav-main { + transform: translateY(-64px); + -webkit-transform: translateY(-64px); + -khtml-transform: translateY(-64px); + -moz-transform: translateY(-64px); + -o-transform: translateY(-64px); + -ms-transform: translateY(-64px); +} +.l_header #wrapper .nav-sub { + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + opacity: 0; + -webkit-opacity: 0; + -moz-opacity: 0; + height: 64px; + width: calc(100% - 2 * 16px); + position: absolute; +} +.l_header #wrapper .nav-sub ::-webkit-scrollbar { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; +} +@media screen and (min-width: 2048px) { + .l_header #wrapper .nav-sub { + max-width: 55vw; + margin: auto; + } +} +.l_header #wrapper.sub .nav-sub { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; +} +.l_header #wrapper .title { + position: relative; + color: var(--color-text); + padding-left: 24px; + max-height: 64px; +} +.l_header #wrapper .nav-main .title { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex-shrink: 0; + line-height: 64px; + padding: 0 24px; + font-size: 1.25rem; + font-family: HFSnakylines, "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Helvetica, monospace; +} +.l_header #wrapper .nav-main .title img { + height: 64px; +} +.l_header .nav-sub { + max-width: 1080px; + margin: auto; +} +.l_header .nav-sub .title { + font-weight: bold; + font-family: HYJiangJunJ, "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Menlo, Monaco, monospace, sans-serif; + line-height: 1.2; + max-height: 64px; + white-space: normal; + flex-shrink: 1; +} +.l_header .switcher { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; + line-height: 64px; + align-items: center; +} +.l_header .switcher .s-toc { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; +} +@media screen and (max-width: 768px) { + .l_header .switcher .s-toc { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + } +} +.l_header .switcher >li { + height: 48px; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + margin: 2px; +} +@media screen and (max-width: 500px) { + .l_header .switcher >li { + margin: 0 1px; + height: 48px; + } +} +.l_header .switcher >li >a { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; + align-items: center; + width: 48px; + height: 48px; + padding: 0.85em 1.1em; + border-radius: 100px; + -webkit-border-radius: 100px; + border: none; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + color: #3dd9b6; +} +.l_header .switcher >li >a:hover { + border: none; +} +.l_header .switcher >li >a.active, +.l_header .switcher >li >a:active { + border: none; + background: var(--color-site-bg); +} +@media screen and (max-width: 500px) { + .l_header .switcher >li >a { + width: 36px; + height: 48px; + } +} +.l_header .nav-sub .switcher { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; +} +.l_header .m_search { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + height: 64px; + width: 240px; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +@media screen and (max-width: 1024px) { + .l_header .m_search { + width: 44px; + min-width: 44px; + } + .l_header .m_search input::placeholder { + opacity: 0; + -webkit-opacity: 0; + -moz-opacity: 0; + } + .l_header .m_search:hover { + width: 240px; + } + .l_header .m_search:hover input::placeholder { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } +} +@media screen and (min-width: 500px) { + .l_header .m_search:hover .input { + width: 100%; + } + .l_header .m_search:hover .input::placeholder { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } +} +@media screen and (max-width: 500px) { + .l_header .m_search { + min-width: 0; + } + .l_header .m_search input::placeholder { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + } +} +.l_header .m_search .form { + position: relative; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + width: 100%; + align-items: center; +} +.l_header .m_search .icon { + position: absolute; + width: 36px; + left: 5px; + color: var(--color-meta); +} +@media screen and (max-width: 500px) { + .l_header .m_search .icon { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; + } +} +.l_header .m_search .input { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + padding-top: 8px; + padding-bottom: 8px; + line-height: 1.3; + width: 100%; + color: var(--color-text); + background: #fafafa; + box-shadow: none; + -webkit-box-shadow: none; + box-sizing: border-box; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + padding-left: 40px; + font-size: 0.875rem; + border-radius: 8px; + -webkit-border-radius: 8px; + border: none; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +@media screen and (min-width: 500px) { + .l_header .m_search .input:focus { + box-shadow: 0 4px 8px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 4px 8px 0px rgba(0,0,0,0.1); + } +} +@media screen and (max-width: 500px) { + .l_header .m_search .input { + background: var(--color-block); + padding-left: 8px; + border: none; + } + .l_header .m_search .input:hover, + .l_header .m_search .input:focus { + border: none; + } +} +@media (max-width: 500px) { + .l_header .m_search { + left: 0; + width: 0; + overflow: hidden; + position: absolute; + background: #fff; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + } + .l_header .m_search .input { + border-radius: 32px; + -webkit-border-radius: 32px; + margin-left: 16px; + padding-left: 16px; + } + .l_header.z_search-open .m_search { + width: 100%; + } + .l_header.z_search-open .m_search .input { + width: calc(100% - 120px); + } +} +ul.m-pc >li>a { + color: inherit; + border-bottom: 2px solid transparent; +} +ul.m-pc >li>a:active, +ul.m-pc >li>a.active { + border-bottom: 2px solid #3dd9b6; +} +ul.m-pc li:hover >ul.list-v, +ul.list-v li:hover >ul.list-v { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; +} +ul.nav-list-h { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + align-items: stretch; +} +ul.nav-list-h>li { + position: relative; + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; + height: 100%; + line-height: 2.4; + border-radius: 4px; + -webkit-border-radius: 4px; +} +ul.nav-list-h>li >a { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + font-weight: 600; +} +ul.list-v { + z-index: 1; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; + position: absolute; + background: var(--color-card); + box-shadow: 0 2px 4px 0px rgba(0,0,0,0.08), 0 4px 8px 0px rgba(0,0,0,0.08), 0 8px 16px 0px rgba(0,0,0,0.08); + -webkit-box-shadow: 0 2px 4px 0px rgba(0,0,0,0.08), 0 4px 8px 0px rgba(0,0,0,0.08), 0 8px 16px 0px rgba(0,0,0,0.08); + margin-top: -6px; + border-radius: 4px; + -webkit-border-radius: 4px; + padding: 8px 0; +} +ul.list-v.show { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; +} +ul.list-v hr { + margin-top: 8px; + margin-bottom: 8px; +} +ul.list-v >li { + white-space: nowrap; + word-break: keep-all; +} +ul.list-v >li.header { + font-size: 0.78125rem; + font-weight: bold; + line-height: 2em; + color: var(--color-meta); + margin: 8px 16px 4px; +} +ul.list-v >li.header i { + margin-right: 8px; +} +ul.list-v >li ul { + margin-left: 0; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; + margin-top: -40px; +} +ul.list-v .aplayer-container { + min-height: 64px; + padding: 6px 16px; +} +ul.list-v >li>a { + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + color: var(--color-list); + font-size: 0.875rem; + font-weight: bold; + line-height: 36px; + padding: 0 20px 0 16px; + text-overflow: ellipsis; + margin: 0 4px; + border-radius: 4px; + -webkit-border-radius: 4px; +} +@media screen and (max-width: 1024px) { + ul.list-v >li>a { + line-height: 40px; + } +} +ul.list-v >li>a >i { + margin-right: 8px; +} +ul.list-v >li>a:active, +ul.list-v >li>a.active { + color: var(--color-list-hl); +} +ul.list-v >li>a:hover { + color: var(--color-list-hl); + background: var(--color-site-bg); +} +.l_header .menu >ul>li>a { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + padding: 0 8px; +} +.l_header .menu >ul>li>a >i { + margin-right: 4px; +} +.l_header ul.nav-list-h>li { + color: var(--color-list); + line-height: 64px; +} +.l_header ul.nav-list-h>li >a { + max-height: 64px; + overflow: hidden; + color: inherit; +} +.l_header ul.nav-list-h>li >a:active, +.l_header ul.nav-list-h>li >a.active { + color: #3dd9b6; +} +.l_header ul.nav-list-h>li:hover>a { + color: var(--color-list-hl); +} +.l_header ul.nav-list-h>li i.music { + animation: rotate-effect 1.5s linear infinite; + -webkit-animation: rotate-effect 1.5s linear infinite; + -khtml-animation: rotate-effect 1.5s linear infinite; + -moz-animation: rotate-effect 1.5s linear infinite; + -o-animation: rotate-effect 1.5s linear infinite; + -ms-animation: rotate-effect 1.5s linear infinite; +} +@-moz-keyframes rotate-effect { + 0% { + transform: rotate(0); + -webkit-transform: rotate(0); + -khtml-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + } + 25% { + transform: rotate(90deg); + -webkit-transform: rotate(90deg); + -khtml-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -o-transform: rotate(90deg); + -ms-transform: rotate(90deg); + } + 50% { + transform: rotate(180deg); + -webkit-transform: rotate(180deg); + -khtml-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -o-transform: rotate(180deg); + -ms-transform: rotate(180deg); + } + 75% { + transform: rotate(270deg); + -webkit-transform: rotate(270deg); + -khtml-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -o-transform: rotate(270deg); + -ms-transform: rotate(270deg); + } + 100% { + transform: rotate(360deg); + -webkit-transform: rotate(360deg); + -khtml-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + } +} +@-webkit-keyframes rotate-effect { + 0% { + transform: rotate(0); + -webkit-transform: rotate(0); + -khtml-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + } + 25% { + transform: rotate(90deg); + -webkit-transform: rotate(90deg); + -khtml-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -o-transform: rotate(90deg); + -ms-transform: rotate(90deg); + } + 50% { + transform: rotate(180deg); + -webkit-transform: rotate(180deg); + -khtml-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -o-transform: rotate(180deg); + -ms-transform: rotate(180deg); + } + 75% { + transform: rotate(270deg); + -webkit-transform: rotate(270deg); + -khtml-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -o-transform: rotate(270deg); + -ms-transform: rotate(270deg); + } + 100% { + transform: rotate(360deg); + -webkit-transform: rotate(360deg); + -khtml-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + } +} +@-o-keyframes rotate-effect { + 0% { + transform: rotate(0); + -webkit-transform: rotate(0); + -khtml-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + } + 25% { + transform: rotate(90deg); + -webkit-transform: rotate(90deg); + -khtml-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -o-transform: rotate(90deg); + -ms-transform: rotate(90deg); + } + 50% { + transform: rotate(180deg); + -webkit-transform: rotate(180deg); + -khtml-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -o-transform: rotate(180deg); + -ms-transform: rotate(180deg); + } + 75% { + transform: rotate(270deg); + -webkit-transform: rotate(270deg); + -khtml-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -o-transform: rotate(270deg); + -ms-transform: rotate(270deg); + } + 100% { + transform: rotate(360deg); + -webkit-transform: rotate(360deg); + -khtml-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + } +} +@keyframes rotate-effect { + 0% { + transform: rotate(0); + -webkit-transform: rotate(0); + -khtml-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + } + 25% { + transform: rotate(90deg); + -webkit-transform: rotate(90deg); + -khtml-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -o-transform: rotate(90deg); + -ms-transform: rotate(90deg); + } + 50% { + transform: rotate(180deg); + -webkit-transform: rotate(180deg); + -khtml-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -o-transform: rotate(180deg); + -ms-transform: rotate(180deg); + } + 75% { + transform: rotate(270deg); + -webkit-transform: rotate(270deg); + -khtml-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -o-transform: rotate(270deg); + -ms-transform: rotate(270deg); + } + 100% { + transform: rotate(360deg); + -webkit-transform: rotate(360deg); + -khtml-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + } +} +.menu-phone li ul.list-v { + right: calc(100% - 0.5 * 16px); +} +.menu-phone li ul.list-v ul { + right: calc(100% - 0.5 * 16px); +} +#wrapper { + max-width: 1080px; + margin: auto; +} +@media screen and (min-width: 2048px) { + #wrapper { + max-width: 55vw; + } +} +#wrapper .menu { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -webkit-flex: 1 1; + -ms-flex: 1 1; + flex: 1 1; + margin: 0 16px 0 0; +} +#wrapper .menu .list-v ul { + left: calc(100% - 0.5 * 16px); +} +.menu-phone { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; + margin-top: 16px; + right: 8px; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +.menu-phone ul { + right: calc(100% - 0.5 * 16px); +} +@media screen and (max-width: 500px) { + .menu-phone { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + } +} +.l_header { + max-width: 65vw; + left: calc((100% - 65vw) * 0.5); + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; +} +@media screen and (max-width: 2048px) { + .l_header { + max-width: 1112px; + left: calc((100% - 1112px) * 0.5); + } +} +@media screen and (max-width: 1112px) { + .l_header { + left: 0; + border-radius: 0; + -webkit-border-radius: 0; + max-width: 100%; + } +} +@media screen and (max-width: 500px) { + .l_header .container { + margin-left: 0; + margin-right: 0; + } + .l_header #wrapper .nav-main .title { + padding-left: 16px; + padding-right: 16px; + } + .l_header #wrapper .nav-sub { + width: 100%; + } + .l_header #wrapper .nav-sub .title { + overflow-y: scroll; + margin-top: 2px; + padding: 8px 16px; + } + .l_header #wrapper .switcher { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + margin-right: 8px; + } + .l_header .menu { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; + } +} +@media screen and (max-width: 500px) { + .list-v li { + max-width: 270px; + } +} +#u-search { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + padding: 60px 20px; + z-index: 1001; +} +@media screen and (max-width: 680px) { + #u-search { + padding: 0px; + } +} +@media screen and (prefers-color-scheme: dark) and (max-width: 500px) { + .l_header .m_search { + background: var(--color-site-bg) !important; + } +} diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000000..e77cae5b2f --- /dev/null +++ b/css/style.css @@ -0,0 +1,7823 @@ +#safearea { + display: block; +} +:root { + --block-hover: #ededed; + --text-p1: #222; + --text-p3: #777; + --card: #fff; +} +::-moz-selection { + background: rgba(33,150,243,0.2); +} +::selection { + background: rgba(33,150,243,0.2); +} +h1 { + font-size: 1.5rem; +} +h2 { + font-size: 1.5rem; +} +h3 { + font-size: 1.25rem; +} +h4 { + font-size: 1.125rem; +} +h5 { + font-size: 1rem; +} +h6 { + font-size: 1rem; +} +h1, +h2, +h3, +h4, +h6 { + font-weight: normal; +} +a:not([href]) { + cursor: default; +} +pre { + tab-size: 4; + -moz-tab-size: 4; + -o-tab-size: 4; + -webkit-tab-size: 4; +} +.clearfix { + zoom: 1; +} +.clearfix:before, +.clearfix:after { + content: " "; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: table; +} +.clearfix:after { + clear: both; +} +.hidden { + text-indent: -9999px; + visibility: hidden; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; +} +.inner { + position: relative; + width: 80%; + max-width: 710px; + margin: 0 auto; +} +.vertical { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: table-cell; + vertical-align: middle; +} +article, +aside, +details, +figcaption, +figure, +footer, +hgroup, +main, +menu, +nav, +section, +summary { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; +} +article { + overflow: hidden; +} +abbr[title] { + border-bottom: 1px dotted; +} +b, +strong { + font-weight: bold; +} +dfn { + font-style: italic; +} +h1 { + font-size: 2em; + margin: 0.67em 0; +} +mark { + background: #ff0; + color: #000; +} +small { + font-size: 80%; +} +sub, +sup { + font-size: 50%; + line-height: 1em; +} +sup { + vertical-align: text-top; +} +sub { + vertical-align: text-bottom; +} +figure { + margin: 1em 40px; +} +pre { + overflow: auto; +} +span.dot, +span.sep { + font-size: 0.9em; + margin: 0 0.2rem; +} +span.dot:before { + content: '·'; +} +span.sep:before { + content: '/'; +} +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} +optgroup, +select, +textarea { + color: inherit /* 1 */; + font: inherit /* 2 */; + margin: 0 /* 3 */; +} +select { + text-transform: none; +} +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button /* 2 */; + cursor: pointer /* 3 */; +} +button[disabled], +html input[disabled] { + cursor: default; +} +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box /* 1 */; + -webkit-box-sizing: border-box /* 1 */; + -moz-box-sizing: border-box /* 1 */; + padding: 0 /* 2 */; +} +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} +input[type="search"] { + -webkit-appearance: textfield /* 1 */; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box /* 2 */; + box-sizing: content-box; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; +} +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} +legend { + border: 0 /* 1 */; + padding: 0 /* 2 */; +} +textarea { + overflow: auto; +} +optgroup { + font-weight: bold; +} +table:not([class]) { + border-collapse: collapse; + overflow: auto; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; + max-width: 100%; + vertical-align: text-top; +} +table:not([class]) th { + background-color: #f1f1f1; +} +table:not([class]) td, +table:not([class]) th { + padding: 8px 16px; + border: 2px solid #f1f1f1; + line-height: 1.5; + font-size: 90%; +} +table:not([class]) tr { + word-break: keep-all; + background-color: #fefefe; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +table:not([class]) tr:hover { + background-color: #f1f1f1; +} +td, +th { + padding: 0; +} +@font-face { + font-family: 'JetbrainsMono'; + src: url("https://justpureh2o.cn/fonts/JetBrainsMono.ttf"); + font-weight: 'normal'; + font-style: 'normal'; + font-display: swap; +} +article#arc, +article#cat, +article#tag { + padding-top: 48px; + padding-bottom: 48px; +} +article#arc h2, +article#cat h2, +article#tag h2 { + font-weight: 600; +} +article#arc h2:first-child, +article#cat h2:first-child, +article#tag h2:first-child { + margin-top: 0; +} +article#arc { + margin-bottom: 32px; + padding-bottom: 64px; +} +article#arc .timenode:before, +article#arc .timenode:after { + margin-left: 12px; +} +article#arc .timenode .meta { + padding: 6px 0; + line-height: 1.5; + height: auto; + max-width: 100%; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + font-size: 0.9375rem; + font-weight: 500; + border-radius: 2px; + -webkit-border-radius: 2px; + color: var(--color-list); +} +article#arc .timenode .meta:before { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; +} +article#arc .timenode .meta:after { + margin-left: 14px; +} +article#arc .timenode .meta:hover { + color: var(--color-p); + background: var(--color-site-bg); +} +article#arc .timenode .meta time { + color: var(--color-meta); + margin-left: 34px; + margin-right: 4px; + flex-shrink: 0; + width: 60px; +} +article#arc .timenode .meta i { + line-height: 1.5; + color: #ff5722; +} +article#arc .timenode .meta i.red { + color: #fe5f58; +} +article#arc .timenode .meta i.green { + color: #3dc550; +} +article#arc .timenode .meta i.yellow { + color: #ffbd2b; +} +article#arc .timenode .meta i.blue { + color: #1bcdfc; +} +article#arc .timenode .meta i.theme { + color: #3dd9b6; +} +article#arc .timenode .meta i.accent { + color: #ff5722; +} +article#arc .timenode .meta i.orange { + color: #ff5722; +} +article#cat .all-cats a { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + padding: 8px 16px; + border-radius: 4px; + -webkit-border-radius: 4px; + color: var(--color-list); + font-size: 0.9375rem; + font-weight: 500; +} +article#cat .all-cats a:hover { + color: var(--color-list-hl); + background: var(--color-site-bg); +} +article#cat .all-cats a.child { + padding-left: 48px; +} +article#tag .all-tags { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + align-items: flex-start; + justify-content: flex-start; + -webkit-justify-content: flex-start; + -khtml-justify-content: flex-start; + -moz-justify-content: flex-start; + -o-justify-content: flex-start; + -ms-justify-content: flex-start; + align-items: baseline; + text-align: center; +} +article#tag .all-tags ul { + margin: 0 -8px; + padding: 0; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; +} +article#tag .all-tags ul li { + list-style: none; + margin: 8px; + border-radius: 4px; + -webkit-border-radius: 4px; + overflow: hidden; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + position: relative; + font-size: 0.9375rem; +} +article#tag .all-tags ul li a { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; + color: var(--color-list); + padding: 4px 52px 4px 16px; + background: var(--color-block); + font-weight: 500; +} +article#tag .all-tags ul li a:hover { + background: #ff5722; + color: #fff; +} +article#tag .all-tags ul li span { + color: var(--color-meta); + background: var(--color-card); + padding: 2px 8px; + border-radius: 2px; + -webkit-border-radius: 2px; + pointer-events: none; + position: absolute; + right: 2px; + top: 2px; + height: calc(100% - 4px); +} +article#tag .all-tags ul li span:before { + content: 'x'; +} +.article { + color: var(--color-p); + word-wrap: break-word; +} +.article a { + word-break: break-word; +} +.article h1.title, +.article h2.title { + left: 0; +} +.article h1.title:before, +.article h2.title:before { + content: none; +} +.article h1, +.article h2 { + padding-bottom: 0.2rem; + margin-bottom: 1rem; + border-bottom: 1px solid rgba(68,68,68,0.1); +} +.article h1 { + text-align: left; + color: var(--color-h1); + margin-top: 48px; +} +.article h2 { + text-align: left; + color: var(--color-h2); + margin-top: 48px; +} +.article h3 { + text-align: left; + color: var(--color-h3); + margin-top: 24px; +} +.article h4 { + text-align: left; + color: var(--color-h4); + margin-top: 16px; +} +.article h5 { + font-weight: bold; + color: var(--color-h5); + margin-top: 1em; +} +.article h6 { + color: var(--color-h6); + margin-top: 1em; +} +.article center, +.article center p { + text-align: center; +} +.article .aplayer { + margin: 1em 0; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; + width: 400px; + max-width: 100%; + border-radius: 4px; + -webkit-border-radius: 4px; + color: #666; +} +.article p.small-img img, +.article div.small-img img { + width: auto; + max-width: 100%; + margin: 0; + box-shadow: none; + -webkit-box-shadow: none; +} +.article s { + color: #8e8e8e; + text-decoration-color: #8e8e8e; +} +.article p { + margin-top: 1em; + margin-bottom: 1em; + text-align: justify; + max-width: 100%; + line-height: inherit; +} +.article .subtitle h6 { + color: rgba(68,68,68,0.9); +} +.article figure figcaption span { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; + margin-right: 5px; +} +.article blockquote { + background: var(--color-block); + border-left: 4px solid #3dd9b6; + border-radius: 4px; + -webkit-border-radius: 4px; +} +.article blockquote { + position: relative; + width: 100%; + padding: 16px; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +.article blockquote, +.article blockquote p, +.article blockquote ul, +.article blockquote ol { + text-align: left; + word-wrap: normal; + font-size: 0.9375rem; + margin-top: 0.5em; + margin-bottom: 0.5em; +} +.article blockquote footer { + padding: 0; + text-align: justify; + color: inherit; + font-style: italic; + margin: 1em 0; +} +.article blockquote footer cite { + color: var(--color-meta); + margin-left: 1em; +} +.article blockquote footer cite::before { + content: '----'; + padding: 0 0.3em; +} +.article blockquote.pullquote.right { + border-left: none; + border-right: 4px solid #3dd9b6; +} +.article blockquote.pullquote.right p { + text-align: right; +} +.article pre { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + margin-top: 1em; + margin-bottom: 1em; + overflow: auto; + background: var(--color-codeblock); + font-size: 0.8125rem; + font-family: JetbrainsMono, "PingFang SC", "Microsoft YaHei", Helvetica, Arial, monospace, courier, sans-serif; + border: 1px solid #ffebcb; + padding: 16px; + border-radius: 4px; + -webkit-border-radius: 4px; +} +.article pre >code:not([class]) { + background: transparent; +} +.article div>pre { + border-radius: 4px; + -webkit-border-radius: 4px; +} +.article div>pre>code:not([class]) { + padding: 0; + margin: 0; + background: transparent; + color: rgba(68,68,68,0.9); +} +.article code { + font-family: JetbrainsMono, "PingFang SC", "Microsoft YaHei", Helvetica, Arial, monospace, courier, sans-serif; +} +.article code:not([class]) { + word-break: break-all; + color: var(--color-inlinecode); + border-radius: 2px; + -webkit-border-radius: 2px; +} +@media screen and (max-width: 500px) { + .article ul, + .article ol { + font-size: 0.875rem; + } + .article figure { + font-size: 13px; + line-height: 1.5; + } +} +.article .widget { + background: transparent; + margin: 1em 0; + box-shadow: none; + -webkit-box-shadow: none; + border-radius: 4px; + -webkit-border-radius: 4px; + cursor: auto; + background: var(--color-block); + padding: 8px 0; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + width: 100%; +} +.article .widget:hover { + box-shadow: none; + -webkit-box-shadow: none; +} +.article .widget:active { + box-shadow: none; + -webkit-box-shadow: none; +} +.article .widget header { + padding: 4px 0.6em; + padding-bottom: 0; +} +.article .widget header, +.article .widget header a { + color: rgba(68,68,68,0.85); +} +.article .widget.copyright, +.article .widget.qrcode { + background: none; + padding: 0; +} +.article .widget.copyright header, +.article .widget.qrcode header { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; +} +.article .widget.copyright .content, +.article .widget.qrcode .content { + padding: 0; +} +.article .widget.list .content, +.article .widget.related_posts .content { + padding: 0 0.6em !important; +} +.article .widget.list .content a, +.article .widget.related_posts .content a { + color: #2092ec; +} +.article .widget.list .content a:hover, +.article .widget.related_posts .content a:hover { + color: #ff5722; +} +.article .widget .content { + padding: 0 0.6em; + margin: 0; +} +.article .widget .content ul { + padding-left: 4px; + margin-left: 16px; +} +.article .widget .content ul a { + transition: all 0.1s ease; + -webkit-transition: all 0.1s ease; + -khtml-transition: all 0.1s ease; + -moz-transition: all 0.1s ease; + -o-transition: all 0.1s ease; + -ms-transition: all 0.1s ease; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline; + border-left: none; + padding: 0; + padding-left: 4px; + color: #2092ec; + font-weight: normal; + text-decoration: none; +} +.article .widget .content ul a:hover, +.article .widget .content ul a.active, +.article .widget .content ul a:active { + border-left: none !important; + background: none !important; +} +.article .widget .content ul a:hover { + color: #ff5722; +} +.article .widget .content .list a .name { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline; + color: #2092ec; +} +.article .widget .content .list a:hover .name { + color: #ff5722; +} +.article .widget.qrcode > .content { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + align-items: center; + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; + padding-left: 16px; + padding-right: 16px; + margin-bottom: 4px; +} +.article .widget.qrcode > .content>.fancybox, +.article .widget.qrcode > .content>img { + margin: 0 8px; +} +.article .widget.qrcode > .content img { + margin-bottom: 4px; +} +.article .article_footer { + margin-top: 64px; +} +.article .widget-blur { + backdrop-filter: none; +} +.md .footer { + margin-top: 64px; +} +.md .footer >div { + margin-top: 1em; + margin-bottom: 1em; +} +.md .footer .header { + line-height: 1.75; + padding-bottom: 8px; + font-weight: 500; + font-size: 0.875rem; + color: var(--color-list); +} +.md .footer .header i { + margin-right: 2px; +} +.md .footer .body ul, +.md .footer .body ol { + margin-top: 0; + margin-bottom: 0; +} +.md .footer .references, +.md .footer .related_posts { + background: var(--color-block); + border-radius: 4px; + -webkit-border-radius: 4px; + padding: 16px; +} +.md .footer .references .body a { + font-size: 0.9375rem; + font-weight: 500; +} +.md .footer .related_posts .body { + margin: 4px; + overflow: hidden; + border-radius: 2px; + -webkit-border-radius: 2px; +} +.md .footer .related_posts .body .vlts-rps { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; +} +.md .footer .related_posts .body .vlts-rps .item { + flex-shrink: 0; + width: 240px; +} +.md .footer .related_posts .body .vlts-rps .item+.item { + margin-left: 16px; +} +.md .footer .related_posts .body .vlts-rps .item:hover img { + filter: ; +} +.md .footer .related_posts .body .vlts-rps img { + border-radius: 2px; + -webkit-border-radius: 2px; + width: 100%; + height: 120px; + object-fit: cover; + filter: ; +} +.md .footer .related_posts .body .vlts-rps span { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + text-align: justify; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; +} +.md .footer .related_posts .body .vlts-rps .title { + font-weight: 600; + -webkit-line-clamp: 1; +} +.md .footer .related_posts .body .vlts-rps .excerpt { + font-size: 0.875rem; + color: var(--color-meta); + -webkit-line-clamp: 3; +} +.md .footer .copyright blockquote p { + font-size: 0.875rem; + margin: 0.25em 0; +} +.md .footer .copyright blockquote p a { + font-weight: 500; +} +.md .footer .donate { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + margin: 0 auto; +} +.md .footer .donate .imgs { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-inline-flexbox /* TWEENER - IE 10 */; + display: -webkit-inline-flex /* NEW - Chrome */; + display: inline-flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: inline-flex; + margin: 0 auto; +} +.md .footer .donate .imgs .fancybox { + margin: 8px; +} +.md .footer .donate .imgs img { + width: 80px; +} +article .readmore { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + margin-top: 24px; + font-size: 0.875rem; +} +.copyright.license { + background: var(--color-copyright-bkg); + color: var(--color-meta); + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + font-size: 0.95rem; + line-height: 1.2; + margin: 15px -40px; + overflow: hidden; + padding: 1.25em 40px; + position: relative; + border-radius: 4px; + -webkit-border-radius: 4px; +} +.copyright.license:after { + background: url("data:image/svg+xml;charset=utf-8,%3Csvg version='1.1' id='Capa_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 367.467 367.467' style='enable-background:new 0 0 367.467 367.467;' xml:space='preserve'%3E%3Cg%3E%3Cpath d='M183.73,0.018C82.427,0.018,0,82.404,0,183.733c0,101.289,82.427,183.716,183.73,183.716 c101.315,0,183.737-82.427,183.737-183.716C367.467,82.404,285.045,0.018,183.73,0.018z M183.73,326.518 c-78.743,0-142.798-64.052-142.798-142.784c0-78.766,64.055-142.817,142.798-142.817c78.752,0,142.807,64.052,142.807,142.817 C326.536,262.466,262.481,326.518,183.73,326.518z'/%3E%3Cpath d='M244.036,217.014c-11.737,20.141-33.562,32.635-56.956,32.635c-36.329,0-65.921-29.585-65.921-65.915 c0-36.36,29.592-65.955,65.921-65.955c23.395,0,45.219,12.54,56.956,32.641l1.517,2.627h44.28l-2.658-7.129 c-7.705-20.413-21.225-37.769-39.122-50.157c-17.942-12.42-39.017-19.009-60.973-19.009c-58.981,0-106.946,48.006-106.946,106.982 c0,58.98,47.965,106.941,106.946,106.941c21.956,0,43.03-6.567,60.973-19.006c17.897-12.391,31.417-29.741,39.122-50.154 l2.658-7.133h-44.28L244.036,217.014z'/%3E%3C/g%3E%3C/svg%3E"); + content: " "; + opacity: 0.1; + -webkit-opacity: 0.1; + -moz-opacity: 0.1; + height: 180px; + right: -10px; + top: -35px; + width: 180px; + position: absolute; +} +.copyright.license a { + color: var(--color-meta); +} +.copyright.license a:hover { + color: #ff5722; +} +.copyright.license .license-title, +.copyright.license .license-meta-title { + margin: 0 0 0.25rem; +} +.copyright.license .license-link, +.copyright.license .license-meta-title { + font-size: 0.8rem; +} +.copyright.license .license-title { + font-weight: 700; +} +.copyright.license .license-link { + margin-bottom: 1rem; +} +.copyright.license .license-meta { + align-items: center; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + justify-content: flex-start; + -webkit-justify-content: flex-start; + -khtml-justify-content: flex-start; + -moz-justify-content: flex-start; + -o-justify-content: flex-start; + -ms-justify-content: flex-start; +} +.copyright.license .license-meta-item { + margin: 0 2rem 1em 0; +} +.copyright.license .license-meta-text { + margin: 0; +} +.copyright.license .license-meta-text a { + border-bottom: 1px solid var(--color-meta); +} +.copyright.license .license-meta-text a:hover { + border-bottom-color: #ff5722; +} +.recommended-article { + overflow: hidden; +} +.recommended-article .recommended-article-header { + margin-top: 8px; + margin-left: 8px; + margin-right: 0; +} +.recommended-article .recommended-article-group { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + overflow: hidden; +} +@media screen and (max-width: 768px) { + .recommended-article .recommended-article-group { + height: 190px; + overflow: scroll; + -ms-overflow-style: none; + } + .recommended-article .recommended-article-group::-webkit-scrollbar { + width: 0 !important; + } +} +.recommended-article .recommended-article-group .recommended-article-item { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + align-content: center; + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; + align-items: center; + overflow: hidden; + width: calc(100%/3 - 16px); + max-height: 200px; + margin-top: 8px; + margin-left: 8px; + margin-right: 0; +} +@media screen and (max-width: 768px) { + .recommended-article .recommended-article-group .recommended-article-item { + width: calc(100%/2 - 16px); + } +} +@media screen and (max-width: 500px) { + .recommended-article .recommended-article-group .recommended-article-item { + width: calc(100% - 16px); + } +} +.recommended-article .recommended-article-group .recommended-article-item img { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + width: 100%; + height: 150px; +} +.recommended-article .recommended-article-group .recommended-article-item span { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + text-align: justify; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; + overflow: hidden; +} +footer.footer { + position: relative; + padding: 40px 10px 120px 10px; + width: 100%; + color: var(--color-site-footer); + margin: 0px auto; + overflow: hidden; + text-align: center; +} +footer.footer, +footer.footer p { + font-size: 0.8125rem; +} +footer.footer .licenses { + color: fade(, 50%); +} +footer.footer .social-wrapper { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + margin: 4px 8px; +} +footer.footer a { + color: var(--color-site-footer); + padding: 0; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +footer.footer a:hover { + color: #ff5722; +} +footer.footer a:not(.social):hover { + text-decoration: underline; +} +footer.footer a.social { + position: relative; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; + text-align: center; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; + align-items: center; + min-width: 36px; + min-height: 36px; + margin: 4px; + opacity: 0.75; + -webkit-opacity: 0.75; + -moz-opacity: 0.75; + border-radius: 4px; + -webkit-border-radius: 4px; + font-size: 1rem; +} +footer.footer a.social img { + margin: 8px; + height: 24px; +} +footer.footer a.social:hover { + color: #ff5722; + background: rgba(255,87,34,0.1); +} +footer.footer .copyright { + margin-top: 16px; +} +footer.footer .copyright p { + font-size: 0.78125rem; +} +@media screen and (max-width: 768px) { + footer.footer { + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; + } +} +.article.l_friends .friends-group .friend-content { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + margin: -8px; + border-radius: 8px; + -webkit-border-radius: 8px; + align-items: flex-start; + line-height: 1.3; +} +.article.l_friends .friends-group .friend-content .friend-card { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + padding: 8px 0; + margin: 8px; + margin-top: calc(2.25 * 16px + 32px); + color: var(--color-meta); + background: var(--color-block); + justify-content: flex-start; + -webkit-justify-content: flex-start; + -khtml-justify-content: flex-start; + -moz-justify-content: flex-start; + -o-justify-content: flex-start; + -ms-justify-content: flex-start; + align-content: flex-start; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + width: calc(100%/4 - 16px); +} +@media screen and (max-width: 1024px) { + .article.l_friends .friends-group .friend-content .friend-card { + width: calc(100%/4 - 16px); + } +} +@media screen and (max-width: 768px) { + .article.l_friends .friends-group .friend-content .friend-card { + width: calc(100%/3 - 16px); + } +} +@media screen and (max-width: 500px) { + .article.l_friends .friends-group .friend-content .friend-card { + width: calc(100%/2 - 16px); + } +} +.article.l_friends .friends-group .friend-content .friend-card:hover .friend-left .avatar { + transform: scale(1.2) rotate(12deg); + -webkit-transform: scale(1.2) rotate(12deg); + -khtml-transform: scale(1.2) rotate(12deg); + -moz-transform: scale(1.2) rotate(12deg); + -o-transform: scale(1.2) rotate(12deg); + -ms-transform: scale(1.2) rotate(12deg); + box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); +} +.article.l_friends .friends-group .friend-content .friend-card .friend-left { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + align-self: center; +} +.article.l_friends .friends-group .friend-content .friend-card .friend-left .avatar { + width: 64px; + height: 64px; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + margin: 16px 8px 4px 8px; + margin-top: calc(-1.25 * 16px - 32px); + border-radius: 100%; + -webkit-border-radius: 100%; + border: 2px solid #fff; + background: #fff; +} +.article.l_friends .friends-group .friend-content .friend-card .friend-right { + margin: 4px 8px; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + text-align: center; +} +.article.l_friends .friends-group .friend-content .friend-card .friend-right p { + text-align: center; +} +.article.l_friends .friends-group .friend-content .friend-card .friend-right .friend-tags-wrapper { + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + margin-left: -2px; + word-break: break-all; +} +.article.l_friends .friends-group .friend-content .friend-card .friend-right p { + margin: 0; +} +.article.l_friends .friends-group .friend-content .friend-card .friend-right p.friend-name { + font-size: 0.8125rem; + padding-top: 4px; + font-weight: bold; +} +.article.l_friends .friends-group .friend-content .friend-card .friend-right p.tags { + font-size: 0.78125rem; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline; + background: none; + word-wrap: break-word; + padding-right: 4px; +} +.md img { + position: relative; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +@media screen and (max-width: 500px) { + .md img { + box-shadow: none; + -webkit-box-shadow: none; + } +} +.md div>img, +.md p>img { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + margin: auto; + border-radius: 4px; + -webkit-border-radius: 4px; +} +@media screen and (max-width: 500px) { + .md div>img, + .md p>img { + border-radius: 2px; + -webkit-border-radius: 2px; + } +} +.md span img { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline; + margin: auto; +} +.md .img-wrap { + margin: 1.5rem auto; + text-align: center; + border-radius: 2px; + -webkit-border-radius: 2px; + overflow: hidden; +} +.md .img-wrap .img-bg { + width: 100%; +} +.md .img-wrap .image-caption { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + margin: 0.75rem auto; + font-size: 0.8125rem; + color: var(--color-meta); +} +.md .img-wrap .image-caption:empty { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; +} +svg.loading { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + position: absolute; + color: var(--text-p3); + width: 100%; + height: 2rem; + margin: auto; + animation: spin infinite 2s; + -webkit-animation: spin infinite 2s; + -khtml-animation: spin infinite 2s; + -moz-animation: spin infinite 2s; + -o-animation: spin infinite 2s; + -ms-animation: spin infinite 2s; + animation-timing-function: linear; +} +@-moz-keyframes spin { + from { + transform: rotate(0deg); + -webkit-transform: rotate(0deg); + -khtml-transform: rotate(0deg); + -moz-transform: rotate(0deg); + -o-transform: rotate(0deg); + -ms-transform: rotate(0deg); + } + to { + transform: rotate(360deg); + -webkit-transform: rotate(360deg); + -khtml-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + } +} +@-webkit-keyframes spin { + from { + transform: rotate(0deg); + -webkit-transform: rotate(0deg); + -khtml-transform: rotate(0deg); + -moz-transform: rotate(0deg); + -o-transform: rotate(0deg); + -ms-transform: rotate(0deg); + } + to { + transform: rotate(360deg); + -webkit-transform: rotate(360deg); + -khtml-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + } +} +@-o-keyframes spin { + from { + transform: rotate(0deg); + -webkit-transform: rotate(0deg); + -khtml-transform: rotate(0deg); + -moz-transform: rotate(0deg); + -o-transform: rotate(0deg); + -ms-transform: rotate(0deg); + } + to { + transform: rotate(360deg); + -webkit-transform: rotate(360deg); + -khtml-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + } +} +@keyframes spin { + from { + transform: rotate(0deg); + -webkit-transform: rotate(0deg); + -khtml-transform: rotate(0deg); + -moz-transform: rotate(0deg); + -o-transform: rotate(0deg); + -ms-transform: rotate(0deg); + } + to { + transform: rotate(360deg); + -webkit-transform: rotate(360deg); + -khtml-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + } +} +#safearea { + margin: 16px 16px 0; +} +#l_body { + position: relative; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +#l_body div.loading { + margin: 16px 0; + width: 100%; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; +} +#l_body div.loading, +#l_body div.loading p { + text-align: center; +} +#l_body #s-top { + transition: all 0.6s ease; + -webkit-transition: all 0.6s ease; + -khtml-transition: all 0.6s ease; + -moz-transition: all 0.6s ease; + -o-transition: all 0.6s ease; + -ms-transition: all 0.6s ease; + z-index: 50; + position: fixed; + width: 48px; + height: 48px; + line-height: 48px; + border-radius: 100%; + -webkit-border-radius: 100%; + bottom: 32px; + right: 32px; + transform: translateY(100px) scale(0); + -webkit-transform: translateY(100px) scale(0); + -khtml-transform: translateY(100px) scale(0); + -moz-transform: translateY(100px) scale(0); + -o-transform: translateY(100px) scale(0); + -ms-transform: translateY(100px) scale(0); + transform-origin: bottom; + -webkit-transform-origin: bottom; + -khtml-transform-origin: bottom; + -moz-transform-origin: bottom; + -o-transform-origin: bottom; + -ms-transform-origin: bottom; + color: var(--color-text); +} +@media screen and (max-width: 768px) { + #l_body #s-top { + right: 16px; + } +} +#l_body #s-top.show { + transform: translateY(0) scale(1); + -webkit-transform: translateY(0) scale(1); + -khtml-transform: translateY(0) scale(1); + -moz-transform: translateY(0) scale(1); + -o-transform: translateY(0) scale(1); + -ms-transform: translateY(0) scale(1); +} +#l_body #s-top.show.hl { + background: #3dd9b6; + color: #fff; + box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); +} +@media screen and (min-width: 768px) { + #l_body #s-top:hover { + transform: scale(1.2); + -webkit-transform: scale(1.2); + -khtml-transform: scale(1.2); + -moz-transform: scale(1.2); + -o-transform: scale(1.2); + -ms-transform: scale(1.2); + border-radius: 25%; + -webkit-border-radius: 25%; + background: #3dd9b6; + color: #fff; + box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); + } + #l_body #s-top:hover.hl { + box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); + } +} +#l_main { + width: calc(100% - 1 * 240px); + padding-right: 16px; + float: left; +} +@media screen and (max-width: 768px) { + #l_main { + width: 100%; + } +} +#l_main.no_sidebar { + width: 100%; + padding-right: 0; + max-width: 840px; + margin: auto; +} +@media screen and (min-width: 2048px) { + #l_main.no_sidebar { + max-width: calc(55vw - 240px); + } +} +#l_main.no_sidebar ~#l_side { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; +} +#l_main .post-list { + position: relative; + margin-bottom: 16px; + column-gap: 16px; + -webkit-column-gap: 16px; + -moz-column-gap: 16px; +} +#l_main .post-list.multiple-columns { + columns: 320px; +} +#l_main .post-wrapper { + column-break-inside: avoid; + break-inside: avoid-column; +} +#l_main .widget .content p, +#l_main .widget .content ul, +#l_main .widget .content ol, +#l_main .widget .content table, +#l_main .widget .content .tabs, +#l_main .widget .content details { + margin-top: 1em; + margin-bottom: 1em; +} +#l_main .widget .content .post { + padding-top: 0; + padding-bottom: 0; + margin-top: 1em; + margin-bottom: 1em; +} +#l_main .widget.grid .content .grid.fixed a { + width: calc(100%/8 - 0 * 16px); +} +@media screen and (max-width: 1024px) { + #l_main .widget.grid .content .grid.fixed a { + width: calc(100%/7 - 0 * 16px); + } +} +@media screen and (max-width: 768px) { + #l_main .widget.grid .content .grid.fixed a { + width: calc(100%/6 - 0 * 16px); + } +} +@media screen and (max-width: 500px) { + #l_main .widget.grid .content .grid.fixed a { + width: calc(100%/5 - 0 * 16px); + } +} +@media screen and (max-width: 425px) { + #l_main .widget.grid .content .grid.fixed a { + width: calc(100%/4 - 0 * 16px); + } +} +@media screen and (max-width: 375px) { + #l_main .widget.grid .content .grid.fixed a { + width: calc(100%/3 - 0 * 16px); + } +} +#l_main .post { + position: relative; + margin-bottom: 16px; + padding: 24px; + border-radius: 8px; + -webkit-border-radius: 8px; +} +#l_main .post h1.title { + font-size: 1.5rem; + margin: 0; + border-bottom: none; + padding-bottom: 4px; + border-bottom: none; +} +#l_main .post .article-meta { + color: var(--color-meta); + margin-bottom: 16px; + line-height: normal; +} +#l_main .post .article-meta#top { + margin-top: 16px; + margin-bottom: 32px; +} +#l_main .post .article-meta#bottom { + margin-top: 32px; + margin-bottom: 8px; +} +#l_main .post .article-meta .aplayer, +#l_main .post .article-meta .aplayer-pic, +#l_main .post .article-meta .thumbnail { + width: 48px; + height: 48px; +} +#l_main .post .article-meta .aplayer, +#l_main .post .article-meta .thumbnail { + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + border-radius: 100%; + -webkit-border-radius: 100%; + float: right; + margin: 2px; + box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); +} +#l_main .post .article-meta .aplayer:hover, +#l_main .post .article-meta .thumbnail:hover { + border-radius: 25%; + -webkit-border-radius: 25%; + transform: scale(1.1); + -webkit-transform: scale(1.1); + -khtml-transform: scale(1.1); + -moz-transform: scale(1.1); + -o-transform: scale(1.1); + -ms-transform: scale(1.1); + box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); +} +@media screen and (max-width: 500px) { + #l_main .post .article-meta .aplayer:hover, + #l_main .post .article-meta .thumbnail:hover { + border-radius: 100%; + -webkit-border-radius: 100%; + transform: scale(1); + -webkit-transform: scale(1); + -khtml-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + } +} +#l_main .post .article-meta .thumbnail { + width: auto; + border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: none; + -webkit-box-shadow: none; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +#l_main .post .article-meta .thumbnail:hover { + border-radius: 4px; + -webkit-border-radius: 4px; + transform: scale(1.1) rotate(4deg); + -webkit-transform: scale(1.1) rotate(4deg); + -khtml-transform: scale(1.1) rotate(4deg); + -moz-transform: scale(1.1) rotate(4deg); + -o-transform: scale(1.1) rotate(4deg); + -ms-transform: scale(1.1) rotate(4deg); + box-shadow: none; + -webkit-box-shadow: none; +} +#l_main .post .article-meta .new-meta-box { + transition: all 0.1s ease; + -webkit-transition: all 0.1s ease; + -khtml-transition: all 0.1s ease; + -moz-transition: all 0.1s ease; + -o-transition: all 0.1s ease; + -ms-transition: all 0.1s ease; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + align-items: center; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + -webkit-font-smoothing: auto; + -moz-osx-font-smoothing: auto; +} +#l_main .post .article-meta .new-meta-box, +#l_main .post .article-meta .new-meta-box p, +#l_main .post .article-meta .new-meta-box i { + font-size: 0.8125rem; +} +#l_main .post .article-meta .new-meta-box .new-meta-item { + color: var(--color-meta); + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + align-items: baseline; + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; + margin: 0 16px 0 0; + padding: 8px 0; +} +#l_main .post .article-meta .new-meta-box .new-meta-item .notlink { + cursor: default; +} +#l_main .post .article-meta .new-meta-box .new-meta-item .notlink:hover { + color: var(--color-meta); +} +#l_main .post .article-meta .new-meta-box .new-meta-item .notlink:hover p { + color: var(--color-meta); +} +#l_main .post .article-meta .new-meta-box .new-meta-item:last-child { + margin-right: 0; +} +#l_main .post .article-meta .new-meta-box .new-meta-item img, +#l_main .post .article-meta .new-meta-box .new-meta-item i { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; +} +#l_main .post .article-meta .new-meta-box .new-meta-item i { + margin-right: 4px; + border-radius: 0; + -webkit-border-radius: 0; +} +#l_main .post .article-meta .new-meta-box .new-meta-item i.fa-hashtag { + margin-right: 2px; +} +#l_main .post .article-meta .new-meta-box .new-meta-item p, +#l_main .post .article-meta .new-meta-box .new-meta-item a { + color: var(--color-meta); + padding: 3px 0; +} +#l_main .post .article-meta .new-meta-box .new-meta-item a { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; + align-items: center; +} +#l_main .post .article-meta .new-meta-box .new-meta-item a img { + height: 16px; + width: 16px; + margin-right: 8px; +} +#l_main .post .article-meta .new-meta-box .new-meta-item a p { + margin: 0; + font-weight: normal; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +#l_main .post .article-meta .new-meta-box .new-meta-item a:hover { + color: #ff5722; +} +#l_main .post .article-meta .new-meta-box .new-meta-item a:hover p { + color: #ff5722; +} +#l_main .post .article-meta .new-meta-box .author img, +#l_main .post .article-meta .new-meta-box .author i { + border-radius: 100%; + -webkit-border-radius: 100%; +} +#l_main .post .article-meta .new-meta-box .author img { + transform: translateY(-0.5px); + -webkit-transform: translateY(-0.5px); + -khtml-transform: translateY(-0.5px); + -moz-transform: translateY(-0.5px); + -o-transform: translateY(-0.5px); + -ms-transform: translateY(-0.5px); +} +@media screen and (max-width: 500px) { + #l_main .post .article-meta .new-meta-box .share { + width: 100%; + margin-top: 16px; + background: var(--color-block); + border-radius: 4px; + -webkit-border-radius: 4px; + } +} +#l_main .post .article-meta .new-meta-box .share-body { + position: relative; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; + margin: 0; + padding: 0 2px; +} +#l_main .post .article-meta .new-meta-box .share-body a { + padding: 0; + margin: 0 1px; +} +#l_main .post .article-meta .new-meta-box .share-body a img { + margin: 2px; + height: 24px; + width: auto; + background: transparent; +} +@media screen and (max-width: 500px) { + #l_main .post .article-meta .new-meta-box .share-body a img { + height: 32px; + margin: 8px; + } +} +#l_main .post .article-meta .new-meta-box .share-body div.hoverbox div.target { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; + position: absolute; + background: var(--color-card); + border-radius: 8px; + -webkit-border-radius: 8px; + box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); + padding: 8px; + left: 50%; + top: -20px; + transform: translate(-50%, -100%); + -webkit-transform: translate(-50%, -100%); + -khtml-transform: translate(-50%, -100%); + -moz-transform: translate(-50%, -100%); + -o-transform: translate(-50%, -100%); + -ms-transform: translate(-50%, -100%); +} +#l_main .post .article-meta .new-meta-box .share-body div.hoverbox div.target img { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + margin: 0; + padding: 0; + height: 128px; + width: 128px; + min-width: 128px; +} +#l_main .post .article-meta .new-meta-box .share-body div.hoverbox:hover div.target { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; +} +@media screen and (max-width: 500px) { + #l_main .post .article-meta .new-meta-box .share-body div.hoverbox div.target { + position: absolute; + } +} +#l_main .post span>img { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; +} +#l_main .post a img { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline; +} +@media screen and (max-width: 768px) { + #l_main { + padding-right: 0; + } +} +@media screen and (max-width: 768px) and (max-width: 500px) { + #l_main { + width: 100%; + } +} +.body-wrapper { + position: relative; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + width: 100%; + max-width: 1080px; + margin: 0 auto; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + justify-content: space-between; + -webkit-justify-content: space-between; + -khtml-justify-content: space-between; + -moz-justify-content: space-between; + -o-justify-content: space-between; + -ms-justify-content: space-between; + align-items: stretch; +} +@media screen and (min-width: 2048px) { + .body-wrapper { + max-width: 55vw; + } +} +article#comments p[ct] { + margin-top: 0; + margin-bottom: 1em; + font-size: 1.125rem; + color: var(--color-text); + font-weight: 600; +} +article#comments p[cst] { + margin-top: 1em; + margin-bottom: 1em; + font-size: 0.875rem; +} +article#comments #load-btns, +article#comments #loading-comments { + text-align: center; + margin: 16px 0; +} +article#comments #load-btns, +article#comments #loading-comments, +article#comments #load-btns a, +article#comments #loading-comments a, +article#comments #load-btns i, +article#comments #loading-comments i { + line-height: 3em; +} +article#comments #load-btns a.load-comments, +article#comments #loading-comments a.load-comments { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; + border-radius: 2px; + -webkit-border-radius: 2px; + cursor: pointer; + background: #44d7b6; + color: #fff; + padding-left: 48px; + padding-right: 48px; +} +article#comments #load-btns a.load-comments:hover, +article#comments #loading-comments a.load-comments:hover { + background: #ff5722; +} +.white-box { + background: var(--color-card); +} +img { + max-width: 100%; +} +img.lazyload:not(.placeholder) { + transition: opacity 0.5s ease-out 0s; + -webkit-transition: opacity 0.5s ease-out 0s; + -khtml-transition: opacity 0.5s ease-out 0s; + -moz-transition: opacity 0.5s ease-out 0s; + -o-transition: opacity 0.5s ease-out 0s; + -ms-transition: opacity 0.5s ease-out 0s; + transition: filter 0.25s ease-out 0s; + -webkit-transition: filter 0.25s ease-out 0s; + -khtml-transition: filter 0.25s ease-out 0s; + -moz-transition: filter 0.25s ease-out 0s; + -o-transition: filter 0.25s ease-out 0s; + -ms-transition: filter 0.25s ease-out 0s; +} +img.lazyload:not(.placeholder):not(.loaded) { + opacity: 0; + -webkit-opacity: 0; + -moz-opacity: 0; +} +img.lazyload:not(.placeholder).loaded { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; +} +img.lazyload:not(.placeholder):not(.loaded) { + filter: blur(8px); +} +img.lazyload:not(.placeholder).loaded { + filter: none; +} +.md >p { + padding-top: 4px; +} +.md h1, +.md h2, +.md h3, +.md h4, +.md h5, +.md h6 { + position: relative; + pointer-events: none; + margin-top: 0; + font-weight: 500; +} +.md h1 >a, +.md h2 >a, +.md h3 >a, +.md h4 >a, +.md h5 >a, +.md h6 >a { + color: inherit; + pointer-events: auto; +} +.md h1 >a:hover, +.md h2 >a:hover, +.md h3 >a:hover, +.md h4 >a:hover, +.md h5 >a:hover, +.md h6 >a:hover { + color: #ff5722; +} +.md h1:before, +.md h2:before, +.md h3:before, +.md h4:before, +.md h5:before, +.md h6:before { + content: ''; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + margin-top: -48px; + height: 96px; + visibility: hidden; + pointer-events: none; +} +.md h1:before, +.md h2:before { + margin-top: -32px; +} +.md .article-meta+h1, +.md .article-meta+h2 { + margin-top: -80px; +} +.md h3, +.md h4, +.md h5, +.md h6 { + margin-bottom: 1em; +} +.md h3:before { + margin-top: -56px; +} +.md h4:before { + margin-top: -64px; +} +.md h5 { + font-weight: bold; +} +.md h2+h3:before { + margin-top: -80px; +} +.md ul, +.md ol { + font-size: 0.9375rem; + list-style: initial; + padding-left: 8px; + margin-left: 16px; + margin-top: 1em; + margin-bottom: 1em; +} +.md ul ul, +.md ol ul, +.md ul ol, +.md ol ol { + margin-top: 0; + margin-bottom: 0; +} +.md ul li, +.md ol li { + margin-top: 0px; + margin-bottom: 0px; +} +.md ul li li, +.md ol li li { + margin-top: 0; + margin-bottom: 0; +} +.md ul li p, +.md ol li p { + margin-top: 4px; + margin-bottom: 0; +} +.md ul.task-list, +.md ol.task-list { + padding-left: 0; + margin-left: 4px; +} +.md ul.task-list li, +.md ol.task-list li { + list-style: none; +} +.md ul.task-list li input, +.md ol.task-list li input { + margin-right: 4px; +} +.md ul>li { + list-style: initial; +} +.md ol>li { + list-style: decimal; +} +.md .div-ori-link { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + text-align: center; + margin: 4rem 0; +} +.md .ori-link { + margin: auto; + padding: 1em 3em; + border: 1px solid #3dd9b6; + border-radius: 4px; + -webkit-border-radius: 4px; + color: #3dd9b6; + font-weight: 500; +} +.md .ori-link:hover { + color: #ff5722; + border-color: #ff5722; +} +#l_main .prev-next { + width: 100%; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + justify-content: space-between; + -webkit-justify-content: space-between; + -khtml-justify-content: space-between; + -moz-justify-content: space-between; + -o-justify-content: space-between; + -ms-justify-content: space-between; + align-items: baseline; + color: var(--color-meta); + margin: 0; + font-weight: 600; +} +#l_main .prev-next .prev { + text-align: left; + border-top-right-radius: 32px; + border-bottom-right-radius: 32px; +} +#l_main .prev-next .next { + text-align: right; + border-top-left-radius: 32px; + border-bottom-left-radius: 32px; +} +#l_main .prev-next p { + margin: 16px; +} +#l_main .prev-next section { + color: var(--color-meta); + padding: 16px; + border-radius: 8px; + -webkit-border-radius: 8px; +} +#l_main .prev-next section:hover { + color: #ff5722; +} +#l_main .article .prev-next { + width: 100%; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + justify-content: space-between; + -webkit-justify-content: space-between; + -khtml-justify-content: space-between; + -moz-justify-content: space-between; + -o-justify-content: space-between; + -ms-justify-content: space-between; + align-content: flex-start; + margin-top: 8px; +} +#l_main .article .prev-next >a { + width: 100%; + padding: 8px; + color: var(--color-meta); + background: var(--color-block); + border-radius: 4px; + -webkit-border-radius: 4px; +} +#l_main .article .prev-next >a:hover { + background: #ffeee8; +} +#l_main .article .prev-next >a:hover p.title { + color: #ff5722; +} +#l_main .article .prev-next >a p { + margin: 8px 0.5rem; +} +#l_main .article .prev-next >a p.title { + font-weight: 600; + font-size: 1rem; +} +#l_main .article .prev-next >a p.title >i { + width: 1rem; +} +#l_main .article .prev-next >a p.content { + font-size: 0.875rem; + font-weight: 400; + text-align: justify; + word-break: break-all; +} +#l_main .article .prev-next >a:only-child { + margin-left: 0; + margin-right: 0; +} +#l_main .article .prev-next .prev { + margin-left: 0; + margin-right: 8px; +} +#l_main .article .prev-next .prev p.title { + text-align: left; +} +#l_main .article .prev-next .next { + margin-left: 8px; + margin-right: 0; +} +#l_main .article .prev-next .next p.title { + text-align: right; +} +.article-title { + font-weight: 500; + margin-bottom: 12px; + line-height: 1.4; +} +.article-title a { + color: var(--color-h1); +} +.article-title a:hover { + color: #ff5722; +} +.article-title[pin] { + margin-right: 36px; +} +.article-desc { + word-break: break-word; +} +.post-v3 { + overflow: hidden; + text-align: justify; +} +.post-v3 .md { + color: var(--color-p); +} +.post-v3 .pin { + position: absolute; + width: 20px; + height: 20px; + border-radius: 20px; + -webkit-border-radius: 20px; + right: 24px; + top: 24px; + z-index: 1; + pointer-events: none; +} +.meta-v3[line_style='solid'] { + border-top: 1px solid rgba(68,68,68,0.1); +} +.meta-v3[line_style='dashed'] { + border-top: 2px dashed rgba(68,68,68,0.1); +} +.meta-v3[line_style='dotted'] { + border-top: 4px dotted rgba(68,68,68,0.1); +} +.meta-v3 { + margin-top: 16px; + padding-top: 12px; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + justify-content: space-between; + -webkit-justify-content: space-between; + -khtml-justify-content: space-between; + -moz-justify-content: space-between; + -o-justify-content: space-between; + -ms-justify-content: space-between; + color: var(--color-meta); +} +.meta-v3 >div { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + align-items: center; + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} +.meta-v3 time { + font-size: 0.875rem; +} +.meta-v3 .category-link { + font-size: 0.875rem; + color: var(--color-meta); + -webkit-font-smoothing: auto; + -moz-osx-font-smoothing: auto; +} +.meta-v3 .category-link:hover { + color: #ff5722; +} +.meta-v3 .readmore { + font-weight: bold; +} +.meta-v3 .avatar { + line-height: 0; + margin-right: 0.75em; +} +.meta-v3 .avatar img { + width: 24px; + height: 24px; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + border-radius: 12px; + -webkit-border-radius: 12px; + object-fit: cover; +} +.headimg-div { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + margin-left: -24px; + margin-top: -24px; + margin-bottom: 20px; + width: calc(100% + 3 * 16px); +} +.headimg-div .headimg-a { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + overflow: hidden; + height: 280px; +} +@media screen and (max-width: 768px) { + .headimg-div .headimg-a { + height: 250px; + } +} +@media screen and (max-width: 500px) { + .headimg-div .headimg-a { + height: 220px; + } +} +@media screen and (max-width: 425px) { + .headimg-div .headimg-a { + height: 190px; + } +} +.headimg-div .headimg { + object-fit: cover; + width: 100%; + height: 100%; + transition: transform 3s ease-out; + -webkit-transition: transform 3s ease-out; + -khtml-transition: transform 3s ease-out; + -moz-transition: transform 3s ease-out; + -o-transition: transform 3s ease-out; + -ms-transition: transform 3s ease-out; +} +.headimg-div .headimg:hover { + transform: scale(1.1); + -webkit-transform: scale(1.1); + -khtml-transform: scale(1.1); + -moz-transform: scale(1.1); + -o-transform: scale(1.1); + -ms-transform: scale(1.1); +} +.headimg-div .headimg.lazyload:not(.placeholder) { + transition: transform 3s ease-out, opacity 0.5s ease-out; + -webkit-transition: transform 3s ease-out, opacity 0.5s ease-out; + -khtml-transition: transform 3s ease-out, opacity 0.5s ease-out; + -moz-transition: transform 3s ease-out, opacity 0.5s ease-out; + -o-transition: transform 3s ease-out, opacity 0.5s ease-out; + -ms-transition: transform 3s ease-out, opacity 0.5s ease-out; +} +.headimg-div .headimg.lazyload:not(.placeholder):not(.loaded) { + opacity: 0; + -webkit-opacity: 0; + -moz-opacity: 0; +} +.headimg-div .headimg.lazyload:not(.placeholder).loaded { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; +} +#u-search .modal { + position: fixed; + height: 80%; + width: 100%; + max-width: 640px; + left: 50%; + top: 0; + margin: 64px 0px 0px -320px; + background: var(--color-card); + z-index: 3; + border-radius: 8px; + -webkit-border-radius: 8px; + overflow: hidden; +} +#u-search .modal .search-icon, +#u-search .modal #resule-hits-empty { + position: absolute; + top: 50%; + left: 50%; + width: 50%; + text-align: center; + transform: translate(-50%, -50%); + -webkit-transform: translate(-50%, -50%); + -khtml-transform: translate(-50%, -50%); + -moz-transform: translate(-50%, -50%); + -o-transform: translate(-50%, -50%); + -ms-transform: translate(-50%, -50%); +} +#u-search .modal .search-icon i, +#u-search .modal #resule-hits-empty i { + font-size: 8em; + color: #e8e8e8; + margin-bottom: 10px; +} +@media screen and (max-width: 680px) { + #u-search .modal { + box-shadow: none; + -webkit-box-shadow: none; + max-width: none; + top: 0; + left: 0; + margin: 0; + height: 100%; + border-radius: 0; + -webkit-border-radius: 0; + } +} +#u-search .modal .modal-header { + position: relative; + width: 100%; + height: 64px; + z-index: 3; + border-top-left-radius: 8px; + border-top-right-radius: 8px; + font-size: $fontsize; + box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + background: #fff; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +@media screen and (max-width: 680px) { + #u-search .modal .modal-header { + border-radius: 0; + -webkit-border-radius: 0; + padding: 0px; + } +} +#u-search .modal .modal-header .btn-close { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + position: absolute; + width: 55px; + height: 64px; + top: 0; + right: 0; + color: #3dd9b6; + cursor: pointer; + text-align: center; + line-height: 64px; + vertical-align: middle; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + z-index: 2; +} +#u-search .modal .modal-header .btn-close:hover { + transform: rotate(90deg); + -webkit-transform: rotate(90deg); + -khtml-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -o-transform: rotate(90deg); + -ms-transform: rotate(90deg); +} +#u-search .modal .modal-header #u-search-modal-form { + position: relative; + width: 100%; + height: 100%; + z-index: 2; +} +#u-search .modal .modal-header #u-search-modal-form input { + color: var(--color-text); +} +#u-search .modal .modal-header #u-search-modal-form #u-search-modal-input { + margin: 16px 50px; + padding: 0 8px; + width: calc(100% - 100px - 16px); + line-height: 2rem; + border-radius: 8px; + -webkit-border-radius: 8px; + vertical-align: middle; + border: none; + appearance: none; + box-shadow: none; + -webkit-box-shadow: none; + background: transparent; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +@media screen and (max-width: 680px) { + #u-search .modal .modal-header #u-search-modal-form #u-search-modal-input { + padding: 0; + } +} +#u-search .modal .modal-header #u-search-modal-form #u-search-modal-input:focus { + border-top-left-radius: 8px; + border-top-right-radius: 8px; +} +#u-search .modal .modal-header #u-search-modal-btn-submit { + position: absolute; + top: 0; + left: 0; + padding-left: 5px; + padding-top: 2px; + background: transparent; + border: none; + width: 50px; + height: 64px; + vertical-align: middle; + color: #3dd9b6; + z-index: 2; +} +#u-search .modal .modal-body { + position: absolute; + padding: 16px; + width: 100%; + height: calc(100% - 64px); + top: 64px; + left: 0; + overflow-y: scroll; + -webkit-overflow-scrolling: touch; + background: var(--color-card); + border-radius: 8px; + -webkit-border-radius: 8px; +} +#u-search .modal .modal-body::-webkit-scrollbar { + height: 4px; + width: 4px; +} +#u-search .modal .modal-body::-webkit-scrollbar-track-piece { + background: transparent; +} +#u-search .modal .modal-body::-webkit-scrollbar-thumb { + background: #3dd9b6; + cursor: pointer; + border-radius: 2px; + -webkit-border-radius: 2px; +} +#u-search .modal .modal-body::-webkit-scrollbar-thumb:hover { + background: #ff5722; +} +#u-search .modal .modal-body .modal-results { + list-style: none; +} +#u-search .modal .modal-body .modal-results .result { + position: relative; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + padding: 16px; + border-radius: 8px; + -webkit-border-radius: 8px; +} +#u-search .modal .modal-body .modal-results .result b[mark] { + color: #25be9c; + text-decoration: underline; + font-size: 120%; + background-color: #ffe600; +} +#u-search .modal .modal-body .modal-results .result:hover { + background: var(--color-site-bg); +} +#u-search .modal .modal-body .modal-results .result:hover .title { + color: var(--color-list-hl); +} +#u-search .modal .modal-body .modal-results .result .title { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; + max-width: 100%; + color: var(--color-list); + font-weight: bold; + padding: 1px; + margin-bottom: 2px; + white-space: normal; + overflow: hidden; + text-overflow: ellipsis; + font-size: 1.125rem; +} +#u-search .modal .modal-body .modal-results .result .digest { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + white-space: inherit; + overflow: hidden; + word-break: break-all; + text-overflow: ellipsis; + font-size: 0.8125rem; + color: var(--color-meta); +} +#u-search .modal .modal-body .modal-results .result .icon { + position: absolute; + top: 50%; + right: 0; + margin-top: -4px; + font-size: 11px; + color: var(--color-meta); +} +#u-search .modal-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0,0,0,0.7); + z-index: 1; +} +#l_side { + width: 240px; + float: right; + position: relative; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; +} +@media screen and (max-width: 768px) { + #l_side { + width: 100%; + } +} +#l_side .widget { + overflow: hidden; +} +#l_side .widget.sticky { + position: sticky; + top: 80px; + z-index: 1; +} +#l_side .widget >.content { + max-height: 200vh; + overflow: auto; + text-align: justify; + font-size: 0.875rem; + max-width: 100%; +} +@media screen and (max-width: 768px) { + #l_side .widget >.content { + max-height: none; + } +} +#l_side .widget >.content::-webkit-scrollbar { + height: 4px; + width: 4px; +} +#l_side .widget >.content::-webkit-scrollbar-track-piece { + background: transparent; +} +#l_side .widget >.content::-webkit-scrollbar-thumb { + background: #3dd9b6; + cursor: pointer; + border-radius: 2px; + -webkit-border-radius: 2px; +} +#l_side .widget >.content::-webkit-scrollbar-thumb:hover { + background: #ff5722; +} +.widget { + z-index: 0; + background: var(--color-card); + margin-bottom: 16px; + border-radius: 8px; + -webkit-border-radius: 8px; + width: 100%; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; +} +.widget ul li, +.widget ol li { + margin-top: 0; + margin-bottom: 0; +} +.widget.desktop { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; +} +@media screen and (max-width: 768px) { + .widget { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none !important; + } + .widget.mobile { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block !important; + } +} +.widget header { + border-top-left-radius: 8px; + border-top-right-radius: 8px; + padding: calc(16px - 2px); + font-weight: bold; + font-size: 0.875rem; + padding-bottom: 0; +} +.widget header, +.widget header a { + color: var(--color-meta); +} +.widget header >a:hover { + color: #ff5722; +} +.widget header span.name { + margin-left: 8px; +} +.widget >.content { + padding: 8px 0; +} +.widget >.content p { + margin-top: 1em; + margin-bottom: 1em; +} +.widget >.content p:first-child { + margin-top: 0.5em; +} +.widget >.content ul>li a { + color: var(--color-meta); + padding: 0 16px; + padding-left: 12px; + line-height: 2; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + justify-content: space-between; + -webkit-justify-content: space-between; + -khtml-justify-content: space-between; + -moz-justify-content: space-between; + -o-justify-content: space-between; + -ms-justify-content: space-between; + align-content: center; + border-left: 2px solid transparent; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +.widget >.content ul.entry, +.widget >.content ul.popular-posts { + list-style: none; +} +.widget >.content ul.entry a, +.widget >.content ul.popular-posts a { + color: var(--color-list); +} +.widget >.content ul.entry a .name, +.widget >.content ul.popular-posts a .name { + -webkit-box-flex: auto; + -moz-box-flex: auto; + -webkit-flex: auto 0; + -ms-flex: auto 0; + flex: auto 0; +} +.widget >.content ul.entry a .badge, +.widget >.content ul.popular-posts a .badge { + -webkit-box-flex: none; + -moz-box-flex: none; + -webkit-flex: none 0; + -ms-flex: none 0; + flex: none 0; + font-weight: normal; + font-size: 0.875rem; + color: rgba(68,68,68,0.7); +} +.widget >.content ul.entry a.active, +.widget >.content ul.popular-posts a.active { + border-left: 2px solid #3dd9b6; + color: var(--color-list-hl); +} +.widget >.content ul.entry a.active .badge, +.widget >.content ul.popular-posts a.active .badge { + color: rgba(61,217,182,0.9); +} +.widget >.content ul.entry a.child, +.widget >.content ul.popular-posts a.child { + padding-left: 32px; +} +.widget >.content ul.entry a:hover, +.widget >.content ul.popular-posts a:hover { + border-left: 2px solid #3dd9b6; + color: var(--color-list-hl); + background: var(--color-site-bg); +} +.widget.blogger { + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +.widget.blogger .content { + padding: 0; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + align-items: stretch; +} +.widget.blogger .content >.avatar { + align-self: center; + overflow: hidden; + position: relative; + border-top-left-radius: 8px; + border-top-right-radius: 8px; + line-height: 0; +} +.widget.blogger .content >.avatar.circle { + border-radius: 100%; + -webkit-border-radius: 100%; + width: 128px; + height: 128px; + margin-top: 32px; + margin-bottom: 1em; +} +.widget.blogger .content >.avatar.circle img { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + -webkit-transform: translate(-50%, -50%); + -khtml-transform: translate(-50%, -50%); + -moz-transform: translate(-50%, -50%); + -o-transform: translate(-50%, -50%); + -ms-transform: translate(-50%, -50%); +} +@media screen and (max-width: 768px) { + .widget.blogger .content >.avatar { + width: 80px; + height: 80px; + border-radius: 100%; + -webkit-border-radius: 100%; + border: 2px solid #fff; + } + .widget.blogger .content >.avatar img { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + -webkit-transform: translate(-50%, -50%); + -khtml-transform: translate(-50%, -50%); + -moz-transform: translate(-50%, -50%); + -o-transform: translate(-50%, -50%); + -ms-transform: translate(-50%, -50%); + position: absolute; + } +} +.widget.blogger .content .text :first-child { + margin-top: 16px; +} +.widget.blogger .content h2 { + text-align: center; + font-weight: bold; + margin: 8px; +} +@media screen and (max-width: 768px) { + .widget.blogger .content h2 { + margin: 8px; + } +} +.widget.blogger .content p { + text-align: center; + font-weight: bold; + margin: 8px 8px 0 8px; + empty-cells: hide; +} +.widget.blogger .content .social-wrapper { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + justify-content: space-between; + -webkit-justify-content: space-between; + -khtml-justify-content: space-between; + -moz-justify-content: space-between; + -o-justify-content: space-between; + -ms-justify-content: space-between; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + margin: 4px 4px; +} +.widget.blogger .content .social-wrapper a { + color: var(--color-meta); + padding: 0; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +.widget.blogger .content .social-wrapper a:hover { + color: #ff5722; +} +.widget.blogger .content .social-wrapper a.social { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; + align-items: center; + width: 32px; + height: 32px; + margin: 4px; + border-radius: 100px; + -webkit-border-radius: 100px; +} +.widget.blogger .content .social-wrapper a.social:hover { + background: #ebfbf7; + color: #3dd9b6; +} +@media screen and (max-width: 768px) { + .widget.blogger .content .social-wrapper { + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; + } +} +@media screen and (max-width: 768px) { + .widget.blogger { + box-shadow: none; + -webkit-box-shadow: none; + background: transparent !important; + margin-top: 32px; + backdrop-filter: none; + color: var(--color-site-inner); + } +} +.widget.text .content { + padding: 4px 16px; +} +.widget.text .content, +.widget.text .content p { + font-size: 0.875rem; + word-break: break-all; +} +.widget.text .content a { + color: #2092ec; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +.widget.text .content a:hover { + color: #ff5722; +} +.widget.text .content a:active { + color: #d93400; +} +.widget.list .content { + padding: 8px 0; +} +.widget.list .content a { + font-size: 0.875rem; + font-weight: bold; + line-height: 1.5; + padding-top: 6px; + padding-bottom: 6px; +} +.widget.list .content a img, +.widget.list .content a i { + margin-right: 4px; +} +.widget.list .content a i { + margin-left: 1px; +} +.widget.list .content a img { + vertical-align: middle; + height: 20px; + width: 20px; + margin-bottom: 4px; +} +.widget.list .content a img#round { + border-radius: 100%; + -webkit-border-radius: 100%; +} +.widget.grid .content .grid { + border: none; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + justify-content: space-around; + -webkit-justify-content: space-around; + -khtml-justify-content: space-around; + -moz-justify-content: space-around; + -o-justify-content: space-around; + -ms-justify-content: space-around; + padding: 4px 16px; +} +.widget.grid .content .grid a { + text-align: center; + border-radius: 2px; + -webkit-border-radius: 2px; + margin: 0; + padding: 4px 8px; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + align-items: center; + font-size: 0.78125rem; + font-weight: bold; + color: rgba(68,68,68,0.7); + line-height: 1.5; + word-wrap: break-word; +} +.widget.grid .content .grid a i { + margin-top: 0.3em; + margin-bottom: 0.3em; + font-size: 1.8em; +} +.widget.grid .content .grid a img { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline; + vertical-align: middle; + margin-bottom: 4px; +} +.widget.grid .content .grid a img#round { + border-radius: 100%; + -webkit-border-radius: 100%; +} +.widget.grid .content .grid a.active { + color: var(--color-list-hl); + background: var(--color-site-bg); +} +.widget.grid .content .grid a:hover { + color: var(--color-list-hl); + background: var(--color-site-bg); + border-radius: 2px; + -webkit-border-radius: 2px; +} +.widget.grid .content .grid.fixed a { + width: calc(100%/3 - 0 * 16px); +} +@media screen and (max-width: 768px) { + .widget.grid .content .grid.fixed a { + width: calc(100%/6 - 0 * 16px); + } +} +@media screen and (max-width: 500px) { + .widget.grid .content .grid.fixed a { + width: calc(100%/5 - 0 * 16px); + } +} +@media screen and (max-width: 425px) { + .widget.grid .content .grid.fixed a { + width: calc(100%/4 - 0 * 16px); + } +} +@media screen and (max-width: 375px) { + .widget.grid .content .grid.fixed a { + width: calc(100%/3 - 0 * 16px); + } +} +.widget.tagcloud .content { + text-align: justify; + padding: 8px 16px; +} +.widget.tagcloud .content a { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + line-height: 1.2em; + margin: 4px 0; + border-bottom: 1px solid transparent; +} +.widget.tagcloud .content a:hover { + color: #ff5722 !important; + border-bottom: 1px solid #ff5722; +} +.widget.related_posts .content { + font-weight: bold; +} +.widget.related_posts .content ul { + margin-top: 8px; + margin-bottom: 8px; +} +.widget.related_posts .content h3 { + font-size: 0.875rem; + font-weight: bold; + margin: 0; +} +.widget.related_posts .content h3 a { + line-height: inherit; + padding-top: 4px; + padding-bottom: 4px; +} +.widget.qrcode .content { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + align-items: center; + justify-content: space-around; + -webkit-justify-content: space-around; + -khtml-justify-content: space-around; + -moz-justify-content: space-around; + -o-justify-content: space-around; + -ms-justify-content: space-around; + padding-left: 16px; + padding-right: 16px; +} +.widget.qrcode .content, +.widget.qrcode .content img { + margin-bottom: 4px; +} +#l_side>.widget.page >.content { + padding-top: 0; + padding-left: 12px; + padding-right: 12px; +} +.webinfo { + padding: 0.2rem 1rem; +} +.webinfo .webinfo-item { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + padding: 4px 0 0; +} +.webinfo .webinfo-item div:first-child { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; +} +.webinfo .webinfo-item div:last-child { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; + float: right; +} +.widget-last { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block !important; +} +.widget-last .item { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + justify-content: space-between; + -webkit-justify-content: space-between; + -khtml-justify-content: space-between; + -moz-justify-content: space-between; + -o-justify-content: space-between; + -ms-justify-content: space-between; + font-size: 0.8rem; +} +.widget-last .item-title { + width: 100%; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.widget-sticky { + position: sticky; + top: 80px; + z-index: 10; +} +.bber-talk { + padding: 0.2rem 1rem; +} +.bber-talk :hover { + border-color: #49b1f5; + box-shadow: none; + -webkit-box-shadow: none; +} +.bber-talk a { + color: var(--font-color); +} +.bber-talk .talk-list { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block !important; + max-height: 25px; + overflow: hidden; +} +.bber-talk .talk-list :hover { + color: #49b1f5 !important; + transition: all 0.2s ease-in-out; + -webkit-transition: all 0.2s ease-in-out; + -khtml-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; +} +.bber-talk .talk-list .item { + text-overflow: ellipsis; + white-space: nowrap; + width: 98%; + overflow: hidden; +} +.snackbar-wrap { + position: fixed; + width: 100%; + left: 0; + bottom: 0; + background: #3dd9b6; + padding: 16px; + z-index: 2; +} +.snackbar-content { + max-width: 1080px; + margin: 16px auto; +} +@media screen and (max-width: 1080px) { + .snackbar-content { + max-width: 100%; + } +} +.snackbar-content p { + margin-top: 0.5rem; + margin-bottom: 0.5rem; + color: #fff; +} +.snackbar-content .title { + font-size: 1.5rem; + font-weight: 600; +} +.snackbar-content .action { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + margin: 1.5rem -4px; +} +.snackbar-content .action a { + margin: 4px; + cursor: pointer; + color: #fff; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; + padding: 0.4em 2em; + font-weight: 600; + border-radius: 2px; + -webkit-border-radius: 2px; + border: 1px solid #fff; +} +.snackbar-content .action a:hover { + color: #3dd9b6; + background: #fff; +} +.snackbar-wrap[theme='warning'] { + background: #f7e751; +} +.snackbar-wrap[theme='warning'] .snackbar-content p { + color: #000; +} +.snackbar-wrap[theme='warning'] .snackbar-content a { + color: #000; + border-color: #000; +} +.snackbar-wrap[theme='warning'] .snackbar-content a:hover { + color: #f7e751; + background: #000; +} +#l_side .toc-wrapper { + z-index: 1; + overflow: hidden; + border-radius: 8px; + -webkit-border-radius: 8px; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + line-height: 1.6; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +#l_side .toc-wrapper header { + position: sticky; + width: 100%; + top: 0; + padding-bottom: 4px; +} +#l_side .toc-wrapper .content { + max-height: calc(100vh - 144px); +} +#l_side .toc-wrapper .content a { + border-left: 2px solid transparent; +} +#l_side .toc-wrapper .content a.active { + color: var(--color-list-hl); + border-left: 2px solid #3dd9b6; +} +#l_side .toc-wrapper .content a:hover { + color: var(--color-list-hl); + background: var(--color-site-bg); + border-left: 2px solid #3dd9b6; +} +@media screen and (max-width: 768px) { + #l_side .toc-wrapper { + z-index: 1001; + position: fixed; + max-height: 1000px; + width: auto; + max-width: calc(100% - 2 * 16px); + top: 48px; + right: 16px; + border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0 4px 8px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 4px 8px 0px rgba(0,0,0,0.1); + border: 1px solid #e7e7e7; + visibility: hidden; + transform: scale(0, 0); + -webkit-transform: scale(0, 0); + -khtml-transform: scale(0, 0); + -moz-transform: scale(0, 0); + -o-transform: scale(0, 0); + -ms-transform: scale(0, 0); + transform-origin: right top; + -webkit-transform-origin: right top; + -khtml-transform-origin: right top; + -moz-transform-origin: right top; + -o-transform-origin: right top; + -ms-transform-origin: right top; + } + #l_side .toc-wrapper.active { + visibility: visible; + transform: scale(1, 1); + -webkit-transform: scale(1, 1); + -khtml-transform: scale(1, 1); + -moz-transform: scale(1, 1); + -o-transform: scale(1, 1); + -ms-transform: scale(1, 1); + } +} +@media screen and (max-width: 375px) { + #l_side .toc-wrapper { + right: 0; + } +} +#l_side .toc-wrapper a { + padding-left: 8px; + color: var(--color-meta); + font-size: 0.875rem; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; +} +#l_side .toc-wrapper ul .toc-child a, +#l_side .toc-wrapper ol .toc-child a { + font-weight: normal; +} +#l_side .toc-wrapper ul .toc-item.toc-level-1 .toc-child a, +#l_side .toc-wrapper ol .toc-item.toc-level-1 .toc-child a { + padding-left: 12.8px; +} +#l_side .toc-wrapper ul .toc-item.toc-level-2 .toc-child a, +#l_side .toc-wrapper ol .toc-item.toc-level-2 .toc-child a { + padding-left: 25.6px; +} +#l_side .toc-wrapper ul .toc-item.toc-level-3 .toc-child a, +#l_side .toc-wrapper ol .toc-item.toc-level-3 .toc-child a { + padding-left: 38.4px; +} +#l_side .toc-wrapper ul .toc-item.toc-level-4 .toc-child a, +#l_side .toc-wrapper ol .toc-item.toc-level-4 .toc-child a { + padding-left: 51.2px; +} +#l_side .toc-wrapper ul .toc-item.toc-level-5 .toc-child a, +#l_side .toc-wrapper ol .toc-item.toc-level-5 .toc-child a { + padding-left: 64px; +} +#l_side .toc-wrapper ul .toc-item.toc-level-6 .toc-child a, +#l_side .toc-wrapper ol .toc-item.toc-level-6 .toc-child a { + padding-left: 76.8px; +} +#l_side .toc-wrapper ul li, +#l_side .toc-wrapper ol li { + width: auto; + text-align: left; +} +#l_side .toc-wrapper ul li a, +#l_side .toc-wrapper ol li a { + padding: 0 8px 0 11px; + font-weight: bold; + width: 100%; +} +#l_side .toc-wrapper:empty { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; +} +#l_side .toc-wrapper .toc-child { + font-size: 1rem; + overflow: hidden; + transition: max-height 0.6s ease-in; + -webkit-transition: max-height 0.6s ease-in; + -khtml-transition: max-height 0.6s ease-in; + -moz-transition: max-height 0.6s ease-in; + -o-transition: max-height 0.6s ease-in; + -ms-transition: max-height 0.6s ease-in; + max-height: 0; +} +#l_side .toc-wrapper .toc-item.active>.toc-link { + color: var(--color-list-hl); + border-left: 2px solid #3dd9b6; +} +#l_side .toc-wrapper .toc-item.active>.toc-child { + max-height: 1000px; +} +.md .video-wrap { + margin: 1.5rem auto; +} +.article span.btn, +.md span.btn { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline; +} +.article span.btn a, +.md span.btn a { + text-decoration: none; + border-bottom: none; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; + padding: 3px 4px 2px 4px; + margin: 2px; + line-height: 1.1; + border-radius: 2px; + -webkit-border-radius: 2px; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +.article span.btn a i, +.md span.btn a i { + margin-right: 2px; +} +.article span.btn a:not([href]), +.md span.btn a:not([href]) { + opacity: 0.5; + -webkit-opacity: 0.5; + -moz-opacity: 0.5; +} +.article span.btn a:not([href]):hover, +.md span.btn a:not([href]):hover { + cursor: $not-allowed, not-allowed; +} +.article span.btn a, +.md span.btn a, +.article span.btn.regular a, +.md span.btn.regular a { + color: #44d7b6; + border: 1px solid #44d7b6; +} +.article span.btn a:hover, +.md span.btn a:hover, +.article span.btn.regular a:hover, +.md span.btn.regular a:hover { + color: #ff5722; + border-color: #ff5722; +} +.article span.btn a i, +.md span.btn a i, +.article span.btn.regular a i, +.md span.btn.regular a i { + margin-right: 4px; +} +.article span.btn.regular a, +.md span.btn.regular a, +.article span.btn.solid a, +.md span.btn.solid a { + padding: 8px 12px; +} +.article span.btn.solid a, +.md span.btn.solid a { + border: none; + background: #44d7b6; + color: #fff; +} +.article span.btn.solid a:hover, +.md span.btn.solid a:hover { + color: #fff; + background: #ff5722; +} +.article span.btn.large a, +.md span.btn.large a { + font-size: 1rem; + padding: 12px 36px; +} +.article span.btn.large a i, +.md span.btn.large a i { + margin-right: 8px; +} +.article span.btn.center, +.md span.btn.center { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + text-align: center; +} +.article div.btns, +.md div.btns { + margin: 0 -8px; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + align-items: flex-start; + overflow: visible; + line-height: 1.8; +} +.article div.btns, +.md div.btns, +.article div.btns p, +.md div.btns p, +.article div.btns a, +.md div.btns a { + font-size: 0.8125rem; + color: var(--color-p); +} +.article div.btns b, +.md div.btns b { + font-size: 0.875rem; +} +.article div.btns.wide>a, +.md div.btns.wide>a { + padding-left: 32px; + padding-right: 32px; +} +.article div.btns.fill>a, +.md div.btns.fill>a { + flex-grow: 1; + width: auto; +} +.article div.btns.around, +.md div.btns.around { + justify-content: space-around; + -webkit-justify-content: space-around; + -khtml-justify-content: space-around; + -moz-justify-content: space-around; + -o-justify-content: space-around; + -ms-justify-content: space-around; +} +.article div.btns.center, +.md div.btns.center { + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; +} +.article div.btns.grid2>a, +.md div.btns.grid2>a { + width: calc(100%/2 - 16px); +} +@media screen and (max-width: 1024px) { + .article div.btns.grid2>a, + .md div.btns.grid2>a { + width: calc(100%/2 - 16px); + } +} +@media screen and (max-width: 768px) { + .article div.btns.grid2>a, + .md div.btns.grid2>a { + width: calc(100%/2 - 16px); + } +} +@media screen and (max-width: 500px) { + .article div.btns.grid2>a, + .md div.btns.grid2>a { + width: calc(100%/1 - 16px); + } +} +.article div.btns.grid3>a, +.md div.btns.grid3>a { + width: calc(100%/3 - 16px); +} +@media screen and (max-width: 1024px) { + .article div.btns.grid3>a, + .md div.btns.grid3>a { + width: calc(100%/3 - 16px); + } +} +@media screen and (max-width: 768px) { + .article div.btns.grid3>a, + .md div.btns.grid3>a { + width: calc(100%/3 - 16px); + } +} +@media screen and (max-width: 500px) { + .article div.btns.grid3>a, + .md div.btns.grid3>a { + width: calc(100%/1 - 16px); + } +} +.article div.btns.grid4>a, +.md div.btns.grid4>a { + width: calc(100%/4 - 16px); +} +@media screen and (max-width: 1024px) { + .article div.btns.grid4>a, + .md div.btns.grid4>a { + width: calc(100%/3 - 16px); + } +} +@media screen and (max-width: 768px) { + .article div.btns.grid4>a, + .md div.btns.grid4>a { + width: calc(100%/3 - 16px); + } +} +@media screen and (max-width: 500px) { + .article div.btns.grid4>a, + .md div.btns.grid4>a { + width: calc(100%/2 - 16px); + } +} +.article div.btns.grid5>a, +.md div.btns.grid5>a { + width: calc(100%/5 - 16px); +} +@media screen and (max-width: 1024px) { + .article div.btns.grid5>a, + .md div.btns.grid5>a { + width: calc(100%/4 - 16px); + } +} +@media screen and (max-width: 768px) { + .article div.btns.grid5>a, + .md div.btns.grid5>a { + width: calc(100%/3 - 16px); + } +} +@media screen and (max-width: 500px) { + .article div.btns.grid5>a, + .md div.btns.grid5>a { + width: calc(100%/2 - 16px); + } +} +.article div.btns a, +.md div.btns a { + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + text-decoration: none; + border-bottom: none; + margin: 8px; + margin-top: calc(1.25 * 16px + 32px); + min-width: 120px; + font-weight: bold; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + justify-content: flex-start; + -webkit-justify-content: flex-start; + -khtml-justify-content: flex-start; + -moz-justify-content: flex-start; + -o-justify-content: flex-start; + -ms-justify-content: flex-start; + align-content: center; + align-items: center; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + padding: 8px; + text-align: center; + background: var(--color-block); + border-radius: 4px; + -webkit-border-radius: 4px; +} +.article div.btns a>img:first-child, +.md div.btns a>img:first-child, +.article div.btns a>i:first-child, +.md div.btns a>i:first-child { + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + height: 64px; + width: 64px; + box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + margin: 16px 8px 4px 8px; + margin-top: calc(-1.25 * 16px - 32px); + border: 2px solid var(--color-card); + background: #fff; + line-height: 60px; + font-size: 28px; +} +.article div.btns a>img:first-child.auto, +.md div.btns a>img:first-child.auto, +.article div.btns a>i:first-child.auto, +.md div.btns a>i:first-child.auto { + width: auto; +} +.article div.btns a>i:first-child, +.md div.btns a>i:first-child { + color: #fff; + background: #3dd9b6; +} +.article div.btns a p, +.md div.btns a p, +.article div.btns a b, +.md div.btns a b { + margin: 0.25em; + font-weight: normal; + line-height: 1.25; + word-wrap: break-word; +} +.article div.btns a b, +.md div.btns a b { + font-weight: bold; + line-height: 1.3; +} +.article div.btns a img, +.md div.btns a img { + margin: 0.4em auto; +} +.article div.btns a:not([href]), +.md div.btns a:not([href]) { + cursor: default; + color: inherit; +} +.article div.btns a[href]:hover, +.md div.btns a[href]:hover { + background: rgba(255,87,34,0.15); +} +.article div.btns a[href]:hover, +.md div.btns a[href]:hover, +.article div.btns a[href]:hover b, +.md div.btns a[href]:hover b { + color: #ff5722; +} +.article div.btns a[href]:hover>img:first-child, +.md div.btns a[href]:hover>img:first-child, +.article div.btns a[href]:hover>i:first-child, +.md div.btns a[href]:hover>i:first-child { + transform: scale(1.1) translateY(-8px); + -webkit-transform: scale(1.1) translateY(-8px); + -khtml-transform: scale(1.1) translateY(-8px); + -moz-transform: scale(1.1) translateY(-8px); + -o-transform: scale(1.1) translateY(-8px); + -ms-transform: scale(1.1) translateY(-8px); + box-shadow: 0 4px 8px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 4px 8px 0px rgba(0,0,0,0.1); +} +.article div.btns a[href]:hover>i:first-child, +.md div.btns a[href]:hover>i:first-child { + background: #ff5722; +} +.article div.btns.circle a>img:first-child, +.md div.btns.circle a>img:first-child, +.article div.btns.circle a>i:first-child, +.md div.btns.circle a>i:first-child { + border-radius: 32px; + -webkit-border-radius: 32px; +} +.article div.btns.rounded a>img:first-child, +.md div.btns.rounded a>img:first-child, +.article div.btns.rounded a>i:first-child, +.md div.btns.rounded a>i:first-child { + border-radius: 16px; + -webkit-border-radius: 16px; +} +.md .checkbox { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + align-items: center; + margin-top: 1em; + margin-bottom: 1em; +/* Checkbox */ +/* Radio */ +/* Colors */ +} +.md .checkbox+.checkbox { + margin-top: -1em; +} +.md .checkbox input { + transform: translate(0, -1px); + -webkit-transform: translate(0, -1px); + -khtml-transform: translate(0, -1px); + -moz-transform: translate(0, -1px); + -o-transform: translate(0, -1px); + -ms-transform: translate(0, -1px); + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + -o-appearance: none; + appearance: none; + position: relative; + height: 16px; + width: 16px; + transition: all 0.15s ease-out 0s; + -webkit-transition: all 0.15s ease-out 0s; + -khtml-transition: all 0.15s ease-out 0s; + -moz-transition: all 0.15s ease-out 0s; + -o-transition: all 0.15s ease-out 0s; + -ms-transition: all 0.15s ease-out 0s; + cursor: pointer; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; + outline: none; + border-radius: 2px; + -webkit-border-radius: 2px; + flex-shrink: 0; + margin-right: 8px; + pointer-events: none; +} +.md .checkbox input[type=checkbox]:before, +.md .checkbox input[type=checkbox]:after { + position: absolute; + content: ""; + background: #fff; +} +.md .checkbox input[type=checkbox]:before { + left: 1px; + top: 5px; + width: 0px; + height: 2px; + transition: all 0.2s ease-in; + -webkit-transition: all 0.2s ease-in; + -khtml-transition: all 0.2s ease-in; + -moz-transition: all 0.2s ease-in; + -o-transition: all 0.2s ease-in; + -ms-transition: all 0.2s ease-in; + transform: rotate(45deg); + -webkit-transform: rotate(45deg); + -khtml-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -o-transform: rotate(45deg); + -ms-transform: rotate(45deg); + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + -o-transform: rotate(45deg); +} +.md .checkbox input[type=checkbox]:after { + right: 7px; + bottom: 3px; + width: 2px; + height: 0px; + transition: all 0.2s ease-out; + -webkit-transition: all 0.2s ease-out; + -khtml-transition: all 0.2s ease-out; + -moz-transition: all 0.2s ease-out; + -o-transition: all 0.2s ease-out; + -ms-transition: all 0.2s ease-out; + transform: rotate(40deg); + -webkit-transform: rotate(40deg); + -khtml-transform: rotate(40deg); + -moz-transform: rotate(40deg); + -o-transform: rotate(40deg); + -ms-transform: rotate(40deg); + -webkit-transform: rotate(40deg); + -moz-transform: rotate(40deg); + -ms-transform: rotate(40deg); + -o-transform: rotate(40deg); + transition-delay: 0.25s; + -webkit-transition-delay: 0.25s; + -khtml-transition-delay: 0.25s; + -moz-transition-delay: 0.25s; + -o-transition-delay: 0.25s; + -ms-transition-delay: 0.25s; +} +.md .checkbox input[type=checkbox]:checked:before { + left: 0px; + top: 7px; + width: 6px; + height: 2px; +} +.md .checkbox input[type=checkbox]:checked:after { + right: 3px; + bottom: 1px; + width: 2px; + height: 10px; +} +.md .checkbox.minus input[type=checkbox]:before { + transform: rotate(0); + -webkit-transform: rotate(0); + -khtml-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + left: 1px; + top: 5px; + width: 0px; + height: 2px; +} +.md .checkbox.minus input[type=checkbox]:after { + transform: rotate(0); + -webkit-transform: rotate(0); + -khtml-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + left: 1px; + top: 5px; + width: 0px; + height: 2px; +} +.md .checkbox.minus input[type=checkbox]:checked:before { + left: 1px; + top: 5px; + width: 10px; + height: 2px; +} +.md .checkbox.minus input[type=checkbox]:checked:after { + left: 1px; + top: 5px; + width: 10px; + height: 2px; +} +.md .checkbox.plus input[type=checkbox]:before { + transform: rotate(0); + -webkit-transform: rotate(0); + -khtml-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + left: 1px; + top: 5px; + width: 0px; + height: 2px; +} +.md .checkbox.plus input[type=checkbox]:after { + transform: rotate(0); + -webkit-transform: rotate(0); + -khtml-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + left: 5px; + top: 1px; + width: 2px; + height: 0px; +} +.md .checkbox.plus input[type=checkbox]:checked:before { + left: 1px; + top: 5px; + width: 10px; + height: 2px; +} +.md .checkbox.plus input[type=checkbox]:checked:after { + left: 5px; + top: 1px; + width: 2px; + height: 10px; +} +.md .checkbox.times input[type=checkbox]:before { + transform: rotate(45deg); + -webkit-transform: rotate(45deg); + -khtml-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -o-transform: rotate(45deg); + -ms-transform: rotate(45deg); + left: 3px; + top: 1px; + width: 0px; + height: 2px; +} +.md .checkbox.times input[type=checkbox]:after { + transform: rotate(135deg); + -webkit-transform: rotate(135deg); + -khtml-transform: rotate(135deg); + -moz-transform: rotate(135deg); + -o-transform: rotate(135deg); + -ms-transform: rotate(135deg); + right: 3px; + top: 1px; + width: 0px; + height: 2px; +} +.md .checkbox.times input[type=checkbox]:checked:before { + left: 1px; + top: 5px; + width: 10px; + height: 2px; +} +.md .checkbox.times input[type=checkbox]:checked:after { + right: 1px; + top: 5px; + width: 10px; + height: 2px; +} +.md .checkbox input[type=radio] { + border-radius: 50%; + -webkit-border-radius: 50%; +} +.md .checkbox input[type=radio]:before { + content: ""; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + width: 8px; + height: 8px; + border-radius: 50%; + -webkit-border-radius: 50%; + margin: 2px; + transform: scale(0); + -webkit-transform: scale(0); + -khtml-transform: scale(0); + -moz-transform: scale(0); + -o-transform: scale(0); + -ms-transform: scale(0); + transition: all 0.25s ease-out; + -webkit-transition: all 0.25s ease-out; + -khtml-transition: all 0.25s ease-out; + -moz-transition: all 0.25s ease-out; + -o-transition: all 0.25s ease-out; + -ms-transition: all 0.25s ease-out; +} +.md .checkbox input[type=radio]:checked:before { + transform: scale(1); + -webkit-transform: scale(1); + -khtml-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); +} +.md .checkbox input { + border: 2px solid #3dd9b6; +} +.md .checkbox input[type=checkbox]:checked { + background: #3dd9b6; +} +.md .checkbox input[type=radio]:checked:before { + background: #3dd9b6; +} +.md .checkbox.red input { + border-color: #fe5f58; +} +.md .checkbox.red input[type=checkbox]:checked { + background: #fe5f58; +} +.md .checkbox.red input[type=radio]:checked:before { + background: #fe5f58; +} +.md .checkbox.green input { + border-color: #3dc550; +} +.md .checkbox.green input[type=checkbox]:checked { + background: #3dc550; +} +.md .checkbox.green input[type=radio]:checked:before { + background: #3dc550; +} +.md .checkbox.yellow input { + border-color: #ffbd2b; +} +.md .checkbox.yellow input[type=checkbox]:checked { + background: #ffbd2b; +} +.md .checkbox.yellow input[type=radio]:checked:before { + background: #ffbd2b; +} +.md .checkbox.cyan input { + border-color: #1bcdfc; +} +.md .checkbox.cyan input[type=checkbox]:checked { + background: #1bcdfc; +} +.md .checkbox.cyan input[type=radio]:checked:before { + background: #1bcdfc; +} +.md .checkbox.blue input { + border-color: #2196f3; +} +.md .checkbox.blue input[type=checkbox]:checked { + background: #2196f3; +} +.md .checkbox.blue input[type=radio]:checked:before { + background: #2196f3; +} +article .checkbox p { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; + margin-top: 0 !important; + margin-bottom: 0 !important; +} +div.dropmenu-wrapper { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; +} +div.dropmenu { + position: relative; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + color: #2092ec; +} +div.dropmenu:hover { + color: inherit; +} +div.dropmenu:hover >ul { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + left: 0; + margin-left: 0; + margin-top: 0px; +} +div.dropmenu ul>li { + list-style: none; +} +div.dropmenu ul>li >a:hover { + text-decoration: none !important; +} +div.dropmenu .list-v .list-v { + left: calc(100% - 0.5 * 16px); +} +div.gallery { + margin: 1em 0; + overflow: hidden; +} +div.gallery+.gallery { + margin-top: -1em; +} +div.gallery >.fancybox, +div.gallery >p>.fancybox { + margin: 1px; + padding: 0; + position: relative; +} +div.gallery >.fancybox a, +div.gallery >p>.fancybox a { + height: 100%; + width: 100%; +} +div.gallery >.fancybox img, +div.gallery >p>.fancybox img { + object-fit: cover; + height: 100%; + width: 100%; +} +div.gallery >.fancybox .image-caption, +div.gallery >p>.fancybox .image-caption { + opacity: 0; + -webkit-opacity: 0; + -moz-opacity: 0; + transform: translateY(100%); + -webkit-transform: translateY(100%); + -khtml-transform: translateY(100%); + -moz-transform: translateY(100%); + -o-transform: translateY(100%); + -ms-transform: translateY(100%); + transition: all 0.3s ease; + -webkit-transition: all 0.3s ease; + -khtml-transition: all 0.3s ease; + -moz-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + -ms-transition: all 0.3s ease; + pointer-events: none; + position: absolute; + width: 100%; + bottom: 0; + text-align: center; + background: rgba(0,0,0,0.3); + color: #fff; +} +div.gallery >.fancybox .image-caption:empty, +div.gallery >p>.fancybox .image-caption:empty { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; +} +div.gallery >.fancybox:hover .image-caption, +div.gallery >p>.fancybox:hover .image-caption { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + transform: translateY(0); + -webkit-transform: translateY(0); + -khtml-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); +} +div.gallery, +div.gallery >p { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; + align-items: center; + flex-wrap: nowrap; + -webkit-flex-wrap: nowrap; + -khtml-flex-wrap: nowrap; + -moz-flex-wrap: nowrap; + -o-flex-wrap: nowrap; + -ms-flex-wrap: nowrap; + padding: 0 !important; + align-items: stretch; +} +div.gallery[col] { + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + justify-content: flex-start; + -webkit-justify-content: flex-start; + -khtml-justify-content: flex-start; + -moz-justify-content: flex-start; + -o-justify-content: flex-start; + -ms-justify-content: flex-start; +} +div.gallery[col='2']>.fancybox { + width: calc(50% - 2 * 1px); +} +div.gallery[col='3']>.fancybox { + width: calc(33.33% - 2 * 1px); +} +div.gallery[col='4']>.fancybox { + width: calc(25% - 2 * 1px); +} +div.gallery[col='5']>.fancybox { + width: calc(20% - 2 * 1px); +} +div.gallery[col='6']>.fancybox { + width: calc(16.66% - 2 * 1px); +} +div.gallery[col='7']>.fancybox { + width: calc(14.2857% - 2 * 1px); +} +div.gallery[col='8']>.fancybox { + width: calc(12.5% - 2 * 1px); +} +div.gallery >p { + margin: 0; +} +div.gallery.left, +div.gallery.left>p { + justify-content: flex-start; + -webkit-justify-content: flex-start; + -khtml-justify-content: flex-start; + -moz-justify-content: flex-start; + -o-justify-content: flex-start; + -ms-justify-content: flex-start; +} +div.gallery.center, +div.gallery.center>p { + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; +} +div.gallery.right, +div.gallery.right>p { + justify-content: flex-end; + -webkit-justify-content: flex-end; + -khtml-justify-content: flex-end; + -moz-justify-content: flex-end; + -o-justify-content: flex-end; + -ms-justify-content: flex-end; +} +div.gallery.stretch, +div.gallery.stretch>p { + align-items: stretch; +} +.fancybox-container .fancybox-stage { + cursor: zoom-out; +} +div.fancybox { + margin-top: 1em; + margin-bottom: 1em; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; + align-items: center; + flex-wrap: nowrap; + -webkit-flex-wrap: nowrap; + -khtml-flex-wrap: nowrap; + -moz-flex-wrap: nowrap; + -o-flex-wrap: nowrap; + -ms-flex-wrap: nowrap; + padding: 0 !important; + overflow: hidden; + border-radius: 2px; + -webkit-border-radius: 2px; +} +@media screen and (max-width: 500px) { + div.fancybox { + border-radius: 1px; + -webkit-border-radius: 1px; + } +} +div.fancybox a { + line-height: 0; + margin: 0 auto; + align-items: stretch; +} +div.fancybox .gallery { + overflow: hidden; +} +div.fancybox .image-caption { + font-size: 0.8125rem; + padding-top: 0.5em; + padding-bottom: 1em; + color: var(--color-meta); +} +div.fancybox .image-caption:empty { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; +} +details { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + padding: 16px; + margin: 1em 0; + border-radius: 4px; + -webkit-border-radius: 4px; + background: var(--color-card); + font-size: 0.9375rem; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + border: 1px solid var(--color-block); +} +details summary { + cursor: pointer; + padding: 16px; + margin: -16px; + border-radius: 4px; + -webkit-border-radius: 4px; + color: rgba(68,68,68,0.7); + font-size: 0.875rem; + font-weight: bold; + position: relative; + line-height: normal; +} +details summary > p, +details summary > h1, +details summary > h2, +details summary > h3, +details summary > h4, +details summary > h5, +details summary > h6 { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline; + border-bottom: none !important; +} +details summary:hover { + color: var(--color-p); +} +details summary:hover:after { + position: absolute; + content: '+'; + text-align: center; + top: 50%; + transform: translateY(-50%); + -webkit-transform: translateY(-50%); + -khtml-transform: translateY(-50%); + -moz-transform: translateY(-50%); + -o-transform: translateY(-50%); + -ms-transform: translateY(-50%); + right: 16px; +} +details >summary { + background: var(--color-block); +} +details[blue] { + border-color: #e8f4fd; +} +details[blue] >summary { + background: #e8f4fd; +} +details[cyan] { + border-color: #e8fafe; +} +details[cyan] >summary { + background: #e8fafe; +} +details[green] { + border-color: #ebf9ed; +} +details[green] >summary { + background: #ebf9ed; +} +details[yellow] { + border-color: #fff8e9; +} +details[yellow] >summary { + background: #fff8e9; +} +details[red] { + border-color: #feefee; +} +details[red] >summary { + background: #feefee; +} +details[open] { + border-color: rgba(68,68,68,0.2); +} +details[open] >summary { + border-bottom: 1px solid rgba(68,68,68,0.2); + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} +details[open][blue] { + border-color: rgba(33,150,243,0.3); +} +details[open][blue] >summary { + border-bottom-color: rgba(33,150,243,0.3); +} +details[open][cyan] { + border-color: rgba(27,205,252,0.3); +} +details[open][cyan] >summary { + border-bottom-color: rgba(27,205,252,0.3); +} +details[open][green] { + border-color: rgba(61,197,80,0.3); +} +details[open][green] >summary { + border-bottom-color: rgba(61,197,80,0.3); +} +details[open][yellow] { + border-color: rgba(255,189,43,0.3); +} +details[open][yellow] >summary { + border-bottom-color: rgba(255,189,43,0.3); +} +details[open][red] { + border-color: rgba(254,95,88,0.3); +} +details[open][red] >summary { + border-bottom-color: rgba(254,95,88,0.3); +} +details[open] >summary { + color: #444; + margin-bottom: 0; +} +details[open] >summary:hover:after { + content: '-'; +} +details[open] >div.content { + padding: 16px; + margin: -16px; + margin-top: 0; +} +details[open] >div.content p>a:hover { + text-decoration: underline; +} +details[open] >div.content > p:first-child, +details[open] >div.content > .tabs:first-child, +details[open] >div.content > ul:first-child, +details[open] >div.content > ol:first-child, +details[open] >div.content > .highlight:first-child, +details[open] >div.content > .note:first-child, +details[open] >div.content > details:first-child { + margin-top: 0; +} +details[open] >div.content > p:last-child, +details[open] >div.content > .tabs:last-child, +details[open] >div.content > ul:last-child, +details[open] >div.content > ol:last-child, +details[open] >div.content > .highlight:last-child, +details[open] >div.content > .note:last-child, +details[open] >div.content > details:last-child { + margin-bottom: 0; +} +.md .frame-wrap { + position: relative; + overflow: hidden; + margin: 0 auto; + max-width: 100%; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + align-items: center; +} +.md .frame-wrap img, +.md .frame-wrap video { + border-radius: 0; + -webkit-border-radius: 0; +} +.md .frame-wrap .frame { + z-index: 1; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + position: absolute; + background-size: 100%; + -webkit-background-size: 100%; + -moz-background-size: 100%; + background-repeat: no-repeat; + overflow: hidden; +} +.md .img-wrap .frame-wrap[part] { + height: auto; +} +.md .frame-wrap#iphone11 img, +.md .frame-wrap#iphone11 video { + width: 287px; + margin-top: 19px; + margin-bottom: 20px; +} +.md .frame-wrap#iphone11 .frame { + background-image: url("https://cdn.jsdelivr.net/gh/volantis-x/cdn-volantis@3/img/frame/iphone11.svg"); + width: 329px; + height: 658px; +} +.md .frame-wrap[part='top'] img, +.md .frame-wrap[part='top'] video { + margin-bottom: 0 !important; +} +.md .frame-wrap:not([part='bottom']) .frame { + top: 0; +} +.md .frame-wrap[part='bottom'] img, +.md .frame-wrap[part='bottom'] video { + bottom: 0; + margin-top: 0 !important; +} +.md .frame-wrap[part='bottom'] .frame { + bottom: 0; +} +@media screen and (max-width: 500px) { + .md .frame-wrap#iphone11 img, + .md .frame-wrap#iphone11 video { + width: 208px; + margin-top: 13px; + margin-bottom: 14px; + } + .md .frame-wrap#iphone11 .frame { + width: 238px; + height: 476px; + } +} +.users-wrap { + overflow: hidden; +} +.users-wrap .group-header { + margin: 0 0 1rem; +} +.users-wrap .group-header p { + margin: 0; + font-size: 0.875rem; +} +.users-wrap .group-header p:first-child { + font-size: 1.25rem; + font-weight: 500; +} +.users-wrap .group-body { + width: 100%; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + align-items: stretch; + margin-bottom: 2rem; +} +.users-wrap .friendsjs-wrap { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; +} +.users-wrap .friendsjs-wrap .loading-wrap { + min-height: 50px; + margin: 2rem 0; + text-align: center; +} +.users-wrap .user-card { + flex-shrink: 1; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + align-items: stretch; + width: 12.5%; +} +@media screen and (max-width: 980px) { + .users-wrap .user-card { + width: 14.28%; + } +} +@media screen and (max-width: 900px) { + .users-wrap .user-card { + width: 16.66%; + } +} +@media screen and (max-width: 820px) { + .users-wrap .user-card { + width: 20%; + } +} +@media screen and (max-width: 768px) { + .users-wrap .user-card { + width: 16.66%; + } +} +@media screen and (max-width: 500px) { + .users-wrap .user-card { + width: 25%; + } +} +.users-wrap .user-card .card-link { + margin: 0; + width: 100%; + color: var(--text-p1); + font-size: 10px; + font-weight: 500; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + justify-content: flex-start; + -webkit-justify-content: flex-start; + -khtml-justify-content: flex-start; + -moz-justify-content: flex-start; + -o-justify-content: flex-start; + -ms-justify-content: flex-start; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + align-items: center; + text-align: center; + line-height: 1.2; + border-radius: 4px; + -webkit-border-radius: 4px; + overflow: hidden; + position: relative; + padding: 1rem 0.5rem; +} +.users-wrap .user-card .card-link img { + object-fit: cover; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + width: 48px; + height: 48px; + background: var(--card); + border-radius: 64px; + -webkit-border-radius: 64px; + margin: 0 0 0.5rem; +} +.users-wrap .user-card .card-link >img { + transition: transform 0.2s ease-out, box-shadow 0.2s ease-out; + -webkit-transition: transform 0.2s ease-out, box-shadow 0.2s ease-out; + -khtml-transition: transform 0.2s ease-out, box-shadow 0.2s ease-out; + -moz-transition: transform 0.2s ease-out, box-shadow 0.2s ease-out; + -o-transition: transform 0.2s ease-out, box-shadow 0.2s ease-out; + -ms-transition: transform 0.2s ease-out, box-shadow 0.2s ease-out; +} +.users-wrap .user-card .card-link:hover { + background: var(--block-hover); +} +.users-wrap .user-card .card-link:hover img { + transform: scale(1.2) rotate(8deg); + -webkit-transform: scale(1.2) rotate(8deg); + -khtml-transform: scale(1.2) rotate(8deg); + -moz-transform: scale(1.2) rotate(8deg); + -o-transform: scale(1.2) rotate(8deg); + -ms-transform: scale(1.2) rotate(8deg); + box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); +} +a.ghcard { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; + line-height: 0; +} +.md .ghcard-group { + column-count: 2; + -webkit-column-count: 2; + -moz-column-count: 2; + column-gap: 0; + -webkit-column-gap: 0; + -moz-column-gap: 0; + margin: 0 -8px; +} +.md .ghcard-group .ghcard { + margin: 8px; +} +.md .img { + object-fit: contain; +} +img.inline { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline !important; + vertical-align: middle; + transform: translateY(-4px); + -webkit-transform: translateY(-4px); + -khtml-transform: translateY(-4px); + -moz-transform: translateY(-4px); + -o-transform: translateY(-4px); + -ms-transform: translateY(-4px); +} +.md .tag.link { + margin-top: 1em; + margin-bottom: 1em; +} +.md .link-card { + margin-right: 1em; + background: var(--color-block); + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-inline-flexbox /* TWEENER - IE 10 */; + display: -webkit-inline-flex /* NEW - Chrome */; + display: inline-flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: inline-flex; + align-items: center; + cursor: pointer; + text-align: center; + width: 361px; + max-width: 100%; + box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + color: var(--color-p); + border-radius: 8px; + -webkit-border-radius: 8px; +} +@media screen and (max-width: 425px) { + .md .link-card { + max-width: 100%; + width: 100%; + } +} +.md .link-card:hover { + box-shadow: 0 4px 8px 0px rgba(0,0,0,0.1), 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 4px 8px 0px rgba(0,0,0,0.1), 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); +} +.md .link-card div.left, +.md .link-card div.right { + pointer-events: none; +} +.md .link-card div.left { + width: 54px; + height: 54px; + margin: 12px; + overflow: hidden; + flex-shrink: 0; + position: relative; +} +.md .link-card div.left i { + font-size: 32px; + line-height: 48px; + margin-left: 4px; +} +.md .link-card div.left img { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + position: absolute; + border-radius: 8px/4; + -webkit-border-radius: 8px/4; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + -webkit-transform: translate(-50%, -50%); + -khtml-transform: translate(-50%, -50%); + -moz-transform: translate(-50%, -50%); + -o-transform: translate(-50%, -50%); + -ms-transform: translate(-50%, -50%); +} +.md .link-card div.right { + overflow: hidden; + margin-right: 16px; +} +.md .link-card p { + margin: 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.md .link-card p.text { + font-weight: bold; +} +.md .link-card p.url { + flex-shrink: 0; + color: var(--color-meta); + font-size: 0.8125rem; +} +.md .link-group { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 16px; +} +@media screen and (max-width: 850px) { + .md .link-group { + grid-template-columns: 1fr; + } +} +.md .link-group .tag.link { + margin: 0; +} +.md .link-group .link-card { + width: 100%; +} +audio, +video { + border-radius: 4px; + -webkit-border-radius: 4px; + max-width: 100%; +} +video { + z-index: 1; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +video:hover { + box-shadow: 0 4px 8px 0px rgba(0,0,0,0.24), 0 8px 16px 0px rgba(0,0,0,0.24); + -webkit-box-shadow: 0 4px 8px 0px rgba(0,0,0,0.24), 0 8px 16px 0px rgba(0,0,0,0.24); +} +div.video { + line-height: 0; + text-align: center; +} +div.videos { + max-width: calc(100% + 2 * 4px); + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + flex-wrap: wrap; + -webkit-flex-wrap: wrap; + -khtml-flex-wrap: wrap; + -moz-flex-wrap: wrap; + -o-flex-wrap: wrap; + -ms-flex-wrap: wrap; + justify-content: flex-start; + -webkit-justify-content: flex-start; + -khtml-justify-content: flex-start; + -moz-justify-content: flex-start; + -o-justify-content: flex-start; + -ms-justify-content: flex-start; + align-items: flex-end; + margin: 1em -4px; +} +div.videos .video, +div.videos iframe { + width: 100%; + margin: 4px; +} +div.videos iframe { + border-radius: 4px; + -webkit-border-radius: 4px; + width: 100%; + min-height: 300px; +} +div.videos.left { + justify-content: flex-start; + -webkit-justify-content: flex-start; + -khtml-justify-content: flex-start; + -moz-justify-content: flex-start; + -o-justify-content: flex-start; + -ms-justify-content: flex-start; +} +div.videos.center { + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; +} +div.videos.right { + justify-content: flex-end; + -webkit-justify-content: flex-end; + -khtml-justify-content: flex-end; + -moz-justify-content: flex-end; + -o-justify-content: flex-end; + -ms-justify-content: flex-end; +} +div.videos.stretch { + align-items: stretch; +} +div.videos[col='1'] .video, +div.videos[col='1'] iframe { + width: 100%; +} +div.videos[col='2'] .video, +div.videos[col='2'] iframe { + width: calc(50% - 2 * 4px); +} +div.videos[col='3'] .video, +div.videos[col='3'] iframe { + width: calc(33.33% - 2 * 4px); +} +div.videos[col='4'] .video, +div.videos[col='4'] iframe { + width: calc(25% - 2 * 4px); +} +div.note { + position: relative; + margin-top: 1em; + margin-bottom: 1em; + padding: 16px; + padding-left: calc(16px + 16px); + border-radius: 4px; + -webkit-border-radius: 4px; + font-size: 0.9375rem; + background: var(--color-block); + border-left: 4px solid #3dd9b6; +} +div.note h2, +div.note h3, +div.note h4, +div.note h5, +div.note h6 { + margin-top: 3px; + margin-bottom: 0; + padding-top: 0 !important; + border-bottom: initial; +} +div.note p, +div.note ul, +div.note ol, +div.note blockquote, +div.note img { + margin-top: 0.5em; + margin-bottom: 0.5em; +} +div.note .link-card { + background: var(--color-card); +} +div.note::before { + position: absolute; + top: calc(50% - 24px * 0.5); + left: 4px; + width: 24px; + height: 24px; + text-align: center; + font-weight: 600; + line-height: 24px; + vertical-align: middle; + font-family: 'Font Awesome 6 Pro'; +} +div.note::before { + color: #3dd9b6; + content: '\f054'; +} +div.note::before { + content: '\f054'; +} +div.note.quote { + background: #e8f4fd; + border-color: #2196f3; +} +div.note.quote::before { + color: #2196f3; + content: '\f10d'; +} +div.note.info { + background: #ebfbf7; + border-color: #3dd9b6; +} +div.note.info::before { + color: #3dd9b6; + content: '\f129'; +} +div.note.success, +div.note.done { + background: #ebf9ed; + border-color: #3dc550; +} +div.note.success::before, +div.note.done::before { + color: #3dc550; + content: '\f00c'; +} +div.note.warning { + background: #fff8e9; + border-color: #ffbd2b; +} +div.note.warning::before { + color: #ffbd2b; + content: '\f12a'; +} +div.note.danger, +div.note.error { + background: #feefee; + border-color: #fe5f58; +} +div.note.danger::before, +div.note.error::before { + color: #fe5f58; + content: '\f00d'; +} +div.note.radiation::before { + content: '\f7b9'; +} +div.note.bug::before { + content: '\f188'; +} +div.note.idea::before { + content: '\f0eb'; +} +div.note.link::before { + content: '\f0c1'; +} +div.note.paperclip::before { + content: '\f0c6'; +} +div.note.todo::before { + content: '\f0ae'; +} +div.note.message::before { + content: '\f4ad'; +} +div.note.guide::before { + content: '\f277'; +} +div.note.download::before { + content: '\f019'; +} +div.note.up::before { + content: '\f102'; +} +div.note.undo::before { + content: '\f2ea'; +} +div.note.play::before { + content: '\f144'; +} +div.note.clear { + background: none; + border-color: none; +} +div.note.light { + background: #f5f5f5; + border-color: #a1a1a1; +} +div.note.light::before { + color: #a1a1a1; +} +div.note.gray { + background: #f5f5f5; + border-color: #696969; +} +div.note.gray::before { + color: #696969; +} +div.note.theme { + background: #ebfbf7; + border-color: #3dd9b6; +} +div.note.theme::before { + color: #3dd9b6; +} +div.note.red { + background: #feefee; + border-color: #fe5f58; +} +div.note.red::before { + color: #fe5f58; +} +div.note.yellow { + background: #fff8e9; + border-color: #ffbd2b; +} +div.note.yellow::before { + color: #ffbd2b; +} +div.note.green { + background: #ebf9ed; + border-color: #3dc550; +} +div.note.green::before { + color: #3dc550; +} +div.note.cyan { + background: #e8fafe; + border-color: #1bcdfc; +} +div.note.cyan::before { + color: #1bcdfc; +} +div.note.blue { + background: #e8f4fd; + border-color: #2196f3; +} +div.note.blue::before { + color: #2196f3; +} +.sites-wrap .group-header { + margin: 0 0 1rem; +} +.sites-wrap .group-header p { + margin: 0; + font-size: 0.875rem; +} +.sites-wrap .group-header p:first-child { + font-size: 1.25rem; + font-weight: 500; +} +.sites-wrap .group-body { + width: 100%; + margin-bottom: 2rem; +} +.sites-wrap .sitesjs-wrap { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; +} +.sites-wrap .sitesjs-wrap .loading-wrap { + min-height: 50px; + margin: 2rem 0; + text-align: center; +} +.sites-wrap .group-body { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: grid; + grid-gap: 1rem 1rem; + grid-template-columns: repeat(auto-fill, calc((100% - 3 * 1rem) / 4)); + margin-bottom: 2rem; +} +@media screen and (max-width: 1024px) { + .sites-wrap .group-body { + grid-template-columns: repeat(auto-fill, calc((100% - 2 * 1rem) / 3)); + } +} +@media screen and (max-width: 900px) { + .sites-wrap .group-body { + grid-template-columns: repeat(auto-fill, calc((100% - 1 * 1rem) / 2)); + } +} +@media screen and (max-width: 768px) { + .sites-wrap .group-body { + grid-template-columns: repeat(auto-fill, calc((100% - 2 * 1rem) / 3)); + } +} +@media screen and (max-width: 500px) { + .sites-wrap .group-body { + grid-template-columns: repeat(auto-fill, calc((100% - 1 * 1rem) / 2)); + } +} +.sites-wrap .group-body .site-card .card-link { + width: 100%; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; +} +.sites-wrap .group-body .site-card .card-link >img { + width: 100%; + height: 120px; + border-radius: 4px; + -webkit-border-radius: 4px; + object-fit: cover; + box-shadow: 0 1px 2px 0px rgba(0,0,0,0.2); + -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.2); +} +@media screen and (max-width: 1024px) { + .sites-wrap .group-body .site-card .card-link >img { + height: 150px; + } +} +@media screen and (max-width: 900px) { + .sites-wrap .group-body .site-card .card-link >img { + height: 180px; + } +} +@media screen and (max-width: 768px) { + .sites-wrap .group-body .site-card .card-link >img { + height: 150px; + } +} +.sites-wrap .group-body .site-card .card-link .info { + margin-top: 0.5rem; + line-height: 1.2; +} +.sites-wrap .group-body .site-card .card-link .info >img { + width: 28px; + height: 28px; + border-radius: 28px; + -webkit-border-radius: 28px; + float: left; + margin-right: 8px; + margin-top: 2px; +} +.sites-wrap .group-body .site-card .card-link .info span { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; +} +.sites-wrap .group-body .site-card .card-link .info .title { + font-weight: 500; + color: var(--text-p1); + font-size: 0.875rem; + margin-top: 1px; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; + -webkit-line-clamp: 1; +} +.sites-wrap .group-body .site-card .card-link .info .desc { + font-size: 10px; + margin-top: 2px; + word-wrap: break-word; + color: var(--text-p3); + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; + -webkit-line-clamp: 2; +} +.sites-wrap .site-card .card-link >img { + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +.sites-wrap .site-card .card-link:hover >img { + box-shadow: 0 4px 8px 0px rgba(0,0,0,0.1), 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 4px 8px 0px rgba(0,0,0,0.1), 0 2px 4px 0px rgba(0,0,0,0.1), 0 4px 8px 0px rgba(0,0,0,0.1), 0 8px 16px 0px rgba(0,0,0,0.1); +} +p.p.subtitle { + font-weight: bold; + color: #3eb399; + font-size: 1.25rem !important; + padding-top: 1.5rem; +} +p.p.subtitle:first-child { + padding-top: 1rem; +} +span.p.logo, +p.p.logo { + font-family: HFSnakylines, "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Helvetica, monospace; +} +span.p.code, +p.p.code { + font-family: JetbrainsMono, "PingFang SC", "Microsoft YaHei", Helvetica, Arial, monospace, courier, sans-serif; +} +span.p.left, +p.p.left { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + text-align: left; +} +span.p.center, +p.p.center { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + text-align: center; +} +span.p.right, +p.p.right { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + text-align: right; +} +span.p.small, +p.p.small { + font-size: 0.875rem; +} +span.p.large, +p.p.large { + font-size: 2.5rem; + line-height: 1.4; +} +span.p.huge, +p.p.huge { + font-size: 4rem; + line-height: 1.4; +} +span.p.ultra, +p.p.ultra { + font-size: 6rem; + line-height: 1.4; +} +span.p.small, +p.p.small, +span.p.large, +p.p.large, +span.p.huge, +p.p.huge, +span.p.ultra, +p.p.ultra { + margin: 0; + padding: 0; +} +span.p.bold, +p.p.bold { + font-weight: bold; +} +span.p.h1, +p.p.h1, +span.p.h2, +p.p.h2 { + padding-bottom: 0.2rem; + font-weight: 500; +} +span.p.h1, +p.p.h1 { + font-size: 1.5rem; + color: var(--color-h1); + padding-top: 2em; +} +span.p.h2, +p.p.h2 { + font-size: 1.5rem; + color: var(--color-h2); + padding-top: 2em; + border-bottom: 1px solid rgba(68,68,68,0.1); +} +span.p.h3, +p.p.h3 { + font-size: 1.25rem; + color: var(--color-h3); + padding-top: 2em; +} +span.p.h4, +p.p.h4 { + font-size: 1.125rem; + color: var(--color-h4); + padding-top: 2em; +} +span.p.h5, +p.p.h5 { + font-size: 1rem; + color: var(--color-h5); + padding-top: 1.5em; +} +span.p.red, +p.p.red { + color: #fe5f58; +} +span.p.yellow, +p.p.yellow { + color: #ffbd2b; +} +span.p.green, +p.p.green { + color: #3dc550; +} +span.p.cyan, +p.p.cyan { + color: #1bcdfc; +} +span.p.blue, +p.p.blue { + color: #2196f3; +} +span.p.purple, +p.p.purple { + color: #9c27b0; +} +span.p.gray, +p.p.gray { + color: #999; +} +.swiper-container { + width: 100%; + border-radius: 4px; + -webkit-border-radius: 4px; + --gap-p: 2rem; +} +.swiper-container:not(.swiper-container-initialized) { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; +} +div.swiper-slide { + text-align: center; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -webkit-box; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -webkit-flex; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + align-self: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + width: 50%; +} +div.swiper-slide img { + border-radius: 4px; + -webkit-border-radius: 4px; +} +.swiper-container[width='max'] div.swiper-slide { + width: 100%; +} +.swiper-container[width='min'] div.swiper-slide { + width: 25%; +} +.swiper-button-prev, +.swiper-button-next { + padding: 1rem 0.5rem; + margin-top: -2rem !important; + border-radius: 4px; + -webkit-border-radius: 4px; + background: rgba(255,255,255,0.25); + transition: background 0.2s ease-out; + -webkit-transition: background 0.2s ease-out; + -khtml-transition: background 0.2s ease-out; + -moz-transition: background 0.2s ease-out; + -o-transition: background 0.2s ease-out; + -ms-transition: background 0.2s ease-out; + --swiper-theme-color: #000 !important; +} +.swiper-button-prev:after, +.swiper-button-next:after { + font-size: 1.2rem !important; + font-weight: 700 !important; +} +.swiper-button-prev:hover, +.swiper-button-next:hover { + background: #fff !important; + --swiper-theme-color: #ff5722 !important; +} +.md .table { + overflow: auto; + margin-top: 1em; + margin-bottom: 1em; +} +.md .table table { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: table; + width: 100%; +} +div.tabs { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + position: relative; + margin-top: 1em; + margin-bottom: 1em; + border-radius: 4px; + -webkit-border-radius: 4px; + background: var(--color-card); + border: 1px solid rgba(68,68,68,0.2); + font-size: 0.9375rem; +} +div.tabs .highlight, +div.tabs p, +div.tabs ul, +div.tabs ol, +div.tabs div.note, +div.tabs details { + margin-top: 1em; + margin-bottom: 1em; +} +div.tabs ul.nav-tabs { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + overflow-x: auto; + white-space: nowrap; + justify-content: flex-start; + -webkit-justify-content: flex-start; + -khtml-justify-content: flex-start; + -moz-justify-content: flex-start; + -o-justify-content: flex-start; + -ms-justify-content: flex-start; + margin: 0 !important; + padding: 8px 8px 0 8px; + background: var(--color-block); + border-radius: 4px 4px 0 0; + -webkit-border-radius: 4px 4px 0 0; + line-height: 1.5; +} +div.tabs ul.nav-tabs li.tab { + list-style-type: none; + margin-top: 0; + margin-bottom: 0; +} +div.tabs ul.nav-tabs li.tab:last-child { + padding-right: 16px; +} +div.tabs ul.nav-tabs li.tab a { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + cursor: pointer; + border-radius: 4px 4px 0 0; + -webkit-border-radius: 4px 4px 0 0; + padding: 8px; + text-align: center; + font-size: 0.875rem; + line-height: inherit; + font-weight: bold; + color: var(--color-meta); + border: 1px solid transparent; +} +div.tabs ul.nav-tabs li.tab a:hover { + color: var(--color-p); +} +div.tabs ul.nav-tabs li.tab a i { + pointer-events: none; +} +div.tabs ul.nav-tabs li.tab.active a { + cursor: default; + color: var(--color-p); + background: #fff; + border: 1px solid rgba(68,68,68,0.2); + border-bottom: 1px solid var(--color-card); +} +div.tabs .tab-content { + border-top: 1px solid rgba(68,68,68,0.2); + margin-top: -1px; +} +div.tabs .tab-content .tab-pane { + padding: 16px; +} +div.tabs .tab-content .tab-pane:not(.active) { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; +} +div.tabs .tab-content .tab-pane.active { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; +} +div.tabs .tab-content .tab-pane > p:first-child, +div.tabs .tab-content .tab-pane > .tabs:first-child, +div.tabs .tab-content .tab-pane > ul:first-child, +div.tabs .tab-content .tab-pane > ol:first-child, +div.tabs .tab-content .tab-pane > .highlight:first-child, +div.tabs .tab-content .tab-pane > .note:first-child { + margin-top: 0; +} +div.tabs .tab-content .tab-pane > p:last-child, +div.tabs .tab-content .tab-pane > .tabs:last-child, +div.tabs .tab-content .tab-pane > ul:last-child, +div.tabs .tab-content .tab-pane > ol:last-child, +div.tabs .tab-content .tab-pane > .highlight:last-child, +div.tabs .tab-content .tab-pane > .note:last-child { + margin-bottom: 0; +} +.article del { + color: #8e8e8e; + text-decoration-color: #8e8e8e; +} +.article u { + color: var(--color-text); + text-decoration: none; + border-bottom: 1px solid #fe5f58; +} +.article emp { + color: var(--color-text); + border-bottom: 4px dotted #fe5f58; +} +.article wavy { + color: var(--color-text); + text-decoration-style: wavy; + text-decoration-line: underline; + text-decoration-color: #fe5f58; +} +.article psw { + color: transparent; + background: #a1a1a1; + border-radius: 2px; + -webkit-border-radius: 2px; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +.article psw:hover { + color: var(--color-p); + background: none; +} +.article kbd { + border-radius: 4px; + -webkit-border-radius: 4px; + border: 1px solid #d2d2d2; + border-bottom-width: 2px; + background: #fafafa; + padding-left: 4px; + padding-right: 4px; +} +div.timenode { + position: relative; +} +div.timenode:before, +div.timenode:after { + content: ''; + z-index: 1; + position: absolute; + background: rgba(61,217,182,0.5); + width: 2px; + left: 7px; +} +div.timenode:before { + top: 0px; + height: 6px; +} +div.timenode:after { + top: 26px; + height: calc(100% - 26px); +} +div.timenode:last-child:after { + height: calc(100% - 26px - 16px); + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; +} +div.timenode .meta, +div.timenode .body { + max-width: calc(100% - 24px); +} +div.timenode .meta { + position: relative; + color: var(--color-meta); + font-size: 0.875rem; + line-height: 32px; + height: 32px; +} +div.timenode .meta:before, +div.timenode .meta:after { + content: ''; + position: absolute; + top: 8px; + z-index: 2; +} +div.timenode .meta:before { + background: rgba(61,217,182,0.5); + width: 16px; + height: 16px; + border-radius: 8px; + -webkit-border-radius: 8px; +} +div.timenode .meta:after { + background: #3dd9b6; + margin-left: 2px; + margin-top: 2px; + width: 12px; + height: 12px; + border-radius: 6px; + -webkit-border-radius: 6px; + transform: scale(0.5); + -webkit-transform: scale(0.5); + -khtml-transform: scale(0.5); + -moz-transform: scale(0.5); + -o-transform: scale(0.5); + -ms-transform: scale(0.5); + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +div.timenode .meta p { + font-weight: bold; + margin: 0 0 0 24px; +} +div.timenode .body { + margin: 4px 0 16px 24px; + padding: 16px; + border-radius: 8px; + -webkit-border-radius: 8px; + background: var(--color-block); + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; +} +div.timenode .body:empty { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; +} +div.timenode .body >*:first-child { + margin-top: 0.25em; +} +div.timenode .body >*:last-child { + margin-bottom: 0.25em; +} +div.timenode .body .highlight { + border: 1px solid #e4e4e4; +} +div.timenode:hover .meta { + color: var(--color-text); +} +div.timenode:hover .meta:before { + background: rgba(255,87,34,0.5); +} +div.timenode:hover .meta:after { + background: #ff5722; + transform: scale(1); + -webkit-transform: scale(1); + -khtml-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); +} +.article mjx-container { + font-family: JetbrainsMono, "PingFang SC", "Microsoft YaHei", Helvetica, Arial, monospace, courier, sans-serif; + padding: 16px 8px; + border-radius: 4px; + -webkit-border-radius: 4px; + min-width: 0 !important; +} +.article mjx-container[jax="CHTML"][display="true"], +.article .has-jax { + overflow: auto hidden; +} +.article mjx-container + br { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; +} +.fa.red, +.fas.red, +.far.red, +.fad.red, +.fal.red, +.fa-solid.red, +.fa-regular.red, +.fa-duotone.red, +.fa-light.red, +.fa-thin.red, +.iziToast>.iziToast-body .iziToast-icon.red { + color: #f44336; +} +.fa.pink, +.fas.pink, +.far.pink, +.fad.pink, +.fal.pink, +.fa-solid.pink, +.fa-regular.pink, +.fa-duotone.pink, +.fa-light.pink, +.fa-thin.pink, +.iziToast>.iziToast-body .iziToast-icon.pink { + color: #e91e63; +} +.fa.purple, +.fas.purple, +.far.purple, +.fad.purple, +.fal.purple, +.fa-solid.purple, +.fa-regular.purple, +.fa-duotone.purple, +.fa-light.purple, +.fa-thin.purple, +.iziToast>.iziToast-body .iziToast-icon.purple { + color: #9c27b0; +} +.fa.indigo, +.fas.indigo, +.far.indigo, +.fad.indigo, +.fal.indigo, +.fa-solid.indigo, +.fa-regular.indigo, +.fa-duotone.indigo, +.fa-light.indigo, +.fa-thin.indigo, +.iziToast>.iziToast-body .iziToast-icon.indigo { + color: #3f51b5; +} +.fa.light-blue, +.fas.light-blue, +.far.light-blue, +.fad.light-blue, +.fal.light-blue, +.fa-solid.light-blue, +.fa-regular.light-blue, +.fa-duotone.light-blue, +.fa-light.light-blue, +.fa-thin.light-blue, +.iziToast>.iziToast-body .iziToast-icon.light-blue { + color: #4ba7ee; +} +.fa.deep-blue, +.fas.deep-blue, +.far.deep-blue, +.fad.deep-blue, +.fal.deep-blue, +.fa-solid.deep-blue, +.fa-regular.deep-blue, +.fa-duotone.deep-blue, +.fa-light.deep-blue, +.fa-thin.deep-blue, +.iziToast>.iziToast-body .iziToast-icon.deep-blue { + color: #3367d6; +} +.fa.teal, +.fas.teal, +.far.teal, +.fad.teal, +.fal.teal, +.fa-solid.teal, +.fa-regular.teal, +.fa-duotone.teal, +.fa-light.teal, +.fa-thin.teal, +.iziToast>.iziToast-body .iziToast-icon.teal { + color: #009688; +} +.fa.light-green, +.fas.light-green, +.far.light-green, +.fad.light-green, +.fal.light-green, +.fa-solid.light-green, +.fa-regular.light-green, +.fa-duotone.light-green, +.fa-light.light-green, +.fa-thin.light-green, +.iziToast>.iziToast-body .iziToast-icon.light-green { + color: #8bc34a; +} +.fa.orange, +.fas.orange, +.far.orange, +.fad.orange, +.fal.orange, +.fa-solid.orange, +.fa-regular.orange, +.fa-duotone.orange, +.fa-light.orange, +.fa-thin.orange, +.iziToast>.iziToast-body .iziToast-icon.orange { + color: #ff9800; +} +.fa.deep-orange, +.fas.deep-orange, +.far.deep-orange, +.fad.deep-orange, +.fal.deep-orange, +.fa-solid.deep-orange, +.fa-regular.deep-orange, +.fa-duotone.deep-orange, +.fa-light.deep-orange, +.fa-thin.deep-orange, +.iziToast>.iziToast-body .iziToast-icon.deep-orange { + color: #ff5722; +} +.fa.brown, +.fas.brown, +.far.brown, +.fad.brown, +.fal.brown, +.fa-solid.brown, +.fa-regular.brown, +.fa-duotone.brown, +.fa-light.brown, +.fa-thin.brown, +.iziToast>.iziToast-body .iziToast-icon.brown { + color: #795548; +} +.fa.blue-grey, +.fas.blue-grey, +.far.blue-grey, +.fad.blue-grey, +.fal.blue-grey, +.fa-solid.blue-grey, +.fa-regular.blue-grey, +.fa-duotone.blue-grey, +.fa-light.blue-grey, +.fa-thin.blue-grey, +.iziToast>.iziToast-body .iziToast-icon.blue-grey { + color: #607d8b; +} +.fa.yellow, +.fas.yellow, +.far.yellow, +.fad.yellow, +.fal.yellow, +.fa-solid.yellow, +.fa-regular.yellow, +.fa-duotone.yellow, +.fa-light.yellow, +.fa-thin.yellow, +.iziToast>.iziToast-body .iziToast-icon.yellow { + color: #fcec60; +} +.fa.TURQUOISE, +.fas.TURQUOISE, +.far.TURQUOISE, +.fad.TURQUOISE, +.fal.TURQUOISE, +.fa-solid.TURQUOISE, +.fa-regular.TURQUOISE, +.fa-duotone.TURQUOISE, +.fa-light.TURQUOISE, +.fa-thin.TURQUOISE, +.iziToast>.iziToast-body .iziToast-icon.TURQUOISE { + color: #1abc9c; +} +.fa.EMERALD, +.fas.EMERALD, +.far.EMERALD, +.fad.EMERALD, +.fal.EMERALD, +.fa-solid.EMERALD, +.fa-regular.EMERALD, +.fa-duotone.EMERALD, +.fa-light.EMERALD, +.fa-thin.EMERALD, +.iziToast>.iziToast-body .iziToast-icon.EMERALD { + color: #2ecc71; +} +.fa.PETERRIVE, +.fas.PETERRIVE, +.far.PETERRIVE, +.fad.PETERRIVE, +.fal.PETERRIVE, +.fa-solid.PETERRIVE, +.fa-regular.PETERRIVE, +.fa-duotone.PETERRIVE, +.fa-light.PETERRIVE, +.fa-thin.PETERRIVE, +.iziToast>.iziToast-body .iziToast-icon.PETERRIVE { + color: #3498db; +} +.fa.AMETHYST, +.fas.AMETHYST, +.far.AMETHYST, +.fad.AMETHYST, +.fal.AMETHYST, +.fa-solid.AMETHYST, +.fa-regular.AMETHYST, +.fa-duotone.AMETHYST, +.fa-light.AMETHYST, +.fa-thin.AMETHYST, +.iziToast>.iziToast-body .iziToast-icon.AMETHYST { + color: #9b59b6; +} +.fa.WETASPHALT, +.fas.WETASPHALT, +.far.WETASPHALT, +.fad.WETASPHALT, +.fal.WETASPHALT, +.fa-solid.WETASPHALT, +.fa-regular.WETASPHALT, +.fa-duotone.WETASPHALT, +.fa-light.WETASPHALT, +.fa-thin.WETASPHALT, +.iziToast>.iziToast-body .iziToast-icon.WETASPHALT { + color: #34495e; +} +.fa.GREENSEA, +.fas.GREENSEA, +.far.GREENSEA, +.fad.GREENSEA, +.fal.GREENSEA, +.fa-solid.GREENSEA, +.fa-regular.GREENSEA, +.fa-duotone.GREENSEA, +.fa-light.GREENSEA, +.fa-thin.GREENSEA, +.iziToast>.iziToast-body .iziToast-icon.GREENSEA { + color: #16a085; +} +.fa.NEPHRITIS, +.fas.NEPHRITIS, +.far.NEPHRITIS, +.fad.NEPHRITIS, +.fal.NEPHRITIS, +.fa-solid.NEPHRITIS, +.fa-regular.NEPHRITIS, +.fa-duotone.NEPHRITIS, +.fa-light.NEPHRITIS, +.fa-thin.NEPHRITIS, +.iziToast>.iziToast-body .iziToast-icon.NEPHRITIS { + color: #27ae60; +} +.fa.BELIZEHOLE, +.fas.BELIZEHOLE, +.far.BELIZEHOLE, +.fad.BELIZEHOLE, +.fal.BELIZEHOLE, +.fa-solid.BELIZEHOLE, +.fa-regular.BELIZEHOLE, +.fa-duotone.BELIZEHOLE, +.fa-light.BELIZEHOLE, +.fa-thin.BELIZEHOLE, +.iziToast>.iziToast-body .iziToast-icon.BELIZEHOLE { + color: #2980b9; +} +.fa.WISTERIA, +.fas.WISTERIA, +.far.WISTERIA, +.fad.WISTERIA, +.fal.WISTERIA, +.fa-solid.WISTERIA, +.fa-regular.WISTERIA, +.fa-duotone.WISTERIA, +.fa-light.WISTERIA, +.fa-thin.WISTERIA, +.iziToast>.iziToast-body .iziToast-icon.WISTERIA { + color: #8e44ad; +} +.fa.MIDNIGHTBLUE, +.fas.MIDNIGHTBLUE, +.far.MIDNIGHTBLUE, +.fad.MIDNIGHTBLUE, +.fal.MIDNIGHTBLUE, +.fa-solid.MIDNIGHTBLUE, +.fa-regular.MIDNIGHTBLUE, +.fa-duotone.MIDNIGHTBLUE, +.fa-light.MIDNIGHTBLUE, +.fa-thin.MIDNIGHTBLUE, +.iziToast>.iziToast-body .iziToast-icon.MIDNIGHTBLUE { + color: #2c3e50; +} +.fa.SUNFLOWER, +.fas.SUNFLOWER, +.far.SUNFLOWER, +.fad.SUNFLOWER, +.fal.SUNFLOWER, +.fa-solid.SUNFLOWER, +.fa-regular.SUNFLOWER, +.fa-duotone.SUNFLOWER, +.fa-light.SUNFLOWER, +.fa-thin.SUNFLOWER, +.iziToast>.iziToast-body .iziToast-icon.SUNFLOWER { + color: #f1c40f; +} +.fa.CARROT, +.fas.CARROT, +.far.CARROT, +.fad.CARROT, +.fal.CARROT, +.fa-solid.CARROT, +.fa-regular.CARROT, +.fa-duotone.CARROT, +.fa-light.CARROT, +.fa-thin.CARROT, +.iziToast>.iziToast-body .iziToast-icon.CARROT { + color: #e67e22; +} +.fa.ALIZARIN, +.fas.ALIZARIN, +.far.ALIZARIN, +.fad.ALIZARIN, +.fal.ALIZARIN, +.fa-solid.ALIZARIN, +.fa-regular.ALIZARIN, +.fa-duotone.ALIZARIN, +.fa-light.ALIZARIN, +.fa-thin.ALIZARIN, +.iziToast>.iziToast-body .iziToast-icon.ALIZARIN { + color: #e74c3c; +} +.fa.CLOUDS, +.fas.CLOUDS, +.far.CLOUDS, +.fad.CLOUDS, +.fal.CLOUDS, +.fa-solid.CLOUDS, +.fa-regular.CLOUDS, +.fa-duotone.CLOUDS, +.fa-light.CLOUDS, +.fa-thin.CLOUDS, +.iziToast>.iziToast-body .iziToast-icon.CLOUDS { + color: #ecf0f1; +} +.fa.CONCRETE, +.fas.CONCRETE, +.far.CONCRETE, +.fad.CONCRETE, +.fal.CONCRETE, +.fa-solid.CONCRETE, +.fa-regular.CONCRETE, +.fa-duotone.CONCRETE, +.fa-light.CONCRETE, +.fa-thin.CONCRETE, +.iziToast>.iziToast-body .iziToast-icon.CONCRETE { + color: #95a5a6; +} +.fa.ORANGE, +.fas.ORANGE, +.far.ORANGE, +.fad.ORANGE, +.fal.ORANGE, +.fa-solid.ORANGE, +.fa-regular.ORANGE, +.fa-duotone.ORANGE, +.fa-light.ORANGE, +.fa-thin.ORANGE, +.iziToast>.iziToast-body .iziToast-icon.ORANGE { + color: #f39c12; +} +.fa.PUMPKIN, +.fas.PUMPKIN, +.far.PUMPKIN, +.fad.PUMPKIN, +.fal.PUMPKIN, +.fa-solid.PUMPKIN, +.fa-regular.PUMPKIN, +.fa-duotone.PUMPKIN, +.fa-light.PUMPKIN, +.fa-thin.PUMPKIN, +.iziToast>.iziToast-body .iziToast-icon.PUMPKIN { + color: #d35400; +} +.fa.POMEGRANATE, +.fas.POMEGRANATE, +.far.POMEGRANATE, +.fad.POMEGRANATE, +.fal.POMEGRANATE, +.fa-solid.POMEGRANATE, +.fa-regular.POMEGRANATE, +.fa-duotone.POMEGRANATE, +.fa-light.POMEGRANATE, +.fa-thin.POMEGRANATE, +.iziToast>.iziToast-body .iziToast-icon.POMEGRANATE { + color: #c0392b; +} +.fa.SILVER, +.fas.SILVER, +.far.SILVER, +.fad.SILVER, +.fal.SILVER, +.fa-solid.SILVER, +.fa-regular.SILVER, +.fa-duotone.SILVER, +.fa-light.SILVER, +.fa-thin.SILVER, +.iziToast>.iziToast-body .iziToast-icon.SILVER { + color: #bdc3c7; +} +.fa.ASBESTOS, +.fas.ASBESTOS, +.far.ASBESTOS, +.fad.ASBESTOS, +.fal.ASBESTOS, +.fa-solid.ASBESTOS, +.fa-regular.ASBESTOS, +.fa-duotone.ASBESTOS, +.fa-light.ASBESTOS, +.fa-thin.ASBESTOS, +.iziToast>.iziToast-body .iziToast-icon.ASBESTOS { + color: #7f8c8d; +} +.highlight { + position: relative; +} +.btn-copy { + z-index: 1; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: inline-block; + cursor: pointer; + border: none; + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -webkit-appearance: none; + font-family: Menlo, JetbrainsMono, "PingFang SC", "Microsoft YaHei", Helvetica, Arial, monospace, courier, sans-serif; + font-size: 11px; + font-weight: bold; + padding: 4px 8px; + color: var(--color-meta); + background: var(--color-block); + border-radius: 3px; + -webkit-border-radius: 3px; + box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + -webkit-box-shadow: 0 1px 2px 0px rgba(0,0,0,0.1); + position: absolute; + top: 1px; + right: 1px; + opacity: 0; + -webkit-opacity: 0; + -moz-opacity: 0; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +.btn-copy >i { + margin-right: 4px; +} +.btn-copy:hover { + color: #ff5722; + background: #ffeee8; +} +.highlight:hover .btn-copy { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; +} +.article pre:hover .btn-copy { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; +} +.hljs:before, +.highlight:before { + position: absolute; + top: 0; + right: 0; + color: var(--color-meta); + font-size: 13px; + padding: 4px 8px; +} +.hljs.md:before, +.highlight.md:before, +.hljs.markdown:before, +.highlight.markdown:before { + content: "md"; +} +.hljs.yaml:before, +.highlight.yaml:before { + content: "YAML"; +} +.hljs.json:before, +.highlight.json:before { + content: "JSON"; +} +.hljs.html:before, +.highlight.html:before { + content: "HTML"; +} +.hljs.js:before, +.highlight.js:before, +.hljs.javascript:before, +.highlight.javascript:before { + content: "JS"; +} +.hljs.css:before, +.highlight.css:before { + content: "CSS"; +} +.hljs.less:before, +.highlight.less:before { + content: "Less"; +} +.hljs.stylus:before, +.highlight.stylus:before { + content: "Stylus"; +} +.hljs.bash:before, +.highlight.bash:before { + content: "bash"; +} +.hljs.shell:before, +.highlight.shell:before { + content: "shell"; +} +.hljs.sh:before, +.highlight.sh:before { + content: "sh"; +} +.hljs.ini:before, +.highlight.ini:before { + content: "ini"; +} +.hljs.c:before, +.highlight.c:before { + content: "C"; +} +.hljs.cpp:before, +.highlight.cpp:before { + content: "C++"; +} +.hljs.objc:before, +.highlight.objc:before, +.hljs.objectivec:before, +.highlight.objectivec:before { + content: "Objective-C"; +} +.hljs.swift:before, +.highlight.swift:before { + content: "Swift"; +} +.hljs.java:before, +.highlight.java:before { + content: "Java"; +} +.hljs.python:before, +.highlight.python:before { + content: "Python"; +} +.hljs.php:before, +.highlight.php:before { + content: "PHP"; +} +.hljs.rust:before, +.highlight.rust:before { + content: "Rust"; +} +.hljs.sql:before, +.highlight.sql:before { + content: "SQL"; +} +.hljs.ruby:before, +.highlight.ruby:before { + content: "Ruby"; +} +.hljs.makefile:before, +.highlight.makefile:before { + content: "Makefile"; +} +.hljs.go:before, +.highlight.go:before { + content: "Go"; +} +.hljs.typescript:before, +.highlight.typescript:before { + content: "TypeScript"; +} +.highlight pre .line, +.highlight pre .params { + color: rgba(68,68,68,0.9); +} +.highlight pre .line .addition { + color: #3fa33f; +} +.highlight pre .line .deletion { + color: #ee2b29; +} +.highlight pre .marked { + background-color: rgba(254,213,66,0.4); + padding: 2px 8px 2px 0; + border-radius: 2px; + -webkit-border-radius: 2px; + width: 100%; +} +.highlight pre .title, +.highlight pre .attr, +.highlight pre .attribute { + color: #3f51b5; +} +.highlight pre .comment { + color: var(--color-meta); +} +.highlight pre .keyword, +.highlight pre .meta-keyword, +.highlight pre .javascript .function { + color: #9c27b0; +} +.highlight pre .type, +.highlight pre .built_in, +.highlight pre .tag .name { + color: #4ba7ee; +} +.highlight pre .variable, +.highlight pre .regexp, +.highlight pre .ruby .constant, +.highlight pre .xml .tag .title, +.highlight pre .xml .pi, +.highlight pre .xml .doctype, +.highlight pre .html .doctype, +.highlight pre .css .id, +.highlight pre .css .class, +.highlight pre .css .pseudo { + color: #fd8607; +} +.highlight pre .number, +.highlight pre .preprocessor, +.highlight pre .literal, +.highlight pre .constant { + color: #fd8607; +} +.highlight pre .class, +.highlight pre .ruby .class .title, +.highlight pre .css .rules .attribute { + color: #ff9800; +} +.highlight pre .string, +.highlight pre .meta-string { + color: #449e48; +} +.highlight pre .value, +.highlight pre .inheritance, +.highlight pre .header, +.highlight pre .ruby .symbol, +.highlight pre .xml .cdata { + color: #4caf50; +} +.highlight pre .css .hexcolor { + color: #6cc; +} +.highlight pre .function, +.highlight pre .python .decorator, +.highlight pre .python .title, +.highlight pre .ruby .function .title, +.highlight pre .ruby .title .keyword, +.highlight pre .perl .sub, +.highlight pre .javascript .title, +.highlight pre .coffeescript .title { + color: #69c; +} +.highlight.html .line .tag .name, +.highlight.css .line .tag .name, +.highlight.less .line .tag .name, +.highlight.stylus .line .tag .name, +.highlight.html .line .selector-tag, +.highlight.css .line .selector-tag, +.highlight.less .line .selector-tag, +.highlight.stylus .line .selector-tag { + color: #ee2b29; +} +.highlight.html .line .selector-class, +.highlight.css .line .selector-class, +.highlight.less .line .selector-class, +.highlight.stylus .line .selector-class, +.highlight.html .line .selector-attr, +.highlight.css .line .selector-attr, +.highlight.less .line .selector-attr, +.highlight.stylus .line .selector-attr { + color: #fd8607; +} +.highlight.html .line .attribute, +.highlight.css .line .attribute, +.highlight.less .line .attribute, +.highlight.stylus .line .attribute { + color: #3f51b5; +} +.highlight.html .line .number, +.highlight.css .line .number, +.highlight.less .line .number, +.highlight.stylus .line .number { + color: #17afca; +} +.highlight.objc .line .meta, +.highlight.objectivec .line .meta, +.highlight.swift .line .meta, +.highlight.c .line .meta { + color: #9c27b0; +} +.highlight.objc .line .meta-string, +.highlight.objectivec .line .meta-string, +.highlight.swift .line .meta-string, +.highlight.c .line .meta-string, +.highlight.objc .line .string, +.highlight.objectivec .line .string, +.highlight.swift .line .string, +.highlight.c .line .string { + color: #fb3f1b; +} +.highlight.objc .line .class, +.highlight.objectivec .line .class, +.highlight.swift .line .class, +.highlight.c .line .class { + color: rgba(68,68,68,0.9); +} +.highlight.objc .line .class .title, +.highlight.objectivec .line .class .title, +.highlight.swift .line .class .title, +.highlight.c .line .class .title { + color: #1e80f0; +} +.highlight.objc .line .comment, +.highlight.objectivec .line .comment, +.highlight.swift .line .comment, +.highlight.c .line .comment { + color: #3fa33f; +} +.highlight.json .line .attr { + color: #e24f5a; +} +.highlight.json .line .literal { + color: #3f51b5; +} +.highlight.yaml .line .attr { + color: #e24f5a; +} +pre { + position: relative; +} +.hljs { + margin: -16px !important; + padding: 16px !important; + -webkit-font-smoothing: auto; + -moz-osx-font-smoothing: auto; +} +.hljs::-webkit-scrollbar { + height: 4px; + width: 4px; +} +.hljs::-webkit-scrollbar-track-piece { + background: transparent; +} +.hljs::-webkit-scrollbar-thumb { + background: #3dd9b6; + cursor: pointer; + border-radius: 2px; + -webkit-border-radius: 2px; +} +.hljs::-webkit-scrollbar-thumb:hover { + background: #ff5722; +} +.highlight { + position: relative; + width: 100%; + margin: 1em 0; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + background: var(--color-block); + font-size: 0.8125rem; + font-family: JetbrainsMono, "PingFang SC", "Microsoft YaHei", Helvetica, Arial, monospace, courier, sans-serif; + border-radius: 4px; + -webkit-border-radius: 4px; + line-height: 1.5; + -webkit-font-smoothing: auto; + -moz-osx-font-smoothing: auto; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +.highlight:hover { + background: var(--color-codeblock); +} +.highlight:hover figcaption { + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + background: #ffeed2; +} +.highlight:hover .gutter { + background: #ffedd0; +} +.highlight figcaption { + font-size: 13px; + position: sticky; + left: 0; + padding: 4px 8px 4px 8px; + background: #eaeaea; + border-top-left-radius: calc(4px - 1px); + border-top-right-radius: calc(4px - 1px); +} +.highlight >table { + overflow: auto; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + margin: 0; + background-color: transparent; + border: none; +} +.highlight >table::-webkit-scrollbar { + height: 4px; + width: 4px; +} +.highlight >table::-webkit-scrollbar-track-piece { + background: transparent; +} +.highlight >table::-webkit-scrollbar-thumb { + background: transparent; + cursor: pointer; + border-radius: 4px; + -webkit-border-radius: 4px; +} +.highlight >table:hover::-webkit-scrollbar-thumb { + background: rgba(68,68,68,0.5); +} +.highlight >table:hover::-webkit-scrollbar-thumb:hover { + background: #ff5722; +} +.highlight >table td, +.highlight >table th { + padding: 0; + border: none; + line-height: 1.5; +} +.highlight >table tr { + background-color: transparent; +} +.highlight >table tr:hover { + background-color: transparent; +} +.highlight >table pre { + overflow-y: hidden; +} +.highlight >table .gutter { + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + padding: 0 12px; + text-align: right; + border-width: 0; + margin-left: 0; + position: sticky; + left: 0; + z-index: 1; + background: #e9e9e9; +} +.highlight >table .gutter pre { + color: var(--color-meta); +} +.highlight >table pre { + background: transparent; + margin: 0; + padding: 0; + border: none; +} +.highlight >table pre .code:before { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; +} +.highlight >table .code { + padding: 20px 16px; + vertical-align: top; + background-color: transparent; +} +.highlight >table .code:before { + content: ""; + position: absolute; + top: 0; + right: 0; + color: var(--color-meta); + font-size: 13px; + padding: 4px 8px; +} +.iziToast-texts { + max-width: 300px !important; + min-width: 200px !important; +} +@media screen and (max-width: 500px) { + .iziToast-texts { + max-width: unset !important; + min-width: unset !important; + } +} +.iziToast-title { + margin-bottom: 6px !important; + font-size: 1rem !important; +} +.iziToast-message { + word-break: break-all !important; +} +@media screen and (max-width: 500px) { + .l_header .list-v .aplayer, + .l_header .list-v .aplayer-pic { + border-radius: 4px; + -webkit-border-radius: 4px; + width: 64px; + height: 64px; + } +} +.aplayer-container { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + justify-content: center; + -webkit-justify-content: center; + -khtml-justify-content: center; + -moz-justify-content: center; + -o-justify-content: center; + -ms-justify-content: center; + min-height: 100px; +} +.aplayer-container meting-js { + max-width: 100%; +} +.aplayer { + max-width: 500px; + border-radius: 4px; + -webkit-border-radius: 4px; + color: var(--color-text); + font-family: HYJiangJunJ, "PingFang SC", "Microsoft YaHei", Helvetica, Arial, Menlo, Monaco, monospace, sans-serif; +} +.aplayer .aplayer-list { + text-align: left; +} +@media screen and (max-width: 500px) { + .aplayer { + border-radius: 8px; + -webkit-border-radius: 8px; + } +} +.l_header .aplayer-volume-wrap { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none !important; +} +.aplayer.aplayer-fixed.aplayer-narrow .aplayer-body { + left: -66px !important; +} +.aplayer.aplayer-fixed.aplayer-narrow .aplayer-body:hover { + left: 0px !important; +} +p, +input, +pre>span, +textarea { + cursor: url("https://unpkg.com/volantis-static@0.0.1660614606622/media/cursor/text.png"), text; +} +.fancybox-container .fancybox-stage, +.fancybox__carousel .is-draggable { + cursor: url("https://unpkg.com/volantis-static@0.0.1660614606622/media/cursor/zoom-out.png"), zoom-out; +} +.fancybox a, +.fancybox-can-zoomIn .fancybox-content, +.fancybox__carousel .fancybox__slide.can-zoom_in .fancybox__content { + cursor: url("https://unpkg.com/volantis-static@0.0.1660614606622/media/cursor/zoom-in.png"), zoom-in; +} +span.btn>a:not([href]):hover, +.fancybox-button[disabled], +.fancybox-button[disabled]:hover, +.gt-container .gt-btn.is--disable, +span.not-select { + cursor: url("https://unpkg.com/volantis-static@0.0.1660614606622/media/cursor/circle.png"), not-allowed; +} +html, +a:not([href]), +a:not([href]) p, +button[disabled], +html input[disabled], +.article .widget, +#l_body .post section.meta .new-meta-box .new-meta-item .notlink, +ul.list-v.rightmenu a, +span.btn a:not([href]), +div.tabs ul.nav-tabs li.tab.active a, +kbd, +.a > p, +.not-select, +.not-select p, +.aplayer .aplayer-info .aplayer-music, +.gt-container a.is--active, +.iziToast, +.iziToast p, +.iframe, +.embed-show, +p > img, +p > svg, +.fix-cursor-default { + cursor: url("https://unpkg.com/volantis-static@0.0.1660614606622/media/cursor/left_ptr.png"), default; +} +a, +psw, +button, +html input[type=button], +input[type=reset], +input[type=submit], +table::-webkit-scrollbar-thumb, +scrollbar::-webkit-scrollbar-thumb, +#scroll-down, +ul.list-v.rightmenu li.music a.nav.volume .aplayer-volume-bar, +#u-search .modal .modal-header .btn-close, +#u-search .modal .modal-footer .nav, +article .checkbox input, +details summary, +.article a.link-card, +div.tabs ul.nav-tabs li.tab a, +.btn-copy, +.fancybox-can-pan .fancybox-content, +.fancybox-can-swipe .fancybox-content, +.waves-effect, +a.result.search-result-fix, +.tag > p, +.prev > p, +.next > p, +.author > p, +.list-h > a > p, +.category > a > p, +.friend-right p, +.v[data-class=v] a, +.v[data-class=v] .vbtn, +.v[data-class=v] .vicon, +.v[data-class=v] .vcards .vcard .vhead .vnick, +.v[data-class=v] .vcards .vcard .vh .vmeta .vat, +.v[data-class=v] .vwrap .vemojis i, +.v[data-class=v] .vcards .vcard .vcontent.expand, +.aplayer .aplayer-pic, +.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon, +.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap, +.aplayer .aplayer-list ol li, +.aplayer .aplayer-list ol li .aplayer-list-author, +.aplayer .aplayer-list ol li .aplayer-list-index, +.waves-button, +.waves-button-input, +.waves-button:hover, +.waves-button:visited, +.fancybox-button, +.gt-container .gt-btn, +.gt-container .gt-user-inner, +.gt-container .gt-avatar-github, +.gt-container .gt-popup .gt-action, +.gt-container .gt-comment-like:hover, +.gt-container .gt-comment-edit:hover, +.gt-container .gt-comment-reply:hover, +.tk-icon, +.tk-avatar img, +.tk-meta a, +.tk-action-icon, +.fancybox, +.fix-cursor-pointer { + cursor: url("https://unpkg.com/volantis-static@0.0.1660614606622/media/cursor/pointer.png"), pointer; +} +.cur-default { + cursor: url("https://unpkg.com/volantis-static@0.0.1660614606622/media/cursor/left_ptr.png"), default !important; +} +.cur-pointer, +.carousel__button, +.fancybox__slide { + cursor: url("https://unpkg.com/volantis-static@0.0.1660614606622/media/cursor/pointer.png"), pointer !important; +} +.cur-not-allowed { + cursor: url("https://unpkg.com/volantis-static@0.0.1660614606622/media/cursor/circle.png"), not-allowed !important; +} +.cur-zoom-in, +.fancybox__carousel .fancybox__slide.can-zoom_in .fancybox__content, +.has-image[data-image-fit=contain].can-zoom_in .fancybox__image { + cursor: url("https://unpkg.com/volantis-static@0.0.1660614606622/media/cursor/zoom-in.png"), zoom-in !important; +} +.cur-zoom-out, +.fancybox__carousel .is-draggable, +.has-image[data-image-fit=contain].is-draggable .fancybox__image { + cursor: url("https://unpkg.com/volantis-static@0.0.1660614606622/media/cursor/zoom-out.png"), zoom-out !important; +} +.cur-text { + cursor: url("https://unpkg.com/volantis-static@0.0.1660614606622/media/cursor/text.png"), text !important; +} +.common_read { + z-index: auto !important; + opacity: 1 !important; + -webkit-opacity: 1 !important; + -moz-opacity: 1 !important; + overflow: visible !important; + transform: none !important; + -webkit-transform: none !important; + -khtml-transform: none !important; + -moz-transform: none !important; + -o-transform: none !important; + -ms-transform: none !important; + animation: none !important; + -webkit-animation: none !important; + -khtml-animation: none !important; + -moz-animation: none !important; + -o-animation: none !important; + -ms-animation: none !important; + position: relative !important; +} +.body-wrapper.common_read { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; +} +#safearea.common_read { + padding-bottom: 16px; +} +@media screen and (max-width: 900px) { + #safearea.common_read { + padding: 0; + margin: 0; + } +} +#l_body.common_read { + z-index: 2147483646 !important; +} +.read_cover { + min-height: 10px !important; +} +@media screen and (max-width: 900px) { + .read_cover { + min-height: 0 !important; + } +} +.common_read_bkg { + background-color: var(--color-read-bkg) !important; + opacity: 1 !important; + -webkit-opacity: 1 !important; + -moz-opacity: 1 !important; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block !important; + position: fixed !important; + top: 0 !important; + left: 0 !important; + right: 0 !important; + bottom: 0 !important; + z-index: 2147483645 !important; + transition: opacity 1s cubic-bezier(0.23, 1, 0.32, 1) 0ms !important; + -webkit-transition: opacity 1s cubic-bezier(0.23, 1, 0.32, 1) 0ms !important; + -khtml-transition: opacity 1s cubic-bezier(0.23, 1, 0.32, 1) 0ms !important; + -moz-transition: opacity 1s cubic-bezier(0.23, 1, 0.32, 1) 0ms !important; + -o-transition: opacity 1s cubic-bezier(0.23, 1, 0.32, 1) 0ms !important; + -ms-transition: opacity 1s cubic-bezier(0.23, 1, 0.32, 1) 0ms !important; +} +.common_read_hide { + opacity: 0 !important; + -webkit-opacity: 0 !important; + -moz-opacity: 0 !important; + z-index: -2147483645 !important; +} +.common_read_main { + width: 840px !important; + padding: 0 !important; + margin: 0 auto; + float: initial !important; +} +@media screen and (max-width: 900px) { + .common_read_main { + width: auto !important; + } +} +.post_read { + background-color: var(--color-read-post) !important; + z-index: 2147483646 !important; + overflow: visible !important; + font-size: 1.15rem !important; + border-radius: 0 !important; + -webkit-border-radius: 0 !important; + box-shadow: 0 6px 12px 3px rgba(0,0,0,0.2); + -webkit-box-shadow: 0 6px 12px 3px rgba(0,0,0,0.2); +} +div#rightmenu-wrapper { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: none; + position: fixed; + z-index: 2147483648; + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} +ul.list-v.rightmenu { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + max-width: 240px; + overflow: hidden; +} +ul.list-v.rightmenu.left { + right: 0; +} +ul.list-v.rightmenu.top { + bottom: 0; +} +ul.list-v.rightmenu a { + cursor: default; +} +ul.list-v.rightmenu a.vlts-menu { + text-overflow: ellipsis; + overflow: hidden; + line-height: 32px; + font-weight: normal; +} +ul.list-v.rightmenu >li>span { + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: block; + color: var(--color-list); + font-size: 0.875rem; + line-height: 36px; + padding: 0 20px 0 16px; + text-overflow: ellipsis; + margin: 0 4px; + border-radius: 4px; + -webkit-border-radius: 4px; +} +@media screen and (max-width: 1024px) { + ul.list-v.rightmenu >li>span { + line-height: 40px; + } +} +ul.list-v.rightmenu >li>span >i { + margin-right: 8px; +} +ul.list-v.rightmenu >li>span:active, +ul.list-v.rightmenu >li>span.active { + color: var(--color-list-hl); +} +ul.list-v.rightmenu >li>span:hover { + color: var(--color-list-hl); + background: var(--color-site-bg); +} +ul.list-v.rightmenu li.navigation, +ul.list-v.rightmenu li.music { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + justify-content: space-between; + -webkit-justify-content: space-between; + -khtml-justify-content: space-between; + -moz-justify-content: space-between; + -o-justify-content: space-between; + -ms-justify-content: space-between; +} +ul.list-v.rightmenu li.navigation a.icon-only, +ul.list-v.rightmenu li.music a.icon-only { + line-height: 0; + margin: 0; + padding: 0; + border-radius: 32px; + -webkit-border-radius: 32px; + overflow: hidden; + width: 32px; + height: 32px; +} +ul.list-v.rightmenu li.navigation a.nav i, +ul.list-v.rightmenu li.music a.nav i { + margin: 0; + width: 32px; + line-height: 32px; +} +ul.list-v.rightmenu li.navigation a.nav:first-child, +ul.list-v.rightmenu li.music a.nav:first-child { + margin-left: 10px; +} +ul.list-v.rightmenu li.navigation a.nav:last-child, +ul.list-v.rightmenu li.music a.nav:last-child { + margin-right: 10px; +} +ul.list-v.rightmenu li.music.name { + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: -ms-flexbox /* TWEENER - IE 10 */; + display: -webkit-flex /* NEW - Chrome */; + display: flex /* NEW, Spec - Opera 12.1, Firefox 20+ */; + display: flex; + -webkit-box-direction: normal; + -moz-box-direction: normal; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + align-items: center; +} +ul.list-v.rightmenu li.music.name p.nav.music-title { + color: #696969; + font-size: 0.875rem; + max-width: 128px; + margin: 0 20px; + overflow: hidden; +} +ul.list-v.rightmenu li.music.name p.nav.music-title:hover { + background: none; +} +ul.list-v.rightmenu li.music .nav.volume { + width: 100%; + padding: 0 8px; +} +ul.list-v.rightmenu li.music .nav.volume:hover { + background: transparent; +} +ul.list-v.rightmenu li.music .nav.volume .aplayer-volume-bar { + margin: 4px 0 8px; + position: relative; + height: 8px; + width: 100%; + background: #ededed; + border-radius: 32px; + -webkit-border-radius: 32px; + overflow: hidden; + cursor: pointer; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; +} +ul.list-v.rightmenu li.music .nav.volume .aplayer-volume-bar i.left, +ul.list-v.rightmenu li.music .nav.volume .aplayer-volume-bar i.right { + color: #696969; + position: absolute; + top: 0; + width: 28px; + line-height: 28px; + transition: all 0.28s ease; + -webkit-transition: all 0.28s ease; + -khtml-transition: all 0.28s ease; + -moz-transition: all 0.28s ease; + -o-transition: all 0.28s ease; + -ms-transition: all 0.28s ease; + opacity: 0; + -webkit-opacity: 0; + -moz-opacity: 0; + transform: scale(0.5) translateY(-18px); + -webkit-transform: scale(0.5) translateY(-18px); + -khtml-transform: scale(0.5) translateY(-18px); + -moz-transform: scale(0.5) translateY(-18px); + -o-transform: scale(0.5) translateY(-18px); + -ms-transform: scale(0.5) translateY(-18px); +} +ul.list-v.rightmenu li.music .nav.volume .aplayer-volume-bar i.left { + left: 0; +} +ul.list-v.rightmenu li.music .nav.volume .aplayer-volume-bar i.right { + right: 0; +} +ul.list-v.rightmenu li.music .nav.volume .aplayer-volume-bar:hover { + height: 28px; +} +ul.list-v.rightmenu li.music .nav.volume .aplayer-volume-bar:hover i { + opacity: 1; + -webkit-opacity: 1; + -moz-opacity: 1; + transform: scale(1) translateY(0); + -webkit-transform: scale(1) translateY(0); + -khtml-transform: scale(1) translateY(0); + -moz-transform: scale(1) translateY(0); + -o-transform: scale(1) translateY(0); + -ms-transform: scale(1) translateY(0); +} +ul.list-v.rightmenu li.music .nav.volume .aplayer-volume-bar .aplayer-volume { + background: #3dd9b6; + height: 100%; + width: 100%; +} +@media (prefers-color-scheme: dark) { + :root { + --color-mode: 'dark'; + } + :root:not([color-scheme]) { + --block-hover: #1c1c1c; + --text-p1: #fff; + --text-p3: #777; + --card: #fff; + } + :root:not([color-scheme]) fa-solid, + :root:not([color-scheme]) fa-regular, + :root:not([color-scheme]) fa-duotone, + :root:not([color-scheme]) fa-light, + :root:not([color-scheme]) fa-thin, + :root:not([color-scheme]) fal, + :root:not([color-scheme]) fad, + :root:not([color-scheme]) fa, + :root:not([color-scheme]) svg.iconfont, + :root:not([color-scheme]) img, + :root:not([color-scheme]) .lazyload { + filter: brightness(70%) !important; + } + :root:not([color-scheme]) .widget.blogger .content .social-wrapper a.social:hover { + background: var(--color-card); + } + :root:not([color-scheme]) .widget >.content ul.entry a .badge, + :root:not([color-scheme]) .widget >.content ul.popular-posts a .badge { + color: unset !important; + } + :root:not([color-scheme]) .content { + color: var(--color-p); + } + :root:not([color-scheme]) .widget >.content a { + color: var(--color-p) !important; + } + :root:not([color-scheme]) .widget >.content a:hover { + color: var(--color-list-hl) !important; + } + :root:not([color-scheme]) .note { + background: var(--color-block) !important; + } + :root:not([color-scheme]) div.tabs ul.nav-tabs li.tab.active a { + color: var(--color-p); + background: var(--color-card); + } + :root:not([color-scheme]) kbd { + background: var(--color-block) !important; + } + :root:not([color-scheme]) .cover-wrapper.dock .menu .list-h a:hover, + :root:not([color-scheme]) .cover-wrapper.featured .menu .list-h a:hover, + :root:not([color-scheme]) .cover-wrapper.focus .menu .list-h a:hover { + color: var(--color-text) !important; + } + :root:not([color-scheme]) .gutter { + background: var(--color-card) !important; + background-color: var(--color-card) !important; + } + :root:not([color-scheme]) .highlight figcaption { + background-color: #14161a; + } + :root:not([color-scheme]) .highlight pre .line, + :root:not([color-scheme]) .highlight pre .params { + color: rgba(158,142,142,0.9); + } + :root:not([color-scheme]) *:not(.highlight) >table tr { + background-color: var(--color-card); + } + :root:not([color-scheme]) *:not(.highlight) >table th { + background: var(--color-site-bg); + } + :root:not([color-scheme]) *:not(.highlight) table td, + :root:not([color-scheme]) *:not(.highlight) table th { + border-color: var(--color-site-bg); + } + :root:not([color-scheme]) *:not(.highlight) >table tr:hover { + background: var(--color-codeblock); + } + :root:not([color-scheme]) .timenode .highlight { + border-color: var(--color-site-bg) !important; + } + :root:not([color-scheme]) blockquote p { + color: var(--color-p); + } + :root:not([color-scheme]) #archive-page .archive .all-tags ul li span { + color: var(--color-text); + background: #6f6f72; + } + :root:not([color-scheme]) .btn-copy:hover { + background: var(--color-site-body); + } + :root:not([color-scheme]) .aplayer { + background: var(--color-site-bg); + } + :root:not([color-scheme]) .aplayer .aplayer-list ol li:hover { + background: rgba(61,217,182,0.2); + } + :root:not([color-scheme]) .aplayer .aplayer-list ol li.aplayer-list-light { + background: var(--color-block); + } + :root:not([color-scheme]) .aplayer-info { + background: var(--color-site-bg) !important; + } + :root:not([color-scheme]) .aplayer .aplayer-lrc:before { + background: linear-gradient(180deg, #282c34 0, rgba(255,255,255,0)); + } + :root:not([color-scheme]) .aplayer .aplayer-lrc:after { + background: linear-gradient(180deg, rgba(0,0,0,0) 0, rgba(33,33,33,0.8)); + } + :root:not([color-scheme]) .aplayer-pic { + filter: brightness(70%); + } + :root:not([color-scheme]) .aplayer .aplayer-list ol li { + border-top: 1px solid var(--color-card); + } + :root:not([color-scheme]) .aplayer.aplayer-withlist .aplayer-info { + border-bottom: 1px solid var(--color-block); + } + :root:not([color-scheme]) .aplayer .aplayer-notice { + background-color: var(--color-site-bg) !important; + } +} +[color-scheme='dark'] { + --block-hover: #1c1c1c; + --text-p1: #fff; + --text-p3: #777; + --card: #fff; +} +[color-scheme='dark'] fa-solid, +[color-scheme='dark'] fa-regular, +[color-scheme='dark'] fa-duotone, +[color-scheme='dark'] fa-light, +[color-scheme='dark'] fa-thin, +[color-scheme='dark'] fal, +[color-scheme='dark'] fad, +[color-scheme='dark'] fa, +[color-scheme='dark'] svg.iconfont, +[color-scheme='dark'] img, +[color-scheme='dark'] .lazyload { + filter: brightness(70%) !important; +} +[color-scheme='dark'] .widget.blogger .content .social-wrapper a.social:hover { + background: var(--color-card); +} +[color-scheme='dark'] .widget >.content ul.entry a .badge, +[color-scheme='dark'] .widget >.content ul.popular-posts a .badge { + color: unset !important; +} +[color-scheme='dark'] .content { + color: var(--color-p); +} +[color-scheme='dark'] .widget >.content a { + color: var(--color-p) !important; +} +[color-scheme='dark'] .widget >.content a:hover { + color: var(--color-list-hl) !important; +} +[color-scheme='dark'] .note { + background: var(--color-block) !important; +} +[color-scheme='dark'] div.tabs ul.nav-tabs li.tab.active a { + color: var(--color-p); + background: var(--color-card); +} +[color-scheme='dark'] kbd { + background: var(--color-block) !important; +} +[color-scheme='dark'] .cover-wrapper.dock .menu .list-h a:hover, +[color-scheme='dark'] .cover-wrapper.featured .menu .list-h a:hover, +[color-scheme='dark'] .cover-wrapper.focus .menu .list-h a:hover { + color: var(--color-text) !important; +} +[color-scheme='dark'] .gutter { + background: var(--color-card) !important; + background-color: var(--color-card) !important; +} +[color-scheme='dark'] .highlight figcaption { + background-color: #14161a; +} +[color-scheme='dark'] .highlight pre .line, +[color-scheme='dark'] .highlight pre .params { + color: rgba(158,142,142,0.9); +} +[color-scheme='dark'] *:not(.highlight) >table tr { + background-color: var(--color-card); +} +[color-scheme='dark'] *:not(.highlight) >table th { + background: var(--color-site-bg); +} +[color-scheme='dark'] *:not(.highlight) table td, +[color-scheme='dark'] *:not(.highlight) table th { + border-color: var(--color-site-bg); +} +[color-scheme='dark'] *:not(.highlight) >table tr:hover { + background: var(--color-codeblock); +} +[color-scheme='dark'] .timenode .highlight { + border-color: var(--color-site-bg) !important; +} +[color-scheme='dark'] blockquote p { + color: var(--color-p); +} +[color-scheme='dark'] #archive-page .archive .all-tags ul li span { + color: var(--color-text); + background: #6f6f72; +} +[color-scheme='dark'] .btn-copy:hover { + background: var(--color-site-body); +} +[color-scheme='dark'] .aplayer { + background: var(--color-site-bg); +} +[color-scheme='dark'] .aplayer .aplayer-list ol li:hover { + background: rgba(61,217,182,0.2); +} +[color-scheme='dark'] .aplayer .aplayer-list ol li.aplayer-list-light { + background: var(--color-block); +} +[color-scheme='dark'] .aplayer-info { + background: var(--color-site-bg) !important; +} +[color-scheme='dark'] .aplayer .aplayer-lrc:before { + background: linear-gradient(180deg, #282c34 0, rgba(255,255,255,0)); +} +[color-scheme='dark'] .aplayer .aplayer-lrc:after { + background: linear-gradient(180deg, rgba(0,0,0,0) 0, rgba(33,33,33,0.8)); +} +[color-scheme='dark'] .aplayer-pic { + filter: brightness(70%); +} +[color-scheme='dark'] .aplayer .aplayer-list ol li { + border-top: 1px solid var(--color-card); +} +[color-scheme='dark'] .aplayer.aplayer-withlist .aplayer-info { + border-bottom: 1px solid var(--color-block); +} +[color-scheme='dark'] .aplayer .aplayer-notice { + background-color: var(--color-site-bg) !important; +} +article#post > h1, +article#post h2, +article#post h3 { + font-weight: 700; + background: linear-gradient(to bottom, transparent 60%, rgba(189,202,219,0.3) 0) no-repeat; + display: -webkit-box /* OLD - iOS 6-, Safari 3.1-6 */; + display: -moz-box /* OLD - Firefox 19- (buggy but mostly works) */; + display: initial; + width: auto; + border-bottom: none; +} +article#post > h3 { + font-weight: 500; + position: initial; +} +.post.post-v3.white-box { + text-align: center; +} +.post.post-v3.white-box a { + font-weight: 600 !important; +} +.post.post-v3.white-box p { + text-align: left; + text-indent: 2em; +} +#l_main > article.cus-indent p { + text-indent: 2em; +} +#l_main > article.cus-indent p.p { + text-indent: initial; +} +#l_main > article.cus-indent details p, +#l_main > article.cus-indent blockquote p, +#l_main > article.cus-indent section p, +#l_main > article.cus-indent .prev-next p, +#l_main > article.cus-indent .new-meta-box p, +#l_main > article.cus-indent .note p, +#l_main > article.cus-indent .tag p { + text-indent: initial; +} +.article a:not([class]):not([data-fancybox]), +.content > a { + position: relative; + text-decoration: none; +} +.article a:not([class]):not([data-fancybox]):before, +.content > a:before { + content: ""; + position: absolute; + left: 0; + bottom: -1px; + height: 1px; + width: 100%; + background: #ff5722; + transform: scale(0); + -webkit-transform: scale(0); + -khtml-transform: scale(0); + -moz-transform: scale(0); + -o-transform: scale(0); + -ms-transform: scale(0); + transition: all 0.5s; + -webkit-transition: all 0.5s; + -khtml-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; +} +.article a:not([class]):not([data-fancybox]):hover:before, +.content > a:hover:before { + transform: scale(1); + -webkit-transform: scale(1); + -khtml-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); +} diff --git a/dcd2023ep1-trailer/index.html b/dcd2023ep1-trailer/index.html new file mode 100644 index 0000000000..9d03cb9d8e --- /dev/null +++ b/dcd2023ep1-trailer/index.html @@ -0,0 +1,4317 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DC Doujin 2023 EP1 先行预告 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ +
+
+ + + + + + + +
+ + + +
+ + + + +
+
+

DC Doujin +2023,点击访问。

+

DC Doujin将在11月带来他的第一部视频作品“一触即发 A Cusp Before It +Rings”。这个视频,对日常学校干饭的情景进行真实再现。其中由木稿比你铁饰演的受伤学生受到热烈关注,其原型是初中部的一位学生,我们将其镜头化,力求最真实地表现出其强烈的反差感。

+

禁止用于商业用途,转载请注明出处 DC +Doujin。

+

Copyright © 2023 DC Doujin, JustPureH2O. All Rights +Reserved.

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + +
+
+ + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/dcdep1-release/index.html b/dcdep1-release/index.html new file mode 100644 index 0000000000..580df8a973 --- /dev/null +++ b/dcdep1-release/index.html @@ -0,0 +1,4304 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DC Doujin 2023 EP1 一触即发正式发布 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ +
+
+ + + + + + + +
+ + + +
+ + + + +
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + +
+
+ + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/dcdoujin/index.html b/dcdoujin/index.html new file mode 100644 index 0000000000..1257e954cb --- /dev/null +++ b/dcdoujin/index.html @@ -0,0 +1,4259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DC Doujin 同人创作 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + + +
+
+

DC Doujin

+

简介

+

DC Doujin 同人创作(以下简称DCD),由JustPureH2O于2023年11月5日创建。主要发布一些幽默视频,以及对应的幕后纪实。旨在用最真实最还原的镜头记录学校生活的点点滴滴。目前该频道的拍摄、剪辑、发布均由JustPureH2O一人承担,主要演员有木稿比你铁狂三唯吾所爱

+

新闻

+

DC Doujin +2023 EP1 先行预告 DC Doujin 2023 EP1 +一触即发 正式发布

+

演员

+

1. 木稿比你铁

+

+

DC Doujin 2023 EP1 拍摄前

+

2. 狂三唯吾所爱

+

+

(左侧)DC Doujin 2023 EP1 拍摄时

+ + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + +
+
+ + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/echorhy-dev-from-scratch-i/index.html b/echorhy-dev-from-scratch-i/index.html new file mode 100644 index 0000000000..51d6a4794e --- /dev/null +++ b/echorhy-dev-from-scratch-i/index.html @@ -0,0 +1,4328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 从零开始的桌面端音游开发 (一)环境 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + + +
+
+

开发初衷

+

Phigros玩得太烂了(确信)

+

啊作为一名中学生最重要的还得是学习!学习为重是吧。想着开发一个C#窗口程序练练手,顺便涉足一下OpenGL图像渲染的领域。挺重要的一点是感觉自己还是太闲了,再加上PC端音游实在太少喽。就萌生了这个想法。

+

图形环境

+

整体基于C#的.NET窗体程序,搭配OpenGL进行图形渲染和绘制。OpenGL本身调用起来比较麻烦,涉及很多底层操作(类似于C/C++的窗体程序开发,代码里全是底层调用),所幸还是有能人志士对繁琐的过程做了简化,对底层的OpenGL进行了一定的函数封装,推出了稳定高效简洁的OpenGL支持库。这里主要有以下几种:

+
    +
  1. SharpGL——部署安装方便、高版本OpenGL支持;但存在内存泄露问题、不支持Linux和Mac
  2. +
  3. CsGL——轻量级、响应快;不支持高版本OpenGL、仅支持32位系统炸裂
  4. +
  5. OpenTK——部署安装方便、跨平台开发、响应快于SharpGL,但慢于CsGL
  6. +
  7. Tao——C风格、支持库
  8. +
+

这里选用OpenTK,综合来讲它的功能够用、开发文档也比较充足最重要我不喜欢C风格的库。若想将OpenTK部署到项目里,新建.NET窗体工程,在NuGet包管理器中搜索OpenTK,点击安装OpenTK.GLControl,这是OpenGL对应的控件包,其中包含了OpenTK库。安装完毕后就可以看到OpenTK控件了。

+

+

OpenTK 官方文档

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + +
+
+ + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/fontainish-research/index.html b/fontainish-research/index.html new file mode 100644 index 0000000000..114c9c4a4d --- /dev/null +++ b/fontainish-research/index.html @@ -0,0 +1,4338 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 《原神》枫丹语言考究 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ +
+
+ + + + + + + +
+ + + +
+ + + + +
+
+

起因

+

这天月假,当我正为即将到来的水神池子疯狂做任务屯原石时,在列表里看到了一个悬赏整整30原石的世界任务。本着不放过任何一个给原石的任务的宗旨,我来到了秋分山西侧,白淞镇东北方向的海边房屋处。只见一位男子全身掩埋在海沙之下、动弹不得,面前摆放着一只散发香味的甜甜花酿鸡。我看他精神失常,满嘴都是“新型美容方式”的胡话又哭又闹,呜呜呜呜,好可怜呀。于是我决定帮他一把……找出了幕后黑手,此时他举起一个木牌,只见上面用老米祖传的架空文字写了一些东西,随着剧情推进,我们得知这是“抗议”(protest)。枫丹作为两个月前才开放的新国家,其文学文化充满乐子的xxs神明固然吸引了我。于是我决定用手头上有限的图片资料,整理出一份类似于枫丹语言图鉴的资料来。以便后期深入探究枫丹的风土人情。

+

初探

+

+

这是在上一部分中提到的,写有“抗议”(protest)的木牌,其中各个字母的对应关系已经标注出来了(相信不用标注也看得出来)。不难发现,最后一个字母与倒数第四个字母是相同的,恰巧对应上protest中字母t的位置。某种方面上证明了这一猜测的正确性,但是鉴于这抽象到与原英文字母完全不搭边的枫丹字体(很水体)实在是太过亮眼,我的内心还是有一点怀疑和否定的。那么我们将这七个字母挨个抽取出来,放到别的语境中去转译,不就可以验证它的准确性了吗?

+

其实也无需这么麻烦,读完前面的大佬对提瓦特通用语的解析。我们惊奇地发现,这很水体居然与提瓦特通用语的字母如出一辙:

+

+

图片来源于:哔哩哔哩,语颂源,【原神考据】提瓦特通用文

+

当然也有一些变化,比如哪里可能突然多出来一横、又或者是将圆弧形的笔画变得棱角分明。图中的SE就是两个典型例子。考虑到可能是手写体带来的美化、钝化等,我接下来去到了枫丹的主城区中,分别在蒸汽鸟报社、卡郎代沙龙前拍下了这几张图片(因为他们离锚点非常的近,不需要跑图)

+
+蒸气鸟报社——板报 + +
+
+蒸气鸟报社——招牌 + +
+
+卡郎代沙龙——招牌 + +
+

我们根据已经解译出来的提瓦特通用语字母进行对拍,发现蒸汽鸟报社的招牌上写着:LOISEAU DE VAPEUR。明显是法语,但是其中的VAPEUR和英语的VAPOR(蒸气)非常相似,因此对拍基本无误。但是由于我本人不懂法语,解释不了第一个词,只能求助于度娘。度娘也是给我甩了一个解释:鸟。并纠正了一个小错误:LOISEAU应为L'OISEAU。完美契合蒸汽鸟报社的招牌。

+

同理,卡郎代沙龙的门牌上写着:CARITAT。推测其原型是18世纪的姓氏德·卡里塔,孔多塞侯爵(Nicolas +de Caritat)的妻子便是18世纪的一位著名沙龙主人。

+

最后放出蒸汽鸟报社门前牌子上的翻译:

+

Exploring the manufacture of security machinery +探秘发条机关(守卫机器)的制造流程

+

Joyous tour through the aquatic workshop +水下工坊快乐一日游游记

+

Exclusive compilation of the past top duellists +旧时顶级决斗代理人的独家专访合集

+

Interview with the deboard restaurant artists +采访德波饭店的艺术家们

+

Iridescene tour and the new trend of music +虹彩巡游之旅,以及新派音乐

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + +
+
+ + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/fonts/HFSnakylines.ttf b/fonts/HFSnakylines.ttf new file mode 100644 index 0000000000..36b21471e8 Binary files /dev/null and b/fonts/HFSnakylines.ttf differ diff --git a/fonts/HYJiangJun-J.ttf b/fonts/HYJiangJun-J.ttf new file mode 100644 index 0000000000..49af2a493b Binary files /dev/null and b/fonts/HYJiangJun-J.ttf differ diff --git a/fonts/JetBrainsMono.ttf b/fonts/JetBrainsMono.ttf new file mode 100644 index 0000000000..5dc6ec2455 Binary files /dev/null and b/fonts/JetBrainsMono.ttf differ diff --git a/friends/index.html b/friends/index.html new file mode 100644 index 0000000000..9ec9c80e26 --- /dev/null +++ b/friends/index.html @@ -0,0 +1,4260 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 友情链接 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + + +
+
+

+ 中学时期的好朋友们 +

+ +

同班同学和其他班的OIer好朋友

+ + + + + +
+ + +

+
+ +
+ + + + + + + + + + +
+ + + + + + + +
+ + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/gz-articles/index.html b/gz-articles/index.html new file mode 100644 index 0000000000..2480f92abb --- /dev/null +++ b/gz-articles/index.html @@ -0,0 +1,4316 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 国祯文集 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ +
+
+ + + + + + + +
+ + + +
+ + + + +
+
+

曾茂华到底有多六

+

——By 国祯

+

曾茂华是中国当代著名的科学家和教育家,他以“慈父”、“良师”、“学者”等称号闻名于世。

+

1:曾茂华的蠢行为

+

曾茂华的蠢行为: +他在大学期间参加了一个乐队,并担任主唱。然而,不幸的是,由于自己的疏忽,他犯下了一件愚蠢的事情——用刀砍掉了对方的手指头。这件事让他成了学校里的头号人物之一。从那以后,他再也不敢做任何愚蠢的事情了。这是因为他害怕自己会被开除出乐队或者成为众矢之的的对象。如果他继续做出这些错误的举动,那么他会失去自己的乐队成员资格,甚至还会遭到开除。所以,为了避免发生这样的悲剧,他必须要记住:永远不要犯错!

+

2:为什么他会做出这种愚蠢的事情?

+

曾茂华的蠢行为发生在他身上,是因为他自己没有意识到他自己的愚蠢。他不知道怎么做才能让事情变得更好,他只想走捷径,而不是去努力做好事情。这种心态会导致他做出错误的决定,因为他会忽略一些重要的信息,或者选择性地记住某些信息。当我们看到一个人犯了下述三种类型的罪时,我们通常就能预测到这个人会再犯同样的问题:1. +根本不会思考问题2. 一味追求便利3. 盲目模仿别人

+

3: 该如何面对这个问题?

+

要想解决问题,首先要认识到自己的行为是愚蠢的。只有当你明白自己做了什么蠢事时,才能够改变你的行为来避免这种错误。其次,不要让别人知道你所犯下的错误。这并不是因为你不想坦白自己所犯错误,而是因为这样会给别人带来困扰。最后,如果你真的想要解决这个问题,可以尝试通过一些有趣的方式来实现它。例如,你可以去找一位专业人士帮助你分析一下这件事情,或者试着去找到一个愿意与你分享观点和建议的人。总之,如果你认为自己的行为很蠢,那么就要大胆地承认出来。只有敢于直面自己的无知,才能真正地改善自己的生活。

+

曾茂华先生不仅对科学领域做出了巨大贡献,而且为国家培养出一批优秀的人才。这些人中不乏有牛顿这样伟大的人物,也有王选这样杰出的人物。

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + +
+
+ + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/i-love-furina-instead/index.html b/i-love-furina-instead/index.html new file mode 100644 index 0000000000..e38f712bb7 --- /dev/null +++ b/i-love-furina-instead/index.html @@ -0,0 +1,4335 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 洛谷 陌路寻诗礼 题解 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + + +
+
+

题目传送门:P10178

+

受到了题面的启发,我才想起那个早已死去的算法——SPFA

+

题面总结成一句话就是:最短路只能有一条

+

那么我们用最短路算法:如果有最短路,先选择最短路。如果在更新最短值时出现了冲突——即某两种方案路径长度相等时,让后来者考虑加上一个 + +范围内的值,使它变长、不再是最短路(退出奖牌争夺)就好了。

+

对于加上的正整数值,不妨从 +开始加。不够就加上 ,还不够就加上 +,以此类推……在经历若干次最短路淘汰后,如果边权加上 +仍然不能满足最短路唯一的硬性需求时,代表这组数值根本就是无解的,因此需输出No。反之将试加的值记录到ans数组中去,在每组数据结束后输出即可。

+

同时请注意多测清空

+

代码,但是

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <bits/stdc++.h>

#define N 300010
using namespace std;

int k;
int h[N], to[N], ne[N], ans[N], dis[N];
bool st[N];
int idx = 0;

void add(int u, int v) {
idx++;
to[idx] = v;
ne[idx] = h[u];
h[u] = idx;
}

bool spfa() {
queue<int> q;
q.push(1);
dis[1] = 0;
st[1] = true;
while (!q.empty()) {
int top = q.front();
q.pop();
for (int i = h[top]; ~i; i = ne[i]) {
int j = to[i];
if (top == j) {
ans[i] = k;
continue;
}
int trial = 1;
if (dis[j] > dis[top] + trial) {
dis[j] = dis[top] + trial;
if (!st[j]) q.push(j), st[j] ^= 1;
} else if (dis[j] == dis[top] + trial) trial++;
if (trial > k) return false;
ans[i] = trial;
}
}
return true;
}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);

int t, n, m;
cin >> t;
while (t--) {
memset(dis, 0x3f, sizeof dis);
memset(h, -1, sizeof h);
memset(st, 0, sizeof st);
idx = 0;

cin >> n >> m >> k;
for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
add(u, v);
}
if (spfa()) {
cout << "Yes\n";
for (int i = 1; i <= m; i++) cout << ans[i] << ' ';
} else cout << "No";
cout << endl;
}
return 0;
}
+

这段代码居然一反常态的在第一组测试点处TLE了???于是重新看到数据范围——,发现竟然是清空的memset出了问题!当你定义了一个大小为 + +的数组时,调用memset的结果就是对这整个 +的空间进行内存赋值,而且估计第一组测试点出了一个比较大的询问个数 ,导致TLE。

+

解决方案就是从 循环到 清空,避免不必要的性能浪费

+

代码

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <bits/stdc++.h>

#define N 300010
using namespace std;

int k;
int h[N], to[N], ne[N], ans[N], dis[N];
bool st[N];
int idx = 0;

void add(int u, int v) {
idx++;
to[idx] = v;
ne[idx] = h[u];
h[u] = idx;
}

bool spfa() {
queue<int> q;
q.push(1);
dis[1] = 0;
st[1] = true;
while (!q.empty()) {
int top = q.front();
q.pop();
for (int i = h[top]; ~i; i = ne[i]) {
int j = to[i];
if (top == j) {
ans[i] = k;
continue;
}
int trial = 1;
if (dis[j] > dis[top] + trial) {
dis[j] = dis[top] + trial;
if (!st[j]) q.push(j), st[j] ^= 1;
} else if (dis[j] == dis[top] + trial) trial++;
if (trial > k) return false;
ans[i] = trial;
}
}
return true;
}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);

int t, n, m;
cin >> t;
while (t--) {
cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
idx = 0;
dis[i] = 0x3f3f3f3f;
st[i] = false;
h[i] = -1;
ans[i] = 0;
}
for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
add(u, v);
}
if (spfa()) {
cout << "Yes\n";
for (int i = 1; i <= m; i++) cout << ans[i] << ' ';
} else cout << "No";
cout << endl;
}
return 0;
}
+

发现第一组数据跑得飞快,完全不见了方才TLE时的拖沓!

+
+

本蒟蒻第一篇题解,害怕~

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + +
+
+ + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/index.html b/index.html new file mode 100644 index 0000000000..b462186efe --- /dev/null +++ b/index.html @@ -0,0 +1,5151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ +
+
+ + +

JustPureH2O

+ + +

深水里摸大鱼

+ +
+ +
+ + +
+ + + + + +
+ +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 在此记录我个人对博客的一些个性化改造 +本博客使用的Volantis(版本 6.0.0 alpha +1)改造版主题已Fork原主题: + +原主题仓库 +Fork + + +前端类 +刷新式Banner +对视差滚动插件进行改造,将原先的定时更换变为了刷新更换,以减少窗口重获焦点后重复加载图片的问题。 +在这里查看本网站的Banner信息 +OJ网站题目标签 +添加了常用OJ网站(洛谷、AcWing)的题目难度标签... + + +
+ +
+
+ + + + + + + + + 博客搭建开发记录 + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 闫氏DP 学习笔记 + +
+ + + +

+ +

+ +
+ + + 说在前面 +本博客中“闫氏DP”指的是2011年NOI金牌保送北京大学计算机系的算法选手闫学灿(yxc/y总)在教授动态规划时提出的“从集合角度分析DP问题的思维方式”。并非指代某类动态规划题型、也不是某种求解动态规划的固定算法。该文章仅作“闫氏DP”的学习笔记,一并附上例题的个人理解。为了使文章生动有趣,后文使用“yxc”或“y总”指代闫学灿本人。 +代码均经过本人实际测试AC后才给出,代码总... + + +
+ +
+
+ + + + + + + + + oi算法 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 题目传送门:P10178 +受到了题面的启发,我才想起那个早已死去的算法——SPFA +题面总结成一句话就是:最短路只能有一条。 +那么我们用最短路算法:如果有最短路,先选择最短路。如果在更新最短值时出现了冲突——即某两种方案路径长度相等时,让后来者考虑加上一个 + +范围内的值,使它变长、不再是最短路(退出奖牌争夺)就好了。 +对于加上的正整数值,不妨从 +开始加。不够就加上 ,还不够就加上 +,以... + + +
+ +
+
+ + + + + + + + + 题解 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 何为分块 +分块,正如其名,将一个整区间分为若干小区间进行操作。分块拥有比线段树更强的泛用性,但是时间复杂度略输一筹;分块代码更加直观、减少理解难度,但是时间复杂度稍逊风骚;分块的代码比线段树更短,但是时间复杂度惜败后者……线段树所上下传递的操作计算必须满足结合律,区间平均数、方差还行,像计算区间众数、中位数这样的问题,线段树就只能被薄纱了…… +考虑到树状数组理解难度较大、较难调试,一般都选用... + + +
+ +
+
+ + + + + + + + + oi算法 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + 开发初衷 +Phigros玩得太烂了(确信) +啊作为一名中学生最重要的还得是学习!学习为重是吧。想着开发一个C#窗口程序练练手,顺便涉足一下OpenGL图像渲染的领域。挺重要的一点是感觉自己还是太闲了,再加上PC端音游实在太少喽。就萌生了这个想法。 +图形环境 +整体基于C#的.NET窗体程序,搭配OpenGL进行图形渲染和绘制。OpenGL本身调用起来比较麻烦,涉及很多底层操作(类似于C/C++... + + +
+ +
+
+ + + + + + + + + 开发记录 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + Hexo云后台——Qexo搭建教程 + +
+ + + +

+ +

+ +
+ + + 在开始之前,首先你需要有一个自己的域名(github.io不算在内,你必须能够亲自更改DNS解析设置),并在博客仓库设置的Pages选项卡中绑定自己的域名。 +部署Qexo环境 +官方提供了四种方式来部署Qexo环境,其中一种允许你在本地进行部署,另外三种各自使用了不同网站提供的免费数据库服务。综合考虑操作便捷性和成功率,这里选用Vercel提供的免费PostgreSQL服务进行部署。 +首先点击... + + +
+ +
+
+ + + + + + + + + 博客搭建 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + + + + + +

+ +

+ +
+ + + +诗曰: +“高数第一杀手,考试一考就寄。复数知识一用,算成正一。朴素演算善后,死磕公式何必?考场信心十足,全错当场暴毙。” + +前置知识:复数、位运算 +Part1. 快速傅里叶变换 +Div1. 世界上最优雅的算法 +FFT起源 +FFT的前身是DFT,可以简单看作是一堆OIer争先恐后对DFT算法进行优化的结果。美苏冷战期间,双方都对自己的核实力有所隐瞒,就等着某一天用自己的核导弹打对方个措手不及... + + +
+ +
+
+ + + + + + + + + oi算法 + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 线性代数 简明教程 二 + +
+ + + +

+ +

+ +
+ + + pandoc测试自动部署 + + + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 约瑟夫环——春晚魔术表演原理解析 + +
+ + + +

+ +

+ +
+ + + +(操作没成功の尴尬,图片来自知乎) +前言 +这篇文章从数学方面推导刘谦2024年央视春晚上表演的第二个魔术的秘密、分析尼格买提错误之处,并在已知信息的加持下尝试推测尼格买提手上所剩的两张半面扑克牌的牌型。有一说一撒贝宁是真的会测假 +对应魔术节目:《守岁共此时》的回看请戳这里,在一小时十分整处。 +魔术步骤 + +四张牌面向下,并打乱。 +对折四张牌,并沿折痕撕开,得到两批半牌,每批四个共八个半牌 +(... + + +
+ +
+
+ + + + + + + +
+ + + +
+ +
+ +
+ + + +
+
+ + + + + + +
+ + 线性代数 简明教程 一 + +
+ + + +

+ +

+ +
+ + + +线性代数 简明教程 +前言 + + + 前言正文 + + + + 我个人认为我自己与线性代数的渊源是极深的。差不多整一年之前,初三上册的寒假,我在启动某二字二次元风格开放世界游戏时偶然做到了一个世界解谜。与平常无脑过的难度不同,这次的解谜可谓是充满血和汗水的教训——看攻略前千万要搞清楚站位和朝向……于是一步错步步错,耗费了整整半个小时才碰巧还原到原始的... + + +
+ +
+
+ + + + + + + + + 自学的数学 + + + + +
+ + + +
+ +
+ +
+ + + +
+ + +
+
+ +

+ 1 / 3 +

+ + + +
+ + + + +
+ + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/journey-to-the-cspj2023/index.html b/journey-to-the-cspj2023/index.html new file mode 100644 index 0000000000..43f3eb7dda --- /dev/null +++ b/journey-to-the-cspj2023/index.html @@ -0,0 +1,4344 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CSP-J 2023 游记 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ +
+
+ + + + + + + +
+ + + +
+ + + + +
+
+

又名:《第一次考就被小学生薄纱的一集》

+

本次考场:绵阳东辰国际学校

+

第一节    赛前准备

+

       插一句:CSP-J +2023没有设置赛前试机环节(包括CSP-S,成都绵阳都这样),个人推测可能是由于开放自选Windows和Linux系统带来的结果。如果你听见诸如:不要操作电脑,违者将作作弊处理 +的话时,请将你按捺不住的双手安稳的放在双腿上,避免出现意料之外的事来。

+

       然而赛前试机仍然是必要的一环(但是如果考场纪律有要求那就算了),因为这样可以让选手对机器有一个初步的了解。因为我本人习惯使用Win+E打开文件系统管理器,用Win+V记录剪切板数据,可是这些功能在考场电脑上都无法使用,进行赛前试机不仅可以避免因赛时临时发现无法使用某些功能而带来的苦恼心态爆炸点+1,而且还可以将IDE环境调整到个人喜欢的状态(例如缺省源代码,相当于每次新建代码不用重新打头文件)。选手可以不占用正式比赛时间完成一些个性化操作,方便赛时操作,其重要性不言而喻。

+

当然,开赛前乱猜试题PDF密码是极其无意义且几乎不可能成功的一件事,更不要使用暴力破解密码工具破解文件(相信守规矩的你也不会将这种工具带进考场里来),这么做不仅会被当做作弊者处理,而且造成的数据丢失也只能由你自己负责。

+

第二节    开赛之初

+

       考场下发的PDF文件带有密码保护,输入时请务必瞪大眼睛区分大小写字母O、o与数字0;小写字母l、大写字母I与数字1,并且将其中的特殊字符认真核对一遍。本次考试,我有幸将密码中的数字0写成了小写字母o,于是浪费了宝贵的2分钟时间改正密码(真实情况是监考老师在黑板上书写密码时字迹不规范导致的混淆)。因此需要认真看好你的密码。

+

       就我认为:在一开始就仔细写好文件重定向输入输出是极其重要的,因为随着考试时间的推进,你的思考重点将从细节性问题变为如何拿到更多的分数上骗分。你就会忽略重新写上两行重定向IO的代码,因而可能Au->Cu,光荣AFO。为了引起你的注意,使用极长的注释双斜线是可行的,我本人习惯打上断点。例如:

+
1
2
//////////////////////////////////////////////// freopen("uqe.in", "r", stdin);
//////////////////////////////////////////////// freopen("uqe.out", "w", stdout);
+

将比

+
1
2
//freopen("uqe.in", "r", stdin);
//freopen("uqe.out", "w", stdout);
+

显眼得多——尤其是当你喜欢为每行代码写上包含心血的易懂注释时。事后你可以通过长按Ctrl+逗号(Dev-C++)的方式快速且安全的删除这些斜线。

+

       不仅如此,看好输入输出文件名也是一个非常重要的细节,建议直接复制粘贴。对于标准样例,直接选中PDF文字再复制一般都不是一个明智的做法,手动输入也是可行的,但是对拍有时会比较繁琐(例如普及组T3的样例)。这边传授一个方便的做法:选中代码左侧序号,在WPS中直接右键菜单点击消除文字即可(本次考试我就是使用的这个方便技巧快捷复制样例数据)。最好找张纸记下来,后面会讲到原因。

+

       顺利解锁了PDF文件,你要做的第一件事就是将四道题全部读熟。对整场比赛的题目有大致的规划,有可能你先前做题时做过与T4极其相似的题目,那么放弃显然是一个很不划算的决策。将题目读熟,大概判断一下算法实现,评估自己哪些题能做好,哪些题要放一放/完全放弃。知己知彼方能百战百胜。

+

       赛初的状态基本上决定了你整场比赛的表现,因此在赛初就做好一切细节方面的完全准备,对你的信心增长是非常重要的!

+

第三节    赛中时期

+

       那么你现在拿到了第一题(信心题)。一般来说,CSP的复赛,算法很少裸露地出现在题目之中,前两题近似看作数学题。保证你的数学思维在线,因为第一题的思路可能千奇百怪,如果你一段时间没有思路(对于第一题大概是5~15分钟),可以考虑先做其他题目。刷新一下思维定势,有可能T1的灵感就乍现于其他题目之中。

+

       在符合时间规划的前提下尽可能多去造hack数据,写出一段代码(尤其是T3放大模拟时)后,千万保证没有任何逻辑问题。当然,不是所有人都能只看代码就能检查的出其中的逻辑漏洞。因此你需要多造hack数据。hack数据多数情况下包括这几个要素:方程的特殊解、极端值/边界值、大数据(int越界)。在规划好的时间内想尽办法为你的代码多挑几根刺出来,你的代码才能更加趋近于满分解。

+

       千万不要看你旁边的人!!! +除非S组巨佬闯进了J组蒟蒻区,否则千万不要在比赛中途去看任何人的任何行为。一方面,你的行为可能被视作交谈作弊喜提CCF全国通报、禁赛3年大礼包;另一方面,如果你抱着嘲笑别人的心态去观察别人,那么你的脸很可能就会被你自己打烂。我在考试时因为瞧不起隔壁的一位小学生,当他开始疯狂敲代码时,我自己的心态就爆炸了——把所有人,不分男女、年龄高低,都当作你的敌人,轻视则死。同时这也给你带来一部分紧张感,会使你的发挥更佳。

+

       给自己适当的放松与勉励,要相信,上天不是无故给你这个周末不用冒着风雨大太阳上补习班的珍贵机会(对于高中生,则是周六不用坐在教室里上正课的机会)。当你完全确认你的代码已经完美无瑕时,告诉自己:同学们都还在悲催的上着课,我却在外边快乐的敲着代码。如此一来可以起到调整心态的作用。

+

       别激动到顺手关了PDF文件。如果你还记得或者是在草稿纸上写了密码,那无所谓;但是如果你没写,你的处境就非常尴尬,这时你可以举手找老师再要,但这绝对对你的心态是一个不小的打击。

+

第四节    赛末时期

+

       经历三个半小时的不懈奋斗,比赛终于迎来最后的半小时。无论你的完成情况如何,一定要用这最后的时间好好检查一下你的代码。瞄一眼你是否有与下面类似的代码:

+
1
2
freopen("uqe2.in", "r", stdin);  // 危
freopen("uqe2.out", "w", stdout); // 爆零警告
+

这段代码的主人是个懒人无疑了,如果你把CCF提供的附加样例复制了出来。切记最后把文件名里的序号删除,否则你就可以AFO了。

+

       或者以下的代码:

+
1
2
3
4
#include <Windows.h>
//其他的代码
if (system("fc uqe.out uqe.ans")) cout<<"WA"<<endl;
else cout<<"AC"<<endl;
+

这位同学也是个Windows爱好者受害者无疑了,CCF明文规定了测试用系统为NOI +Linux。因此不存在Windows.h这个头文件,如果你忘记删除了,那一定是个大大滴CE。正式比赛时,用bits/stdc++.h万能头即可(Windows和Linux通用)。我有一个考S组的朋友,因为忘记删除这个对拍头文件而喜提一个0分,直接亏大发。

+

       不要忘记将你的重定向取消注释。你连读入输出都没有了,属实是可以AFO了。最后三分钟,请将你的蹄子挪开键盘鼠标。否则可能会越改越慌,不妨好好回想一下这周老师留了什么作业,你缺了哪些课需要去补,总之不要再动你的鼠标键盘了!如果实在是不放心编译问题,按一下F11,通过即可。保证你的工作目录下只留.cpp文件,所以将你复制的样例文件和编译的exe文件全部删除。

+

第五节    考试结束

+

       请你千万保持冷静,不要习惯性地把机器关机了。CCF明文规定:由关机造成的数据损失,责任由考生自负。只需要把你的IDE关闭就好。

+

       回家后,把周一要交的作业补好。别再谈考试的事情了,让你自己有个好心情。毕竟不管你的表现怎么样,它都过去了不是吗?

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + +
+
+ + + + +
+ + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/js/app.js b/js/app.js new file mode 100644 index 0000000000..0defeb374f --- /dev/null +++ b/js/app.js @@ -0,0 +1,1152 @@ +document.addEventListener("DOMContentLoaded", function () { + volantis.requestAnimationFrame(() => { + VolantisApp.init(); + VolantisApp.subscribe(); + VolantisFancyBox.init(); + highlightKeyWords.startFromURL(); + locationHash(); + }); +}); + +/* 锚点定位 */ +const locationHash = () => { + if (window.location.hash) { + let locationID = decodeURI(window.location.hash.split('#')[1]).replace(/\ /g, '-'); + let target = document.getElementById(locationID); + if (target) { + setTimeout(() => { + if (window.location.hash.startsWith('#fn')) { // hexo-reference https://github.com/volantis-x/hexo-theme-volantis/issues/647 + volantis.scroll.to(target, { addTop: - volantis.dom.header.offsetHeight - 5, behavior: 'instant', observer: true }) + } else { + // 锚点中上半部有大片空白 高度大概是 volantis.dom.header.offsetHeight + volantis.scroll.to(target, { addTop: 5, behavior: 'instant', observer: true }) + } + }, 1000) + } + } +} +Object.freeze(locationHash); + +/* Main */ +const VolantisApp = (() => { + const fn = {}, + COPYHTML = ''; + let scrollCorrection = 80; + + fn.init = () => { + if (volantis.dom.header) { + scrollCorrection = volantis.dom.header.clientHeight + 16; + } + + window.onresize = () => { + if (document.documentElement.clientWidth < 500) { + volantis.isMobile = 1; + } else { + volantis.isMobile = 0; + } + if (volantis.isMobile != volantis.isMobileOld) { + fn.setGlobalHeaderMenuEvent(); + fn.setHeader(); + fn.setHeaderSearch(); + } + } + volantis.scroll.push(fn.scrollEventCallBack, "scrollEventCallBack") + } + + fn.event = () => { + volantis.dom.$(document.getElementById("scroll-down"))?.on('click', function () { + fn.scrolltoElement(volantis.dom.bodyAnchor); + }); + + // 如果 sidebar 为空,隐藏 sidebar。 + const sidebar = document.querySelector("#l_side") + if (sidebar) { + const sectionList = sidebar.querySelectorAll("section") + if (!sectionList.length) { + document.querySelector("#l_main").classList.add("no_sidebar") + } + } + + // 站点信息 最后活动日期 + if (volantis.GLOBAL_CONFIG.sidebar.for_page.includes('webinfo') || volantis.GLOBAL_CONFIG.sidebar.for_post.includes('webinfo')) { + const lastupd = volantis.GLOBAL_CONFIG.sidebar.webinfo.lastupd; + if (!!document.getElementById('last-update-show') && lastupd.enable && lastupd.friendlyShow) { + document.getElementById('last-update-show').innerHTML = fn.utilTimeAgo(volantis.GLOBAL_CONFIG.lastupdate); + } + } + + // 站点信息 运行时间 + if (!!document.getElementById('webinfo-runtime-count')) { + let BirthDay = new Date(volantis.GLOBAL_CONFIG.sidebar.webinfo.runtime.data); + let timeold = (new Date().getTime() - BirthDay.getTime()); + let daysold = Math.floor(timeold / (24 * 60 * 60 * 1000)); + document.getElementById('webinfo-runtime-count').innerHTML = `${daysold} ${volantis.GLOBAL_CONFIG.sidebar.webinfo.runtime.unit}`; + } + + // 消息提示 复制时弹出 + document.body.oncopy = function () { + fn.messageCopyright() + }; + } + + fn.restData = () => { + scrollCorrection = volantis.dom.header ? volantis.dom.header.clientHeight + 16 : 80; + } + + fn.setIsMobile = () => { + if (document.documentElement.clientWidth < 500) { + volantis.isMobile = 1; + volantis.isMobileOld = 1; + } else { + volantis.isMobile = 0; + volantis.isMobileOld = 0; + } + } + + // 校正页面定位(被导航栏挡住的区域) + fn.scrolltoElement = (elem, correction = scrollCorrection) => { + volantis.scroll.to(elem, { + top: elem.getBoundingClientRect().top + document.documentElement.scrollTop - correction + }) + } + + // 滚动事件回调们 + fn.scrollEventCallBack = () => { + // 【移动端 PC】////////////////////////////////////////////////////////////////////// + + // 显示/隐藏 Header导航 topBtn 【移动端 PC】 + const showHeaderPoint = volantis.dom.bodyAnchor.offsetTop - scrollCorrection; + const scrollTop = volantis.scroll.getScrollTop(); // 滚动条距离顶部的距离 + + // topBtn + if (volantis.dom.topBtn) { + if (scrollTop > volantis.dom.bodyAnchor.offsetTop) { + volantis.dom.topBtn.addClass('show'); + // 向上滚动高亮 topBtn + if (volantis.scroll.del > 0) { + volantis.dom.topBtn.removeClass('hl'); + } else { + volantis.dom.topBtn.addClass('hl'); + } + } else { + volantis.dom.topBtn.removeClass('show').removeClass('hl'); + } + } + + // Header导航 + if (volantis.dom.header) { + if (scrollTop - showHeaderPoint > -1) { + volantis.dom.header.addClass('show'); + } else { + volantis.dom.header.removeClass('show'); + } + } + + // 决定一二级导航栏的切换 【向上滚动切换为一级导航栏;向下滚动切换为二级导航栏】 【移动端 PC】 + if (pdata.ispage && volantis.dom.wrapper) { + if (volantis.scroll.del > 0 && scrollTop > 100) { // 向下滚动 + volantis.dom.wrapper.addClass('sub'); // <---- 二级导航显示 + } else if (volantis.scroll.del < 0) { // 向上滚动 + volantis.dom.wrapper.removeClass('sub'); // <---- 取消二级导航显示 一级导航显示 + } + } + + // 【移动端】////////////////////////////////////////////////////////////////////// + if (volantis.isMobile) { + // 【移动端】 页面滚动 隐藏 移动端toc目录按钮 + if (pdata.ispage && volantis.dom.tocTarget && volantis.dom.toc) { + volantis.dom.tocTarget.removeClass('active'); + volantis.dom.toc.removeClass('active'); + } + // 【移动端】 滚动时隐藏子菜单 + if (volantis.dom.mPhoneList) { + volantis.dom.mPhoneList.forEach(function (e) { + volantis.dom.$(e).hide(); + }) + } + } + } + + // 设置滚动锚点 + fn.setScrollAnchor = () => { + // click topBtn 滚动至bodyAnchor 【移动端 PC】 + if (volantis.dom.topBtn && volantis.dom.bodyAnchor) { + volantis.dom.topBtn.click(e => { + e.preventDefault(); + e.stopPropagation(); + fn.scrolltoElement(volantis.dom.bodyAnchor); + e.stopImmediatePropagation(); + }); + } + + } + + // 设置导航栏 + fn.setHeader = () => { + // !!! 此处的Dom对象需要重载 !!! + if (!pdata.ispage) return; + + // 填充二级导航文章标题 【移动端 PC】 + volantis.dom.wrapper.find('.nav-sub .title').html(document.title.split(" - ")[0]); + + // ====== bind events to every btn ========= + // 评论按钮 【移动端 PC】 + volantis.dom.comment = volantis.dom.$(document.getElementById("s-comment")); // 评论按钮 桌面端 移动端 + volantis.dom.commentTarget = volantis.dom.$(document.querySelector('#l_main article#comments')); // 评论区域 + if (volantis.dom.commentTarget) { + volantis.dom.comment.click(e => { // 评论按钮点击后 跳转到评论区域 + e.preventDefault(); + e.stopPropagation(); + volantis.cleanContentVisibility(); + fn.scrolltoElement(volantis.dom.commentTarget); + e.stopImmediatePropagation(); + }); + } else volantis.dom.comment.style.display = 'none'; // 关闭了评论,则隐藏评论按钮 + + // 移动端toc目录按钮 【移动端】 + if (volantis.isMobile) { + volantis.dom.toc = volantis.dom.$(document.getElementById("s-toc")); // 目录按钮 仅移动端 + volantis.dom.tocTarget = volantis.dom.$(document.querySelector('#l_side .toc-wrapper')); // 侧边栏的目录列表 + if (volantis.dom.tocTarget) { + // 点击移动端目录按钮 激活目录按钮 显示侧边栏的目录列表 + volantis.dom.toc.click((e) => { + e.stopPropagation(); + volantis.dom.tocTarget.toggleClass('active'); + volantis.dom.toc.toggleClass('active'); + }); + // 点击空白 隐藏 + volantis.dom.$(document).click(function (e) { + e.stopPropagation(); + if (volantis.dom.tocTarget) { + volantis.dom.tocTarget.removeClass('active'); + } + volantis.dom.toc.removeClass('active'); + }); + } else if (volantis.dom.toc) volantis.dom.toc.style.display = 'none'; // 隐藏toc目录按钮 + } + } + + // 设置导航栏菜单选中状态 【移动端 PC】 + fn.setHeaderMenuSelection = () => { + // !!! 此处的Dom对象需要重载 !!! + volantis.dom.headerMenu = volantis.dom.$(document.querySelectorAll('#l_header .navigation,#l_cover .navigation,#l_side .navigation')); // 导航列表 + + // 先把已经激活的取消激活 + volantis.dom.headerMenu.forEach(element => { + let li = volantis.dom.$(element).find('li a.active') + if (li) + li.removeClass('active') + let div = volantis.dom.$(element).find('div a.active') + if (div) + div.removeClass('active') + }); + + // replace '%' '/' '.' + var idname = location.pathname.replace(/\/|%|\./g, ''); + if (idname.length == 0) { + idname = 'home'; + } + var page = idname.match(/page\d{0,}$/g); + if (page) { + page = page[0]; + idname = idname.split(page)[0]; + } + var index = idname.match(/index.html/); + if (index) { + index = index[0]; + idname = idname.split(index)[0]; + } + // 转义字符如 [, ], ~, #, @ + idname = idname.replace(/(\[|\]|~|#|@)/g, '\\$1'); + if (idname && volantis.dom.headerMenu) { + volantis.dom.headerMenu.forEach(element => { + // idname 不能为数字开头, 加一个 action- 前缀 + let id = element.querySelector("[active-action=action-" + idname + "]") + if (id) { + volantis.dom.$(id).addClass('active') + } + }); + } + } + + // 设置全局事件 + fn.setGlobalHeaderMenuEvent = () => { + if (volantis.isMobile) { + // 【移动端】 关闭已经展开的子菜单 点击展开子菜单 + document.querySelectorAll('#l_header .m-phone li').forEach(function (e) { + if (e.querySelector(".list-v")) { + // 点击菜单 + volantis.dom.$(e).click(function (e) { + e.stopPropagation(); + // 关闭已经展开的子菜单 + e.currentTarget.parentElement.childNodes.forEach(function (e) { + if (Object.prototype.toString.call(e) == '[object HTMLLIElement]') { + e.childNodes.forEach(function (e) { + if (Object.prototype.toString.call(e) == '[object HTMLUListElement]') { + volantis.dom.$(e).hide() + } + }) + } + }) + // 点击展开子菜单 + let array = e.currentTarget.children + for (let index = 0; index < array.length; index++) { + const element = array[index]; + if (volantis.dom.$(element).title === 'menu') { // 移动端菜单栏异常 + volantis.dom.$(element).display = "flex" // https://github.com/volantis-x/hexo-theme-volantis/issues/706 + } else { + volantis.dom.$(element).show() + } + } + }, 0); + } + }) + } else { + // 【PC端】 hover时展开子菜单,点击时[target.baseURI==origin时]隐藏子菜单? 现有逻辑大部分情况不隐藏子菜单 + document.querySelectorAll('#wrapper .m-pc li > a[href]').forEach(function (e) { + volantis.dom.$(e.parentElement).click(function (e) { + e.stopPropagation(); + if (e.target.origin == e.target.baseURI) { + document.querySelectorAll('#wrapper .m-pc .list-v').forEach(function (e) { + volantis.dom.$(e).hide(); // 大概率不会执行 + }) + } + }, 0); + }) + } + fn.setPageHeaderMenuEvent(); + } + + // 【移动端】隐藏子菜单 + fn.setPageHeaderMenuEvent = () => { + if (!volantis.isMobile) return + // 【移动端】 点击空白处隐藏子菜单 + volantis.dom.$(document).click(function (e) { + volantis.dom.mPhoneList.forEach(function (e) { + volantis.dom.$(e).hide(); + }) + }); + } + + // 设置导航栏搜索框 【移动端】 + fn.setHeaderSearch = () => { + if (!volantis.isMobile) return; + if (!volantis.dom.switcher) return; + // 点击移动端搜索按钮 + volantis.dom.switcher.click(function (e) { + e.stopPropagation(); + volantis.dom.header.toggleClass('z_search-open'); // 激活移动端搜索框 + volantis.dom.switcher.toggleClass('active'); // 移动端搜索按钮 + }); + // 点击空白取消激活 + volantis.dom.$(document).click(function (e) { + volantis.dom.header.removeClass('z_search-open'); + volantis.dom.switcher.removeClass('active'); + }); + // 移动端点击搜索框 停止事件传播 + volantis.dom.search.click(function (e) { + e.stopPropagation(); + }); + } + + // 设置 tabs 标签 【移动端 PC】 + fn.setTabs = () => { + let tabs = document.querySelectorAll('#l_main .tabs .nav-tabs') + if (!tabs) return + tabs.forEach(function (e) { + e.querySelectorAll('a').forEach(function (e) { + volantis.dom.$(e).on('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + const $tab = volantis.dom.$(e.target.parentElement.parentElement.parentElement); + $tab.find('.nav-tabs .active').removeClass('active'); + volantis.dom.$(e.target.parentElement).addClass('active'); + $tab.find('.tab-content .active').removeClass('active'); + $tab.find(e.target.className).addClass('active'); + return false; + }); + }) + }) + } + + // hexo-reference 页脚跳转 https://github.com/volantis-x/hexo-theme-volantis/issues/647 + fn.footnotes = () => { + let ref = document.querySelectorAll('#l_main .footnote-backref, #l_main .footnote-ref > a'); + ref.forEach(function (e, i) { + ref[i].click = () => { }; // 强制清空原 click 事件 + volantis.dom.$(e).on('click', (e) => { + e.stopPropagation(); + e.preventDefault(); + let targetID = decodeURI(e.target.hash.split('#')[1]).replace(/\ /g, '-'); + let target = document.getElementById(targetID); + if (target) { + volantis.scroll.to(target, { addTop: - volantis.dom.header.offsetHeight - 5, behavior: 'instant' }) + } + }); + }) + } + + // 工具类:代码块复制 + fn.utilCopyCode = (Selector) => { + document.querySelectorAll(Selector).forEach(node => { + const test = node.insertAdjacentHTML("beforebegin", COPYHTML); + const _BtnCopy = node.previousSibling; + _BtnCopy.onclick = e => { + e.stopPropagation(); + const _icon = _BtnCopy.querySelector('i'); + const _span = _BtnCopy.querySelector('span'); + + node.focus(); + const range = new Range(); + range.selectNodeContents(node); + document.getSelection().removeAllRanges(); + document.getSelection().addRange(range); + + const str = document.getSelection().toString(); + fn.utilWriteClipText(str).then(() => { + fn.messageCopyright(); + _BtnCopy.classList.add('copied'); + _icon.classList.remove('fa-copy'); + _icon.classList.add('fa-check-circle'); + _span.innerText = "COPIED"; + setTimeout(() => { + _icon.classList.remove('fa-check-circle'); + _icon.classList.add('fa-copy'); + _span.innerText = "COPY"; + }, 2000) + }).catch(e => { + VolantisApp.message('系统提示', e, { + icon: 'fa fa-exclamation-circle red' + }); + _BtnCopy.classList.add('copied-failed'); + _icon.classList.remove('fa-copy'); + _icon.classList.add('fa-exclamation-circle'); + _span.innerText = "COPY FAILED"; + setTimeout(() => { + _icon.classList.remove('fa-exclamation-circle'); + _icon.classList.add('fa-copy'); + _span.innerText = "COPY"; + }) + }) + } + }); + } + + // 工具类:复制字符串到剪切板 + fn.utilWriteClipText = (str) => { + return navigator.clipboard + .writeText(str) + .then(() => { + return Promise.resolve() + }) + .catch(e => { + const input = document.createElement('textarea'); + input.setAttribute('readonly', 'readonly'); + document.body.appendChild(input); + input.innerHTML = str; + input.select(); + try { + let result = document.execCommand('copy') + document.body.removeChild(input); + if (!result || result === 'unsuccessful') { + return Promise.reject('复制文本失败!') + } else { + return Promise.resolve() + } + } catch (e) { + document.body.removeChild(input); + return Promise.reject( + '当前浏览器不支持复制功能,请检查更新或更换其他浏览器操作!' + ) + } + }) + } + + // 工具类:返回时间间隔 + fn.utilTimeAgo = (dateTimeStamp) => { + const minute = 1e3 * 60, hour = minute * 60, day = hour * 24, week = day * 7, month = day * 30; + const now = new Date().getTime(); + const diffValue = now - dateTimeStamp; + const minC = diffValue / minute, + hourC = diffValue / hour, + dayC = diffValue / day, + weekC = diffValue / week, + monthC = diffValue / month; + if (diffValue < 0) { + result = "" + } else if (monthC >= 1 && monthC < 7) { + result = " " + parseInt(monthC) + " 月前" + } else if (weekC >= 1 && weekC < 4) { + result = " " + parseInt(weekC) + " 周前" + } else if (dayC >= 1 && dayC < 7) { + result = " " + parseInt(dayC) + " 天前" + } else if (hourC >= 1 && hourC < 24) { + result = " " + parseInt(hourC) + " 小时前" + } else if (minC >= 1 && minC < 60) { + result = " " + parseInt(minC) + " 分钟前" + } else if (diffValue >= 0 && diffValue <= minute) { + result = "刚刚" + } else { + const datetime = new Date(); + datetime.setTime(dateTimeStamp); + const Nyear = datetime.getFullYear(); + const Nmonth = datetime.getMonth() + 1 < 10 ? "0" + (datetime.getMonth() + 1) : datetime.getMonth() + 1; + const Ndate = datetime.getDate() < 10 ? "0" + datetime.getDate() : datetime.getDate(); + const Nhour = datetime.getHours() < 10 ? "0" + datetime.getHours() : datetime.getHours(); + const Nminute = datetime.getMinutes() < 10 ? "0" + datetime.getMinutes() : datetime.getMinutes(); + const Nsecond = datetime.getSeconds() < 10 ? "0" + datetime.getSeconds() : datetime.getSeconds(); + result = Nyear + "-" + Nmonth + "-" + Ndate + } + return result; + } + + // 消息提示:标准 + fn.message = (title, message, option = {}, done = null) => { + if (typeof iziToast === "undefined") { + volantis.css(volantis.GLOBAL_CONFIG.cdn.izitoast_css) + volantis.js(volantis.GLOBAL_CONFIG.cdn.izitoast_js, () => { + tozashMessage(title, message, option, done); + }); + } else { + tozashMessage(title, message, option, done); + } + function tozashMessage(title, message, option, done) { + const { + icon, + time, + position, + transitionIn, + transitionOut, + messageColor, + titleColor, + backgroundColor, + zindex, + displayMode + } = option; + iziToast.show({ + layout: '2', + icon: 'Fontawesome', + closeOnEscape: 'true', + displayMode: displayMode || 'replace', + transitionIn: transitionIn || volantis.GLOBAL_CONFIG.plugins.message.transitionIn, + transitionOut: transitionOut || volantis.GLOBAL_CONFIG.plugins.message.transitionOut, + messageColor: messageColor || volantis.GLOBAL_CONFIG.plugins.message.messageColor, + titleColor: titleColor || volantis.GLOBAL_CONFIG.plugins.message.titleColor, + backgroundColor: backgroundColor || volantis.GLOBAL_CONFIG.plugins.message.backgroundColor, + zindex: zindex || volantis.GLOBAL_CONFIG.plugins.message.zindex, + icon: icon || volantis.GLOBAL_CONFIG.plugins.message.icon.default, + timeout: time || volantis.GLOBAL_CONFIG.plugins.message.time.default, + position: position || volantis.GLOBAL_CONFIG.plugins.message.position, + title: title, + message: message, + onClosed: () => { + if (done) done(); + }, + }); + } + } + + // 消息提示:询问 + fn.question = (title, message, option = {}, success = null, cancel = null, done = null) => { + if (typeof iziToast === "undefined") { + volantis.css(volantis.GLOBAL_CONFIG.cdn.izitoast_css) + volantis.js(volantis.GLOBAL_CONFIG.cdn.izitoast_js, () => { + tozashQuestion(title, message, option, success, cancel, done); + }); + } else { + tozashQuestion(title, message, option, success, cancel, done); + } + + function tozashQuestion(title, message, option, success, cancel, done) { + const { + icon, + time, + position, + transitionIn, + transitionOut, + messageColor, + titleColor, + backgroundColor, + zindex + } = option; + iziToast.question({ + id: 'question', + icon: 'Fontawesome', + close: false, + overlay: true, + displayMode: 'once', + position: 'center', + messageColor: messageColor || volantis.GLOBAL_CONFIG.plugins.message.messageColor, + titleColor: titleColor || volantis.GLOBAL_CONFIG.plugins.message.titleColor, + backgroundColor: backgroundColor || volantis.GLOBAL_CONFIG.plugins.message.backgroundColor, + zindex: zindex || volantis.GLOBAL_CONFIG.plugins.message.zindex, + icon: icon || volantis.GLOBAL_CONFIG.plugins.message.icon.quection, + timeout: time || volantis.GLOBAL_CONFIG.plugins.message.time.quection, + title: title, + message: message, + buttons: [ + ['', (instance, toast) => { + instance.hide({ transitionOut: transitionOut || 'fadeOut' }, toast, 'button'); + if (success) success(instance, toast) + }], + ['', (instance, toast) => { + instance.hide({ transitionOut: transitionOut || 'fadeOut' }, toast, 'button'); + if (cancel) cancel(instance, toast) + }] + ], + onClosed: (instance, toast, closedBy) => { + if (done) done(instance, toast, closedBy); + } + }); + } + } + + // 消息提示:隐藏 + fn.hideMessage = (done = null) => { + const toast = document.querySelector('.iziToast'); + if (!toast) { + if (done) done() + return; + } + + if (typeof iziToast === "undefined") { + volantis.css(volantis.GLOBAL_CONFIG.cdn.izitoast_css) + volantis.js(volantis.GLOBAL_CONFIG.cdn.izitoast_js, () => { + hideMessage(done); + }); + } else { + hideMessage(done); + } + + function hideMessage(done) { + iziToast.hide({}, toast); + if (done) done(); + } + } + + // 消息提示:复制 + let messageCopyrightShow = 0; + fn.messageCopyright = () => { + // 消息提示 复制时弹出 + if (volantis.GLOBAL_CONFIG.plugins.message.enable + && volantis.GLOBAL_CONFIG.plugins.message.copyright.enable + && messageCopyrightShow < 1) { + messageCopyrightShow++; + VolantisApp.message(volantis.GLOBAL_CONFIG.plugins.message.copyright.title, + volantis.GLOBAL_CONFIG.plugins.message.copyright.message, { + icon: volantis.GLOBAL_CONFIG.plugins.message.copyright.icon, + transitionIn: 'flipInX', + transitionOut: 'flipOutX', + displayMode: 1 + }); + } + } + + return { + init: () => { + fn.init(); + fn.event(); + }, + subscribe: () => { + fn.setIsMobile(); + fn.setHeader(); + fn.setHeaderMenuSelection(); + fn.setGlobalHeaderMenuEvent(); + fn.setHeaderSearch(); + fn.setScrollAnchor(); + fn.setTabs(); + fn.footnotes(); + }, + utilCopyCode: fn.utilCopyCode, + utilWriteClipText: fn.utilWriteClipText, + utilTimeAgo: fn.utilTimeAgo, + message: fn.message, + question: fn.question, + hideMessage: fn.hideMessage, + messageCopyright: fn.messageCopyright, + scrolltoElement: fn.scrolltoElement + } +})() +Object.freeze(VolantisApp); + +/* FancyBox */ +const VolantisFancyBox = (() => { + const fn = {}; + + fn.loadFancyBox = (done) => { + volantis.css(volantis.GLOBAL_CONFIG.cdn.fancybox_css); + volantis.js(volantis.GLOBAL_CONFIG.cdn.fancybox_js).then(() => { + if (done) done(); + }) + } + + /** + * 加载及处理 + * + * @param {*} checkMain 是否只处理文章区域的文章 + * @param {*} done FancyBox 加载完成后的动作,默认执行分组绑定 + * @returns + */ + fn.init = (checkMain = true, done = fn.groupBind) => { + if (!document.querySelector(".md .gallery img, .fancybox") && checkMain) return; + if (typeof Fancybox === "undefined") { + fn.loadFancyBox(done); + } else { + done(); + } + } + + /** + * 图片元素预处理 + * + * @param {*} selectors 选择器 + * @param {*} name 分组 + */ + fn.elementHandling = (selectors, name) => { + const nodeList = document.querySelectorAll(selectors); + nodeList.forEach($item => { + if ($item.hasAttribute('fancybox')) return; + $item.setAttribute('fancybox', ''); + const $link = document.createElement('a'); + $link.setAttribute('href', $item.src); + $link.setAttribute('data-caption', $item.alt); + $link.setAttribute('data-fancybox', name); + $link.classList.add('fancybox'); + $link.append($item.cloneNode()); + $item.replaceWith($link); + }) + } + + /** + * 原生绑定 + * + * @param {*} selectors 选择器 + */ + fn.bind = (selectors) => { + fn.init(false, () => { + Fancybox.bind(selectors, { + groupAll: true, + Hash: false, + hideScrollbar: false, + Thumbs: { + autoStart: false, + }, + caption: function (fancybox, carousel, slide) { + return slide.$trigger.alt || null + } + }); + }); + } + + /** + * 分组绑定 + * + * @param {*} groupName 分组名称 + */ + fn.groupBind = (groupName = null) => { + const group = new Set(); + + document.querySelectorAll(".gallery").forEach(ele => { + if (ele.querySelector("img")) { + group.add(ele.getAttribute('data-group') || 'default'); + } + }) + + if (!!groupName) group.add(groupName); + + for (const iterator of group) { + Fancybox.unbind('[data-fancybox="' + iterator + '"]'); + Fancybox.bind('[data-fancybox="' + iterator + '"]', { + Hash: false, + hideScrollbar: false, + Thumbs: { + autoStart: false, + } + }); + } + } + + return { + init: fn.init, + bind: fn.bind, + groupBind: (selectors, groupName = 'default') => { + try { + fn.elementHandling(selectors, groupName); + fn.init(false, () => { + fn.groupBind(groupName) + }); + } catch (error) { + console.error(error) + } + } + } +})() +Object.freeze(VolantisFancyBox); + +// highlightKeyWords 与 搜索功能搭配 https://github.com/next-theme/hexo-theme-next/blob/eb194a7258058302baf59f02d4b80b6655338b01/source/js/third-party/search/local-search.js +// Question: 锚点稳定性未知 +// ToDo: 查找模式 +// 0. (/////////要知道浏览器自带全页面查找功能 CTRL + F) +// 1. 右键开启查找模式 / 导航栏菜单开启?? / CTRL + F ??? +// 2. 查找模式面板 (可拖动? or 固定?) +// 3. keyword mark id 从 0 开始编号 查找下一处 highlightKeyWords.scrollToNextHighlightKeywordMark() 查找上一处 scrollToPrevHighlightKeywordMark() 循环查找(取模%) +// 4. 可输入修改 查找关键词 keywords(type:list) +// 5. 区分大小写 caseSensitive (/ 全字匹配?? / 正则匹配??) +// 6. 在选定区域中查找 querySelector ?? +// 7. 关闭查找模式 +// 8. 搜索跳转 (URL 入口) 自动开启查找模式 调用 scrollToNextHighlightKeywordMark() +const highlightKeyWords = (() => { + let fn = {} + fn.markNum = 0 + fn.markNextId = -1 + fn.startFromURL = () => { + const params = decodeURI(new URL(location.href).searchParams.get('keyword')); + const keywords = params ? params.split(' ') : []; + const post = document.querySelector('#l_main'); + if (keywords.length == 1 && keywords[0] == "null") { + return; + } + fn.start(keywords, post); // 渲染耗时较长 + fn.scrollToFirstHighlightKeywordMark() + } + fn.scrollToFirstHighlightKeywordMark = () => { + volantis.cleanContentVisibility(); + let target = fn.scrollToNextHighlightKeywordMark("0"); + if (!target) { + volantis.requestAnimationFrame(fn.scrollToFirstHighlightKeywordMark) + } + } + fn.scrollToNextHighlightKeywordMark = (id) => { + // Next Id + let input = id || (fn.markNextId + 1) % fn.markNum; + fn.markNextId = parseInt(input) + let target = document.getElementById("keyword-mark-" + fn.markNextId); + if (!target) { + fn.markNextId = (fn.markNextId + 1) % fn.markNum; + target = document.getElementById("keyword-mark-" + fn.markNextId); + } + if (target) { + volantis.scroll.to(target, { addTop: - volantis.dom.header.offsetHeight - 5, behavior: 'instant' }) + } + // Current target + return target + } + fn.scrollToPrevHighlightKeywordMark = (id) => { + // Prev Id + let input = id || (fn.markNextId - 1 + fn.markNum) % fn.markNum; + fn.markNextId = parseInt(input) + let target = document.getElementById("keyword-mark-" + fn.markNextId); + if (!target) { + fn.markNextId = (fn.markNextId - 1 + fn.markNum) % fn.markNum; + target = document.getElementById("keyword-mark-" + fn.markNextId); + } + if (target) { + volantis.scroll.to(target, { addTop: - volantis.dom.header.offsetHeight - 5, behavior: 'instant' }) + } + // Current target + return target + } + fn.start = (keywords, querySelector) => { + fn.markNum = 0 + if (!keywords.length || !querySelector || (keywords.length == 1 && keywords[0] == "null")) return; + console.log(keywords); + const walk = document.createTreeWalker(querySelector, NodeFilter.SHOW_TEXT, null); + const allNodes = []; + while (walk.nextNode()) { + if (!walk.currentNode.parentNode.matches('button, select, textarea')) allNodes.push(walk.currentNode); + } + allNodes.forEach(node => { + const [indexOfNode] = fn.getIndexByWord(keywords, node.nodeValue); + if (!indexOfNode.length) return; + const slice = fn.mergeIntoSlice(0, node.nodeValue.length, indexOfNode); + fn.highlightText(node, slice, 'keyword'); + fn.highlightStyle() + }); + } + fn.getIndexByWord = (words, text, caseSensitive = false) => { + const index = []; + const included = new Set(); + words.forEach(word => { + const div = document.createElement('div'); + div.innerText = word; + word = div.innerHTML; + + const wordLen = word.length; + if (wordLen === 0) return; + let startPosition = 0; + let position = -1; + if (!caseSensitive) { + text = text.toLowerCase(); + word = word.toLowerCase(); + } + while ((position = text.indexOf(word, startPosition)) > -1) { + index.push({ position, word }); + included.add(word); + startPosition = position + wordLen; + } + }); + index.sort((left, right) => { + if (left.position !== right.position) { + return left.position - right.position; + } + return right.word.length - left.word.length; + }); + return [index, included]; + }; + fn.mergeIntoSlice = (start, end, index) => { + let item = index[0]; + let { position, word } = item; + const hits = []; + const count = new Set(); + while (position + word.length <= end && index.length !== 0) { + count.add(word); + hits.push({ + position, + length: word.length + }); + const wordEnd = position + word.length; + + index.shift(); + while (index.length !== 0) { + item = index[0]; + position = item.position; + word = item.word; + if (wordEnd > position) { + index.shift(); + } else { + break; + } + } + } + return { + hits, + start, + end, + count: count.size + }; + }; + fn.highlightText = (node, slice, className) => { + const val = node.nodeValue; + let index = slice.start; + const children = []; + for (const { position, length } of slice.hits) { + const text = document.createTextNode(val.substring(index, position)); + index = position + length; + let mark = document.createElement('mark'); + mark.className = className; + mark = fn.highlightStyle(mark) + mark.appendChild(document.createTextNode(val.substr(position, length))); + children.push(text, mark); + } + node.nodeValue = val.substring(index, slice.end); + children.forEach(element => { + node.parentNode.insertBefore(element, node); + }); + } + fn.highlightStyle = (mark) => { + if (!mark) return; + mark.id = "keyword-mark-" + fn.markNum; + fn.markNum++; + mark.style.background = "transparent"; + mark.style["border-bottom"] = "1px dashed #ff2a2a"; + mark.style["color"] = "#ff2a2a"; + mark.style["font-weight"] = "bold"; + return mark + } + fn.cleanHighlightStyle = () => { + document.querySelectorAll(".keyword").forEach(mark => { + mark.style.background = "transparent"; + mark.style["border-bottom"] = null; + mark.style["color"] = null; + mark.style["font-weight"] = null; + }) + } + return { + start: (keywords, querySelector) => { + fn.start(keywords, querySelector) + }, + startFromURL: () => { + fn.startFromURL() + }, + scrollToNextHighlightKeywordMark: (id) => { + fn.scrollToNextHighlightKeywordMark(id) + }, + scrollToPrevHighlightKeywordMark: (id) => { + fn.scrollToPrevHighlightKeywordMark(id) + }, + cleanHighlightStyle: () => { + fn.cleanHighlightStyle() + }, + } +})() +Object.freeze(highlightKeyWords); + +/* DOM 控制 */ +const DOMController = { + /** + * 控制元素显隐 + */ + visible: (ele, type = true) => { + if (ele) ele.style.display = type === true ? 'block' : 'none'; + }, + + /** + * 移除元素 + */ + remove: (param) => { + const node = document.querySelectorAll(param); + node.forEach(ele => { + ele.remove(); + }) + }, + + removeList: (list) => { + list.forEach(param => { + DOMController.remove(param) + }) + }, + + /** + * 设置属性 + */ + setAttribute: (param, attrName, attrValue) => { + const node = document.querySelectorAll(param); + node.forEach(ele => { + ele.setAttribute(attrName, attrValue) + }) + }, + + setAttributeList: (list) => { + list.forEach(item => { + DOMController.setAttribute(item[0], item[1], item[2]) + }) + }, + + /** + * 设置样式 + */ + setStyle: (param, styleName, styleValue) => { + const node = document.querySelectorAll(param); + node.forEach(ele => { + ele.style[styleName] = styleValue; + }) + }, + + setStyleList: (list) => { + list.forEach(item => { + DOMController.setStyle(item[0], item[1], item[2]) + }) + }, + + fadeIn: (e) => { + if (!e) return; + e.style.visibility = "visible"; + e.style.opacity = 1; + e.style.display = "block"; + e.style.transition = "all 0.5s linear"; + return e + }, + + fadeOut: (e) => { + if (!e) return; + e.style.visibility = "hidden"; + e.style.opacity = 0; + e.style.display = "none"; + e.style.transition = "all 0.5s linear"; + return e + }, + + fadeToggle: (e) => { + if (!e) return; + if (e.style.visibility == "hidden") { + e = DOMController.fadeIn(e) + } else { + e = DOMController.fadeOut(e) + } + return e + }, + + fadeToggleList: (list) => { + list.forEach(param => { + DOMController.fadeToggle(param) + }) + }, + + hasClass: (e, c) => { + if (!e) return; + return e.className.match(new RegExp('(\\s|^)' + c + '(\\s|$)')); + }, + + addClass: (e, c) => { + if (!e) return; + e.classList.add(c); + return e + }, + + removeClass: (e, c) => { + if (!e) return; + e.classList.remove(c); + return e + }, + + toggleClass: (e, c) => { + if (!e) return; + if (DOMController.hasClass(e, c)) { + DOMController.removeClass(e, c) + } else { + DOMController.addClass(e, c) + } + return e + }, + + toggleClassList: (list) => { + list.forEach(item => { + DOMController.toggleClass(item[0], item[1]) + }) + } +} +Object.freeze(DOMController); + +const VolantisRequest = { + timeoutFetch: (url, ms, requestInit) => { + const controller = new AbortController() + requestInit.signal?.addEventListener('abort', () => controller.abort()) + let promise = fetch(url, { ...requestInit, signal: controller.signal }) + if (ms > 0) { + const timer = setTimeout(() => controller.abort(), ms) + promise.finally(() => { clearTimeout(timer) }) + } + promise = promise.catch((err) => { + throw ((err || {}).name === 'AbortError') ? new Error(`Fetch timeout: ${url}`) : err + }) + return promise + }, + + Fetch: async (url, requestInit, timeout = 15000) => { + const resp = await VolantisRequest.timeoutFetch(url, timeout, requestInit); + if (!resp.ok) throw new Error(`Fetch error: ${url} | ${resp.status}`); + let json = await resp.json() + if (!json.success) throw json + return json + }, + + POST: async (url, data) => { + const requestInit = { + method: 'POST', + } + if (data) { + const formData = new FormData(); + Object.keys(data).forEach(key => formData.append(key, String(data[key]))) + requestInit.body = formData; + } + const json = await VolantisRequest.Fetch(url, requestInit) + return json.data; + }, + + Get: async (url, data) => { + const json = await VolantisRequest.Fetch(url + (data ? (`?${new URLSearchParams(data)}`) : ''), { + method: 'GET' + }) + } +} +Object.freeze(VolantisRequest); diff --git a/js/collapsible.js b/js/collapsible.js new file mode 100644 index 0000000000..937cf2a564 --- /dev/null +++ b/js/collapsible.js @@ -0,0 +1,8 @@ +(function (document) { + [].forEach.call(document.getElementsByClassName('collapsible'), function(panel) { + panel.getElementsByClassName('collapsible-title')[0].onclick = function() { + panel.classList.toggle("collapsed"); + panel.classList.toggle("expanded"); + } + }); +})(document); \ No newline at end of file diff --git a/js/plugins/aplayer.js b/js/plugins/aplayer.js new file mode 100644 index 0000000000..36f6d7da2c --- /dev/null +++ b/js/plugins/aplayer.js @@ -0,0 +1,186 @@ +/** + * 右键音乐 + * */ +const RightMenuAplayer = (() => { + let playStatus; // 播放器状态 + const APlayer = {}; // 右键音乐所控制的播放器 + const fn = {}; + + fn.checkAPlayer = () => { + if (playStatus === undefined || APlayer.player === undefined) { + fn.setAPlayerObject(); + } else if (APlayer.observer === undefined) { + fn.setAPlayerObserver(); + } + } + + // 设置全局播放器所对应的 aplyer 对象 + fn.setAPlayerObject = () => { + let meting = document.querySelectorAll('.footer meting-js'); + if (meting.length == 0) { + meting = document.querySelectorAll('meting-js'); + } + APlayer.player = undefined; + meting.forEach((item, index) => { + if (item.meta.id == volantis.GLOBAL_CONFIG.plugins.aplayer.id && item.aplayer && APlayer.player === undefined) { + APlayer.player = item.aplayer; + fn.setAPlayerObserver(); + fn.updateTitle(); + } + }); + } + + // 事件监听 + fn.setAPlayerObserver = () => { + try { + APlayer.player.on('play', function (e) { + fn.updateAPlayerControllerStatus(e); + APlayer.status = 'play'; + }); + APlayer.player.on('pause', function (e) { + fn.updateAPlayerControllerStatus(e); + APlayer.status = 'pause'; + }); + APlayer.player.on('volumechange', function (e) { + fn.onUpdateAPlayerVolume(e); + }); + APlayer.player.on('loadstart', function (e) { + fn.updateTitle(e); + }); + + // 监听音量手势 + APlayer.volumeBarWrap = document.getElementsByClassName('nav volume')[0].children[0]; + APlayer.volumeBar = APlayer.volumeBarWrap.children[0]; + + const thumbMove = (e) => { + fn.updateAPlayerVolume(e); + }; + + const thumbUp = (e) => { + APlayer.volumeBarWrap.classList.remove('aplayer-volume-bar-wrap-active'); + document.removeEventListener('mouseup', thumbUp); + document.removeEventListener('mousemove', thumbMove); + fn.updateAPlayerVolume(e); + }; + + APlayer.volumeBarWrap.addEventListener('mousedown', (event) => { + event.stopPropagation(); + APlayer.volumeBarWrap.classList.add('aplayer-volume-bar-wrap-active'); + document.addEventListener('mousemove', thumbMove); + document.addEventListener('mouseup', thumbUp); + }); + + APlayer.volumeBarWrap.addEventListener('click', (event) => { + event.stopPropagation(); + }); + + fn.updateAPlayerControllerStatus(); + fn.onUpdateAPlayerVolume(); + APlayer.observer = true; + } catch (error) { + console.log(error); + APlayer.observer = undefined; + } + } + + fn.updateAPlayerVolume = (e) => { + let percentage = ((e.clientX || e.changedTouches[0].clientX) - + APlayer.volumeBar.getBoundingClientRect().left) / APlayer.volumeBar.clientWidth; + percentage = Math.max(percentage, 0); + percentage = Math.min(percentage, 1); + APlayer.player.volume(percentage); + } + + fn.onUpdateAPlayerVolume = () => { + try { + APlayer.volumeBar.children[0].style.width = APlayer.player.audio.volume * 100 + '%'; + } catch (error) { + console.log(error); + } + } + + // 更新控制器状态 + fn.updateAPlayerControllerStatus = () => { + try { + if (APlayer.player.audio.paused) { + playStatus = 'pause'; + document.getElementsByClassName('nav toggle')[0].children[0].classList.add('fa-play'); + document.getElementsByClassName('nav toggle')[0].children[0].classList.remove('fa-pause'); + } else { + playStatus = 'play'; + document.getElementsByClassName('nav toggle')[0].children[0].classList.remove('fa-play'); + document.getElementsByClassName('nav toggle')[0].children[0].classList.add('fa-pause'); + } + } catch (error) { + console.log(error); + } + } + + // 播放/暂停 + fn.aplayerToggle = () => { + fn.checkAPlayer(); + try { + APlayer.player.toggle(); + } catch (error) { + console.log(error); + } + } + + // 上一曲 + fn.aplayerBackward = () => { + fn.checkAPlayer(); + try { + APlayer.player.skipBack(); + APlayer.player.play(); + } catch (error) { + console.log(error); + } + } + + // 下一曲 + fn.aplayerForward = () => { + fn.checkAPlayer(); + try { + APlayer.player.skipForward(); + APlayer.player.play(); + } catch (error) { + console.log(error); + } + } + + // 调节音量 + fn.aplayerVolume = (percent) => { + fn.checkAPlayer(); + try { + APlayer.player.volume(percent); + } catch (error) { + console.log(error); + } + } + + // 更新音乐标题 + fn.updateTitle = () => { + fn.checkAPlayer(); + try { + const index = APlayer.player.list.index; + const obj = APlayer.player.list.audios[index]; + document.getElementsByClassName('nav music-title')[0].innerHTML = obj.title; + } catch (error) { + //console.log(error); + } + } + + return { + checkAPlayer: fn.checkAPlayer, + aplayerBackward: fn.aplayerBackward, + aplayerToggle: fn.aplayerToggle, + aplayerForward: fn.aplayerForward, + APlayer: APlayer + } +})() + +Object.freeze(RightMenuAplayer); + +volantis.requestAnimationFrame(() => { + RightMenuAplayer.checkAPlayer(); +}); diff --git a/js/plugins/parallax.js b/js/plugins/parallax.js new file mode 100644 index 0000000000..c170b1961b --- /dev/null +++ b/js/plugins/parallax.js @@ -0,0 +1,191 @@ +let Parallax = {}; +Parallax.options = {}; +Parallax.options.speed = 0.25; +Parallax.options.zIndex = -100; +Parallax.options.fade = 1500; +Parallax.slidein = () => { + let slider = Parallax.mirrors[0].slider; + if (Parallax.mirrors.length >= 2) { + slider = Parallax.mirrors[1].slider; + } + var opac = parseFloat(slider.style.opacity); + if (opac !== 1) { + if (Parallax.mirrors.length >= 2) { + opac = opac + 0.1; + slider.style.opacity = opac; + setTimeout(Parallax.slidein, Parallax.options.fade / 10); + }else{ + slider.style.opacity = 1; + } + } else { + if (Parallax.mirrors.length >= 2) { + Parallax.mirrors[0].mirror.remove(); + Parallax.mirrors.shift(); + } + } +}; +Parallax.start = () => { + let mirror = document.createElement("div"); + mirror.classList.add("parallax-mirror"); + mirror.style.visibility = "hidden"; + mirror.style.zIndex = Parallax.options.zIndex; + mirror.style.position = "fixed"; + mirror.style.top = 0; + mirror.style.left = 0; + mirror.style.overflow = "hidden"; + Parallax.window.appendChild(mirror); + let slider = document.createElement("img"); + slider.src = Parallax.options.src; + slider.alt = "parallax"; + slider.classList.add("parallax-slider"); + slider.style.opacity = 0; + mirror.appendChild(slider); + if (!Parallax.mirrors) { + Parallax.mirrors = []; + } + let mirrorItem = {}; + mirrorItem.mirror = mirror; + mirrorItem.slider = slider; + Parallax.mirrors.push(mirrorItem); + Parallax.slidein(); + slider.addEventListener( + "load", + function () { + Parallax.update(); + }, + false + ); +}; +Parallax.init = () => { + function loadDimensions() { + Parallax.wH = document.documentElement.clientHeight; + Parallax.wW = document.documentElement.clientWidth; + } + function getScrollTop() { + var scrollPos; + if (window.pageYOffset) { + scrollPos = window.pageYOffset; + } else if (document.compatMode && document.compatMode != "BackCompat") { + scrollPos = document.documentElement.scrollTop; + } else if (document.body) { + scrollPos = document.body.scrollTop; + } + return scrollPos; + } + function loadScrollPosition() { + const winScrollTop = getScrollTop(); + Parallax.sT = Math.max(0, winScrollTop); + Parallax.sL = Math.max(0, document.body.scrollLeft); + Parallax.overScroll = Math.min(winScrollTop, 0); + } + window.addEventListener( + "resize", + function () { + loadDimensions(); + Parallax.update(); + }, + false + ); + loadDimensions(); + let lastPosition = -1; + (function loop() { + const yoffset = getScrollTop(); + if (lastPosition !== yoffset) { + lastPosition = yoffset; + loadScrollPosition(); + Parallax.update(); + } + window.requestAnimationFrame = + window.requestAnimationFrame || + window.mozRequestAnimationFrame || + window.webkitRequestAnimationFrame; + window.requestAnimationFrame(loop); + })(); +}; + +Parallax.refreshItem = (slider) => { + Parallax.options.aspectRatio = + slider.naturalWidth / (slider.naturalHeight || 1); + const aspect = Parallax.options.aspectRatio || 1; + Parallax.options.boxWidth = Parallax.window.clientWidth; + Parallax.options.boxHeight = Parallax.window.clientHeight; + Parallax.options.boxOffsetTop = Parallax.window.scrollTop; + Parallax.options.boxOffsetLeft = Parallax.window.scrollLeft; + Parallax.options.boxOffsetBottom = + Parallax.options.boxOffsetTop + Parallax.options.boxHeight; + const winHeight = Parallax.wH; + const maxOffset = Parallax.options.boxOffsetTop; + const minOffset = Math.max( + Parallax.options.boxOffsetTop + Parallax.options.boxHeight - winHeight, + 0 + ); + const imageHeightMin = + (Parallax.options.boxHeight + + (maxOffset - minOffset) * (1 - Parallax.options.speed)) | + 0; + const imageOffsetMin = + ((Parallax.options.boxOffsetTop - maxOffset) * + (1 - Parallax.options.speed)) | + 0; + let margin; + if (Parallax.options.boxWidth < imageHeightMin * aspect) { + Parallax.options.imageWidth = (imageHeightMin * aspect) | 0; + Parallax.options.imageHeight = imageHeightMin; + Parallax.options.offsetBaseTop = imageOffsetMin; + margin = Parallax.options.imageWidth - Parallax.options.boxWidth; + Parallax.options.offsetLeft = (-margin / 2) | 0; + } else { + Parallax.options.imageWidth = Parallax.options.boxWidth; + Parallax.options.imageHeight = (Parallax.options.boxWidth / aspect) | 0; + Parallax.options.offsetLeft = 0; + margin = Parallax.options.imageHeight - imageHeightMin; + Parallax.options.offsetBaseTop = (imageOffsetMin - margin / 2) | 0; + } +}; +Parallax.renderItem = (mirror, slider) => { + const scrollTop = Parallax.sT; + const scrollLeft = Parallax.sL; + const scrollBottom = scrollTop + Parallax.wH; + if ( + Parallax.options.boxOffsetBottom > scrollTop && + Parallax.options.boxOffsetTop <= scrollBottom + ) { + Parallax.options.visibility = "visible"; + Parallax.options.mirrorTop = Parallax.options.boxOffsetTop - scrollTop; + Parallax.options.mirrorLeft = Parallax.options.boxOffsetLeft - scrollLeft; + Parallax.options.offsetTop = + Parallax.options.offsetBaseTop - + Parallax.options.mirrorTop * (1 - Parallax.options.speed); + } else { + Parallax.options.visibility = "hidden"; + } + mirror.style.transform = + "translate3d(" + + Parallax.options.mirrorLeft + + "px, " + + Parallax.options.mirrorTop + + "px, 0px)"; + mirror.style.visibility = Parallax.options.visibility; + mirror.style.height = Parallax.options.boxHeight + "px"; + mirror.style.width = Parallax.options.boxWidth + "px"; + + slider.style.transform = + "translate3d(" + + Parallax.options.offsetLeft + + "px, " + + Parallax.options.offsetTop + + "px, 0px)"; + slider.style.position = "absolute"; + slider.style.height = Parallax.options.imageHeight + "px"; + slider.style.width = Parallax.options.imageWidth + "px"; + slider.style.maxWidth = "none"; +}; +Parallax.update = () => { + if (!Parallax.mirrors) { + return + } + Parallax.mirrors.forEach((e) => { + Parallax.refreshItem(e.slider); + Parallax.renderItem(e.mirror, e.slider); + }); +}; diff --git a/js/plugins/rightMenus.js b/js/plugins/rightMenus.js new file mode 100644 index 0000000000..980b12172b --- /dev/null +++ b/js/plugins/rightMenus.js @@ -0,0 +1,618 @@ + +const RightMenus = { + defaultEvent: ['copyText', 'copyLink', 'copyPaste', 'copyAll', 'copyCut', 'copyImg', 'printMode', 'readMode'], + defaultGroup: ['navigation', 'inputBox', 'seletctText', 'elementCheck', 'elementImage', 'articlePage'], + messageRightMenu: volantis.GLOBAL_CONFIG.plugins.message.enable && volantis.GLOBAL_CONFIG.plugins.message.rightmenu.enable, + corsAnywhere: volantis.GLOBAL_CONFIG.plugins.rightmenus.options.corsAnywhere, + urlRegx: /^((https|http)?:\/\/)+[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^<>\"\"])*$/, + imgRegx: /\.(jpe?g|png|webp|svg|gif|jifi)(-|_|!|\?|\/)?.*$/, + + /** + * 加载右键菜单 + */ + initialMenu: () => { + RightMenus.fun.init(); + }, + + /** + * 读取剪切板 + * @returns text + */ + readClipboard: async () => { + let clipboardText; + const result = await navigator.permissions.query({ name: 'clipboard-read' }); + switch (result.state) { + case 'granted': + case 'prompt': + clipboardText = await navigator.clipboard.readText() + break; + default: + window.clipboardRead = false; + break; + } + return clipboardText; + }, + + /** + * 写入文本到剪切板 + * @param {String} text + */ + writeClipText: text => { + return navigator.clipboard + .writeText(text) + .then(() => { + return Promise.resolve() + }) + .catch(err => { + return Promise.reject(err) + }) + }, + + /** + * 写入图片到剪切板 + * @param {*} link + * @param {*} success + * @param {*} error + */ + writeClipImg: async (link, success, error) => { + const image = new Image; + image.crossOrigin = "Anonymous"; + image.addEventListener('load', () => { + let canvas = document.createElement("canvas"); + let context = canvas.getContext("2d"); + canvas.width = image.width; + canvas.height = image.height; + context.drawImage(image, 0, 0); + canvas.toBlob(blob => { + navigator.clipboard.write([ + new ClipboardItem({ 'image/png': blob }) + ]).then(e => { + success(e) + }).catch(e => { + error(e) + }) + }, 'image/png') + }, false) + image.src = `${link}?(lll¬ω¬)`; + }, + + /** + * 粘贴文本到剪切板 + * @param {*} elemt + * @param {*} value + */ + insertAtCaret: (elemt, value) => { + const startPos = elemt.selectionStart, + endPos = elemt.selectionEnd; + if (document.selection) { + elemt.focus(); + var sel = document.selection.createRange(); + sel.text = value; + elemt.focus(); + } else { + if (startPos || startPos == '0') { + var scrollTop = elemt.scrollTop; + elemt.value = elemt.value.substring(0, startPos) + value + elemt.value.substring(endPos, elemt.value.length); + elemt.focus(); + elemt.selectionStart = startPos + value.length; + elemt.selectionEnd = startPos + value.length; + elemt.scrollTop = scrollTop; + } else { + elemt.value += value; + elemt.focus(); + } + } + } +} + +/** + * 事件处理区域 + */ +RightMenus.fun = (() => { + const rightMenuConfig = volantis.GLOBAL_CONFIG.plugins.rightmenus; + + const + fn = {}, + _rightMenuWrapper = document.getElementById('rightmenu-wrapper'), + _rightMenuContent = document.getElementById('rightmenu-content'), + _rightMenuList = document.querySelectorAll('#rightmenu-content li.menuLoad-Content'), + _rightMenuListWithHr = document.querySelectorAll('#rightmenu-content li, #rightmenu-content hr, #menuMusic'), + _readBkg = document.getElementById('read_bkg'), + _menuMusic = document.getElementById('menuMusic'), + _backward = document.querySelector('#menuMusic .backward'), + _toggle = document.querySelector('#menuMusic .toggle'), + _forward = document.querySelector('#menuMusic .forward'); + + // 公共数据 + let globalData = { + mouseEvent: null, + isInputBox: false, + selectText: '', + inputValue: '', + isLink: false, + linkUrl: '', + isMediaLink: false, + mediaLinkUrl: '', + isImage: false, + isArticle: false, + pathName: '', + isReadClipboard: true, + isShowMusic: false, + statusCheck: false + } + const globalDataBackup = Object.assign({}, globalData); + + /** + * 初始化监听事件处理 + */ + fn.initEvent = () => { + fn.elementAppend(); + fn.contextmenu(); + fn.menuEvent(); + } + + /** + * 预置元素设定 + */ + fn.elementAppend = () => { + // 阅读模式 + if (_readBkg) _readBkg.parentNode.removeChild(_readBkg); + const readBkg = document.createElement("div"); + readBkg.className = "common_read_bkg common_read_hide"; + readBkg.id = "read_bkg"; + window.document.body.appendChild(readBkg); + } + + /** + * 右键菜单位置设定 + * @param {*} event + */ + fn.menuPosition = (event) => { + try { + let mouseClientX = event.clientX; + let mouseClientY = event.clientY; + let screenWidth = document.documentElement.clientWidth || document.body.clientWidth; + let screenHeight = document.documentElement.clientHeight || document.body.clientHeight; + + _rightMenuWrapper.style.display = 'block'; + fn.menuControl(event); + + let menuWidth = _rightMenuContent.offsetWidth; + let menuHeight = _rightMenuContent.offsetHeight; + let showLeft = mouseClientX + menuWidth > screenWidth ? mouseClientX - menuWidth + 10 : mouseClientX; + let showTop = mouseClientY + menuHeight > screenHeight ? mouseClientY - menuHeight + 10 : mouseClientY; + showTop = mouseClientY + menuHeight > screenHeight && showTop < menuHeight && mouseClientY < menuHeight ? + showTop + (screenHeight - menuHeight - showTop - 10) : showTop; + _rightMenuWrapper.style.left = `${showLeft}px`; + _rightMenuWrapper.style.top = `${showTop}px`; + if (volantis.GLOBAL_CONFIG.plugins.message.rightmenu.notice) fn.menuNotic(); + } catch (error) { + console.error(error); + fn.hideMenu(); + return true; + } + return false; + } + + /** + * 菜单项控制 + * @param {*} event + */ + fn.menuControl = (event) => { + fn.globalDataSet(event); + if (!!_menuMusic) _menuMusic.style.display = globalData.isShowMusic ? 'block' : 'none'; + _rightMenuList.forEach(item => { + item.style.display = 'none'; + const nodeName = item.firstElementChild.nodeName; + const groupName = item.firstElementChild.getAttribute('data-group'); + const itemEvent = item.firstElementChild.getAttribute('data-event'); + if (globalData.statusCheck || globalData.isArticle) { + switch (groupName) { + case 'inputBox': + if (globalData.isInputBox) { + item.style.display = 'block'; + if (itemEvent === 'copyCut' && !globalData.selectText) item.style.display = 'none'; + if (itemEvent === 'copyAll' && !globalData.inputValue) item.style.display = 'none'; + if (itemEvent === 'copyPaste' && !globalData.isReadClipboard) item.style.display = 'none'; + } + break; + case 'seletctText': + if (!!globalData.selectText) item.style.display = 'block'; + break; + case 'elementCheck': + if (globalData.isLink || globalData.isMediaLink) item.style.display = 'block'; + break; + case 'elementImage': + if (globalData.isImage) item.style.display = 'block'; + break; + case 'articlePage': + if (globalData.isArticle) item.style.display = 'block'; + break; + default: + item.style.display = nodeName === 'A' + ? globalData.isArticle && !globalData.statusCheck && rightMenuConfig.options.articleShowLink + ? 'block' + : 'none' + : 'block'; + break; + } + } else if (nodeName === 'A' || RightMenus.defaultGroup.every(item => { return groupName !== item })) { + item.style.display = 'block'; + } + }) + + // 执行外部事件 + volantis.mouseEvent = event; + volantis.rightmenu.method.handle.start() + + // 过滤 HR 元素 + let elementHrItem = { item: null, hide: true }; + _rightMenuListWithHr.forEach((item) => { + if (item.nodeName === "HR") { + item.style.display = 'block'; + if (!elementHrItem.item) { + elementHrItem.item = item; + return; + } + if (elementHrItem.hide || elementHrItem.item.nextElementSibling.nodeName === "hr") { + elementHrItem.item.style.display = 'none'; + } + elementHrItem.item = item; + elementHrItem.hide = true; + } else { + if (item.style.display === 'block' && elementHrItem.hide) { + elementHrItem.hide = false; + } + } + }) + if (!!elementHrItem.item && elementHrItem.hide) elementHrItem.item.style.display = 'none'; + } + + /** + * 元素状态判断/全局数据设置 + * @param {*} event + */ + fn.globalDataSet = (event) => { + globalData = Object.assign({}, globalDataBackup); + globalData.mouseEvent = event; + globalData.selectText = window.getSelection().toString(); + + // 判断是否为输入框 + if (event.target.tagName.toLowerCase() === 'input' || event.target.tagName.toLowerCase() === 'textarea') { + globalData.isInputBox = true; + globalData.inputValue = event.target.value; + } + + // 判断是否允许读取剪切板 + if (globalData.isInputBox && window.clipboardRead === false) { + globalData.isReadClipboard = false; + } + + // 判断是否包含链接 + if (!!event.target.href && RightMenus.urlRegx.test(event.target.href)) { + globalData.isLink = true; + globalData.linkUrl = event.target.href; + } + + // 判断是否包含媒体链接 + if (!!event.target.currentSrc && RightMenus.urlRegx.test(event.target.currentSrc)) { + globalData.isMediaLink = true; + globalData.mediaLinkUrl = event.target.currentSrc; + } + + // 判断是否为图片地址 + if (globalData.isMediaLink && RightMenus.imgRegx.test(globalData.mediaLinkUrl)) { + globalData.isImage = true; + } + + // 判断是否为文章页面 + if (!!(document.querySelector('#post.article') || null)) { + globalData.isArticle = true; + globalData.pathName = window.location.pathname; + } + + // 判断是否显示音乐控制器 + if (volantis.GLOBAL_CONFIG.plugins.aplayer?.enable + && typeof RightMenuAplayer !== 'undefined' + && RightMenuAplayer.APlayer.player !== undefined) { + if (rightMenuConfig.options.musicAlwaysShow + || RightMenuAplayer.APlayer.status === 'play' + || RightMenuAplayer.APlayer.status === 'undefined') { + globalData.isShowMusic = true; + } + } + + // 设定校验状态 + if (!!globalData.selectText || globalData.isInputBox || globalData.isLink || globalData.isMediaLink) { + globalData.statusCheck = true; + } + } + + /** + * 全局右键监听函数 + */ + fn.contextmenu = () => { + window.document.oncontextmenu = (event) => { + if (event.ctrlKey || document.body.offsetWidth <= 500) { + fn.hideMenu(); + return true; + } + return fn.menuPosition(event); + } + + _rightMenuWrapper.oncontextmenu = (event) => { + event.stopPropagation(); + event.preventDefault(); + return false; + } + + window.removeEventListener('blur', fn.hideMenu); + window.addEventListener('blur', fn.hideMenu); + document.body.removeEventListener('click', fn.hideMenu); + document.body.addEventListener('click', fn.hideMenu); + } + + /** + * 菜单项事件处理函数 + */ + fn.menuEvent = () => { + _rightMenuList.forEach(item => { + let eventName = item.firstElementChild.getAttribute('data-event'); + const id = item.firstElementChild.getAttribute('id'); + const groupName = item.firstElementChild.getAttribute('data-group'); + if (item.firstElementChild.nodeName === "A") return; + item.addEventListener('click', () => { + try { + if (RightMenus.defaultEvent.every(item => { return eventName !== item })) { + if (groupName === 'seletctText') { + RightMenusFunction[id](globalData.selectText) + } else if (groupName === 'elementCheck') { + RightMenusFunction[id](globalData.isLink ? globalData.linkUrl : globalData.mediaLinkUrl) + } else if (groupName === 'elementImage') { + RightMenusFunction[id](globalData.mediaLinkUrl) + } else { + RightMenusFunction[id]() + } + } else { + fn[eventName]() + } + } catch (error) { + if (volantis.GLOBAL_CONFIG.debug === "rightMenus") { + console.error({ + id: id, + error: error, + globalData: globalData, + groupName: groupName, + eventName: eventName + }); + } + if (RightMenus.messageRightMenu) { + VolantisApp.message('错误提示', error, { + icon: rightMenuConfig.options.iconPrefix + ' fa-exclamation-square red', + time: '15000' + }); + } + } + }) + }) + + if (_forward && _toggle && _forward) { + _backward.onclick = (e) => { + e.preventDefault(); + e.stopPropagation(); + RightMenuAplayer.aplayerBackward(); + } + _toggle.onclick = (e) => { + e.preventDefault(); + e.stopPropagation(); + RightMenuAplayer.aplayerToggle(); + } + _forward.onclick = (e) => { + e.preventDefault(); + e.stopPropagation(); + RightMenuAplayer.aplayerForward(); + } + } + } + + /** + * 隐藏菜单显示 + */ + fn.hideMenu = () => { + _rightMenuWrapper.style.display = null; + _rightMenuWrapper.style.left = null; + _rightMenuWrapper.style.top = null; + } + + /** + * 右键菜单覆盖提示 + */ + fn.menuNotic = () => { + const NoticeRightMenu = localStorage.getItem('NoticeRightMenu') === 'true'; + if (RightMenus.messageRightMenu && !NoticeRightMenu) + VolantisApp.message('右键菜单', '唤醒原系统菜单请使用:Ctrl + 右键', { + icon: rightMenuConfig.options.iconPrefix + ' fa-exclamation-square red', + displayMode: 1, + time: 9000 + }, () => { + localStorage.setItem('NoticeRightMenu', 'true') + }); + } + + fn.copyText = () => { + VolantisApp.utilWriteClipText(globalData.selectText) + .then(() => { + if (RightMenus.messageRightMenu) { + VolantisApp.messageCopyright(); + } + }).catch(e => { + if (RightMenus.messageRightMenu) { + VolantisApp.message('系统提示', e, { + icon: rightMenuConfig.options.iconPrefix + ' fa-exclamation-square red', + displayMode: 1, + time: 9000 + }); + } + }) + } + + fn.copyLink = () => { + VolantisApp.utilWriteClipText(globalData.linkUrl || globalData.mediaLinkUrl) + .then(() => { + if (RightMenus.messageRightMenu) { + VolantisApp.messageCopyright(); + } + }).catch(e => { + if (RightMenus.messageRightMenu) { + VolantisApp.message('系统提示', e, { + icon: rightMenuConfig.options.iconPrefix + ' fa-exclamation-square red', + displayMode: 1, + time: 9000 + }); + } + }) + } + + fn.copyAll = () => { + globalData.mouseEvent.target.select(); + } + + fn.copyPaste = async () => { + const result = await RightMenus.readClipboard() || ''; + if (RightMenus.messageRightMenu && window.clipboardRead === false) { + VolantisApp.message('系统提示', '未授予剪切板读取权限!'); + } else if (RightMenus.messageRightMenu && result === '') { + VolantisApp.message('系统提示', '仅支持复制文本内容!'); + } else { + RightMenus.insertAtCaret(globalData.mouseEvent.target, result); + } + } + + fn.copyCut = () => { + const statrPos = globalData.mouseEvent.target.selectionStart; + const endPos = globalData.mouseEvent.target.selectionEnd; + const inputStr = globalData.inputValue; + fn.copyText(globalData.selectText); + globalData.mouseEvent.target.value = inputStr.substring(0, statrPos) + inputStr.substring(endPos, inputStr.length); + globalData.mouseEvent.target.selectionStart = statrPos; + globalData.mouseEvent.target.selectionEnd = statrPos; + globalData.mouseEvent.target.focus(); + } + + fn.copyImg = () => { + if (volantis.GLOBAL_CONFIG.plugins.message.rightmenu.notice) { + VolantisApp.message('系统提示', '复制中,请等待。', { + icon: rightMenuConfig.options.iconPrefix + ' fa-images' + }) + } + RightMenus.writeClipImg(globalData.mediaLinkUrl, e => { + if (RightMenus.messageRightMenu) { + VolantisApp.hideMessage(); + VolantisApp.message('系统提示', '图片复制成功!', { + icon: rightMenuConfig.options.iconPrefix + ' fa-images' + }); + } + }, (e) => { + console.error(e); + if (RightMenus.messageRightMenu) { + VolantisApp.hideMessage(); + VolantisApp.message('系统提示', '复制失败:' + e, { + icon: rightMenuConfig.options.iconPrefix + ' fa-exclamation-square red', + time: 9000 + }); + } + }) + } + + fn.printMode = () => { + if (window.location.pathname === globalData.pathName) { + if (RightMenus.messageRightMenu) { + const message = '是否打印当前页面?
建议打印时勾选背景图形
' + VolantisApp.question('', message, { time: 9000 }, () => { fn.printHtml() }) + } else { + fn.printHtml() + } + } + } + + fn.printHtml = () => { + if (volantis.isReadModel) fn.readMode(); + DOMController.setAttribute('details', 'open', 'true'); + DOMController.removeList([ + '.cus-article-bkg', '.iziToast-overlay', '.iziToast-wrapper', '.prev-next', + 'footer', '#l_header', '#l_cover', '#l_side', '#comments', '#s-top', '#BKG', + '#rightmenu-wrapper', '.nav-tabs', '.parallax-mirror', '.new-meta-item.share', + '.new-meta-box', 'button.btn-copy', 'iframe' + ]); + DOMController.setStyleList([ + ['body', 'backgroundColor', 'unset'], ['#l_main, .copyright.license', 'width', '100%'], + ['#post', 'boxShadow', 'none'], ['#post', 'background', 'none'], ['#post', 'padding', '0'], + ['h1', 'textAlign', 'center'], ['h1', 'fontWeight', '600'], ['h1', 'fontSize', '2rem'], ['h1', 'marginBottom', '20px'], + ['.tab-pane', 'display', 'block'], ['.tab-content', 'borderTop', 'none'], ['.highlight>table pre', 'whiteSpace', 'pre-wrap'], + ['.highlight>table pre', 'wordBreak', 'break-all'], ['.fancybox img', 'height', 'auto'], ['.fancybox img', 'weight', 'auto'], + ['.copyright.license', 'margin', '0'], ['.copyright.license', 'padding', '1.25em 20px'], + ['figure.highlight, .copyright.license', 'display', 'inline-block'], + ]); + setTimeout(() => { + window.print(); + document.body.innerHTML = ''; + window.location.reload(); + }, 50); + } + + fn.readMode = () => { + if (typeof ScrollReveal === 'function') ScrollReveal().clean('#comments'); + DOMController.setStyle('#l_header', 'opacity', 0); + DOMController.fadeToggleList([ + document.querySelector('#l_cover'), document.querySelector('footer'), + document.querySelector('#s-top'), document.querySelector('.article-meta#bottom'), + document.querySelector('.prev-next'), document.querySelector('#l_side'), + document.querySelector('#comments'), + ]); + DOMController.toggleClassList([ + [document.querySelector('#l_main'), 'common_read'], [document.querySelector('#l_main'), 'common_read_main'], + [document.querySelector('#l_body'), 'common_read'], [document.querySelector('#safearea'), 'common_read'], + [document.querySelector('#read_bkg'), 'common_read_hide'], + [document.querySelector('h1'), 'common_read_h1'], [document.querySelector('#post'), 'post_read'], + [document.querySelector('#l_cover'), 'read_cover'], [document.querySelector('.widget.toc-wrapper'), 'post_read'] + ]); + DOMController.setStyle('.copyright.license', 'margin', '15px 0'); + volantis.isReadModel = volantis.isReadModel === undefined ? true : !volantis.isReadModel; + if (volantis.isReadModel) { + if (RightMenus.messageRightMenu) VolantisApp.message('系统提示', '阅读模式已开启,您可以点击屏幕空白处退出。', { + backgroundColor: 'var(--color-read-post)', + icon: rightMenuConfig.options.iconPrefix + ' fa-book-reader', + displayMode: 1, + time: 5000 + }); + document.querySelector('#l_body').removeEventListener('click', fn.readMode); + document.querySelector('#l_body').addEventListener('click', (event) => { + if (DOMController.hasClass(event.target, 'common_read')) { + fn.readMode(); + } + }); + } else { + document.querySelector('#l_body').removeEventListener('click', fn.readMode); + document.querySelector('#post').removeEventListener('click', fn.readMode); + DOMController.setStyle('.prev-next', 'display', 'flex'); + DOMController.setStyle('.copyright.license', 'margin', '15px -40px'); + } + } + + return { + init: fn.initEvent, + hideMenu: fn.hideMenu, + readMode: fn.readMode + } +})() + +Object.freeze(RightMenus); +volantis.requestAnimationFrame(() => { + if (document.readyState !== 'loading') { + RightMenus.initialMenu(); + } else { + document.addEventListener("DOMContentLoaded", function () { + RightMenus.initialMenu(); + }) + } +}); diff --git a/js/plugins/tags/contributors.js b/js/plugins/tags/contributors.js new file mode 100644 index 0000000000..6a273f9d43 --- /dev/null +++ b/js/plugins/tags/contributors.js @@ -0,0 +1,89 @@ +const ContributorsJS = { + requestAPI: (url, callback, timeout) => { + let retryTimes = 5; + + function request() { + return new Promise((resolve, reject) => { + let status = 0; // 0 等待 1 完成 2 超时 + let timer = setTimeout(() => { + if (status === 0) { + status = 2; + timer = null; + reject('请求超时'); + if (retryTimes == 0) { + timeout(); + } + } + }, 5000); + fetch(url).then(function (response) { + if (status !== 2) { + clearTimeout(timer); + resolve(response); + timer = null; + status = 1; + } + if (response.ok) { + return response.json(); + } + throw new Error('Network response was not ok.'); + }).then(function (data) { + retryTimes = 0; + callback(data); + }).catch(function (error) { + if (retryTimes > 0) { + retryTimes -= 1; + setTimeout(() => { + request(); + }, 5000); + } else { + timeout(); + } + }); + }); + } + request(); + }, + layout: (cfg) => { + const el = cfg.el; + ContributorsJS.requestAPI(cfg.api, function (data) { + el.querySelector('.loading-wrap').remove(); + var cellALL = ""; + (data || []).forEach((item, i) => { + var user = '
'; + user += ''; + user += '' + item.login + ''; + user += '
' + item.login + '
'; + user += '
'; + user += '
'; + cellALL += user; + }); + el.querySelector('.group-body').innerHTML = cellALL; + }, function () { + try { + el.querySelector('.loading-wrap svg').remove(); + el.querySelector('.loading-wrap p').innerText('加载失败,请稍后重试。'); + } catch (e) { } + }); + }, + start: () => { + const els = document.getElementsByClassName('contributorsjs-wrap'); + for (var i = 0; i < els.length; i++) { + const el = els[i]; + const api = el.getAttribute('api'); + if (api == null) { + continue; + } + var cfg = new Object(); + cfg.el = el; + cfg.api = api; + cfg.class = el.getAttribute('class'); + cfg.avatar = volantis.GLOBAL_CONFIG.default.avatar; + ContributorsJS.layout(cfg); + } + } +} + + + +ContributorsJS.start(); \ No newline at end of file diff --git a/js/plugins/tags/friends.js b/js/plugins/tags/friends.js new file mode 100644 index 0000000000..8a0201c57c --- /dev/null +++ b/js/plugins/tags/friends.js @@ -0,0 +1,90 @@ +const FriendsJS = { + requestAPI: (url, callback, timeout) => { + let retryTimes = 5; + + function request() { + return new Promise((resolve, reject) => { + let status = 0; // 0 等待 1 完成 2 超时 + let timer = setTimeout(() => { + if (status === 0) { + status = 2; + timer = null; + reject('请求超时'); + if (retryTimes == 0) { + timeout(); + } + } + }, 5000); + fetch(url).then(function (response) { + if (status !== 2) { + clearTimeout(timer); + resolve(response); + timer = null; + status = 1; + } + if (response.ok) { + return response.json(); + } + throw new Error('Network response was not ok.'); + }).then(function (data) { + retryTimes = 0; + callback(data); + }).catch(function (error) { + if (retryTimes > 0) { + retryTimes -= 1; + setTimeout(() => { + request(); + }, 5000); + } else { + timeout(); + } + }); + }); + } + request(); + }, + layout: (cfg) => { + const el = cfg.el; + FriendsJS.requestAPI(cfg.api, function (data) { + el.querySelector('.loading-wrap').remove(); + const arr = data.content; + var cellALL = ""; + arr.forEach((item, i) => { + var user = '
'; + user += ''; + user += '' + item.title + ''; + user += '
' + item.title + '
'; + user += '
'; + user += '
'; + cellALL += user; + }); + el.querySelector('.group-body').innerHTML = cellALL; + }, function () { + try { + el.querySelector('.loading-wrap svg').remove(); + el.querySelector('.loading-wrap p').innerText('加载失败,请稍后重试。'); + } catch (e) { } + }); + }, + start: () => { + const els = document.getElementsByClassName('friendsjs-wrap'); + for (var i = 0; i < els.length; i++) { + const el = els[i]; + const api = el.getAttribute('api'); + if (api == null) { + continue; + } + var cfg = new Object(); + cfg.el = el; + cfg.api = api; + cfg.class = el.getAttribute('class'); + cfg.avatar = volantis.GLOBAL_CONFIG.default.avatar; + FriendsJS.layout(cfg); + } + } +} + + + +FriendsJS.start(); \ No newline at end of file diff --git a/js/plugins/tags/sites.js b/js/plugins/tags/sites.js new file mode 100644 index 0000000000..d85907f74a --- /dev/null +++ b/js/plugins/tags/sites.js @@ -0,0 +1,93 @@ +const SitesJS = { + requestAPI: (url, callback, timeout) => { + let retryTimes = 5; + + function request() { + return new Promise((resolve, reject) => { + let status = 0; // 0 等待 1 完成 2 超时 + let timer = setTimeout(() => { + if (status === 0) { + status = 2; + timer = null; + reject('请求超时'); + if (retryTimes == 0) { + timeout(); + } + } + }, 5000); + fetch(url).then(function (response) { + if (status !== 2) { + clearTimeout(timer); + resolve(response); + timer = null; + status = 1; + } + if (response.ok) { + return response.json(); + } + throw new Error('Network response was not ok.'); + }).then(function (data) { + retryTimes = 0; + callback(data); + }).catch(function (error) { + if (retryTimes > 0) { + retryTimes -= 1; + setTimeout(() => { + request(); + }, 5000); + } else { + timeout(); + } + }); + }); + } + request(); + }, + layout: (cfg) => { + const el = cfg.el; + SitesJS.requestAPI(cfg.api, function (data) { + el.querySelector('.loading-wrap').remove(); + const arr = data.content; + var cellALL = ""; + arr.forEach((item, i) => { + var cell = '
'; + cell += ''; + cell += '' + item.title + ''; + cell += '
'; + cell += '' + item.title + ''; + cell += '' + item.title + ''; + cell += '' + (item.description || item.url) + ''; + cell += '
'; + cell += '
'; + cell += '
'; + cellALL += cell; + }); + el.querySelector('.group-body').innerHTML = cellALL; + }, function () { + try { + el.querySelector('.loading-wrap svg').remove(); + el.querySelector('.loading-wrap p').innerText('加载失败,请稍后重试。'); + } catch (e) { } + }); + }, + start: (cfg) => { + const els = document.getElementsByClassName('sitesjs-wrap'); + for (var i = 0; i < els.length; i++) { + const el = els[i]; + const api = el.getAttribute('api'); + if (api == null) { + continue; + } + var cfg = new Object(); + cfg.class = el.getAttribute('class'); + cfg.el = el; + cfg.api = api; + cfg.avatar = volantis.GLOBAL_CONFIG.default.link; + cfg.screenshot = volantis.GLOBAL_CONFIG.default.cover; + SitesJS.layout(cfg); + } + } +} + + +SitesJS.start(); \ No newline at end of file diff --git a/js/search/algolia.js b/js/search/algolia.js new file mode 100644 index 0000000000..513472a51a --- /dev/null +++ b/js/search/algolia.js @@ -0,0 +1,235 @@ +let SearchService = (() => { + const fn = {}; + let search, algolia, timerId; + fn.queryText = null; + fn.template = ` + `; + + fn.init = () => { + let div = document.createElement("div"); + div.innerHTML += fn.template; + document.body.append(div); + + algolia = volantis.GLOBAL_CONFIG.search; + if (algolia.appId && algolia.apiKey && algolia.indexName) { + fn.event(); + fn.setAlgolia(); + } else { + document.querySelector('#u-search main.modal-body').innerHTML = 'Algolia setting is invalid!'; + document.querySelector('#u-search main.modal-body').style.textAlign = 'center'; + document.querySelector('#u-search .modal').style.maxHeight = '128px'; + } + } + + fn.event = () => { + document + .querySelector("#u-search-btn-close") + .addEventListener("click", fn.close, false); + document + .querySelector("#modal-overlay") + .addEventListener("click", fn.close, false); + document.querySelectorAll(".u-search-form").forEach((e) => { + e.addEventListener("submit", fn.onSubmit, false); + }); + document.querySelector("#algolia-search-input").addEventListener("input", event => { + let input = event.target.querySelector(".ais-SearchBox-input"); + if (input) { + fn.queryText = input.value; + } else { + fn.queryText = event.target.value; + } + }) + } + + fn.setAlgolia = () => { + search = instantsearch({ + indexName: algolia.indexName, + searchClient: algoliasearch(algolia.appId, algolia.apiKey), + searchFunction(helper) { + helper.state.query && helper.search() + }, + }) + + const configure = instantsearch.widgets.configure({ + hitsPerPage: algolia.hitsPerPage + }) + + const searchBox = instantsearch.widgets.searchBox({ + container: '#algolia-search-input', + autofocus: true, + showReset: false, + showSubmit: false, + showLoadingIndicator: false, + searchAsYouType: algolia.searchAsYouType, + placeholder: algolia.placeholder, + templates: { + input: 'algolia-input' + }, + queryHook(query, refine) { + clearTimeout(timerId) + timerId = setTimeout(() => refine(query), 500) + } + }) + + const hits = instantsearch.widgets.hits({ + container: '#algolia-hits', + templates: { + item(data) { + const keyword = !!fn.queryText ? `?keyword=${fn.queryText}` : '' + const link = data.permalink ? data.permalink : `${volantis.GLOBAL_CONFIG.root}${data.path}` + const result = data._highlightResult + const content = result.contentStripTruncate + ? fn.cutContent(result.contentStripTruncate.value) + : result.contentStrip + ? fn.cutContent(result.contentStrip.value) + : result.content + ? fn.cutContent(result.content.value) + : '' + return ` + + ${result.title.value || 'no-title'} + ${content} + ` + }, + empty: function (data) { + return ( + `

${volantis.GLOBAL_CONFIG.languages.search.hits_empty.replace(/\$\{query}/, data.query)}

` + ) + } + } + }) + + const stats = instantsearch.widgets.stats({ + container: '#algolia-info > .algolia-stats', + templates: { + text: function (data) { + const stats = volantis.GLOBAL_CONFIG.languages.search.hits_stats + .replace(/\$\{hits}/, data.nbHits) + .replace(/\$\{time}/, data.processingTimeMS) + return ( + `${stats}` + ) + } + } + }) + + const powerBy = instantsearch.widgets.poweredBy({ + container: '#algolia-info > .algolia-poweredBy', + theme: volantis.dark?.mode === 'dark' ? 'dark' : 'light' + }) + + const pagination = instantsearch.widgets.pagination({ + container: '#algolia-pagination', + totalPages: 5, + templates: { + first: '', + last: '', + previous: '', + next: '' + } + }) + + search.addWidgets([configure, searchBox, hits, stats, powerBy, pagination]) + + search.start() + + } + + fn.setQueryText = queryText => { + fn.queryText = queryText; + if (!search) { + fn.init() + } + search?.setUiState({ + [algolia.indexName]: { + query: queryText + } + }) + } + + fn.search = () => { + document.querySelector("#u-search").style.display = "block"; + document.addEventListener("keydown", event => { + if (event.code === "Escape") { + fn.close(); + } + }, { once: true }) + } + + fn.onSubmit = (event) => { + event.preventDefault(); + let input = event.target.querySelector(".u-search-input"); + fn.setQueryText(input?.value ? input.value : event.target.value) + fn.search(); + }; + + fn.cutContent = content => { + if (content === '') return '' + + const firstOccur = content.indexOf('') + + let start = firstOccur - 30 + let end = firstOccur + 120 + let pre = '' + let post = '' + + if (start <= 0) { + start = 0 + end = 140 + } else { + pre = '...' + } + + if (end > content.length) { + end = content.length + } else { + post = '...' + } + + let matchContent = pre + content.substring(start, end) + post + return matchContent + } + + fn.close = () => { + document.querySelector("#u-search").style.display = "none"; + }; + + return { + init: fn.init, + setQueryText: queryText => { + fn.setQueryText(queryText); + }, + search: fn.search, + close: fn.close + } +})() + +Object.freeze(SearchService); + +SearchService.init(); diff --git a/js/search/hexo.js b/js/search/hexo.js new file mode 100644 index 0000000000..20936d9b3d --- /dev/null +++ b/js/search/hexo.js @@ -0,0 +1,193 @@ +let SearchService = (() => { + const fn = {}; + fn.queryText = null; + fn.data = null; + fn.template = ` +`; + fn.init = async () => { + let div = document.createElement("div"); + div.innerHTML += fn.template; + document.body.append(div); + document.querySelectorAll(".u-search-form").forEach((e) => { + e.addEventListener("submit", fn.onSubmit, false); + }); + let uSearchModalInput = document.querySelector("#u-search-modal-input"); + uSearchModalInput.addEventListener("input", fn.onSubmit); + document + .querySelector("#u-search-btn-close") + .addEventListener("click", fn.close, false); + document + .querySelector("#modal-overlay") + .addEventListener("click", fn.close, false); + if (!fn.data) { + fn.data = await fn.fetchData(); + } + }; + fn.onSubmit = (event) => { + event.preventDefault(); + let input = event.target.querySelector(".u-search-input"); + if (input) { + fn.queryText = input.value; + } else { + fn.queryText = event.target.value; + } + + if (fn.queryText) { + fn.search(); + } + }; + fn.search = async () => { + document.querySelectorAll(".u-search-input").forEach((e) => { + e.value = fn.queryText; + }); + document.querySelector("#u-search").style.display = "block"; + if (!fn.data) { + fn.data = await fn.fetchData(); + } + let results = ""; + results += fn.buildResultList(fn.data.pages); + results += fn.buildResultList(fn.data.posts); + if (results === "") { + results = `

${volantis.GLOBAL_CONFIG.languages.search.hits_empty.replace(/\$\{query}/, fn.queryText)}

` + } + document.querySelector("#u-search .modal-results").innerHTML = results; + document.addEventListener("keydown", function f(event) { + if (event.code === "Escape") { + fn.close(); + document.removeEventListener("keydown", f); + } + }); + }; + fn.close = () => { + document.querySelector("#u-search").style.display = "none"; + }; + fn.fetchData = () => { + return fetch(volantis.GLOBAL_CONFIG.search.dataPath) + .then((response) => response.text()) + .then((res) => { + const data = JSON.parse(res); + // console.log(data); + return data; + }); + }; + fn.buildResultList = (data) => { + let html = ""; + data.forEach((post) => { + if (post.text) { + post.text = post.text.replace(/12345\d*/g, "") // 简易移除代码行号 + } + if (!post.title && post.text) { + post.title = post.text.trim().slice(0, 15) + } + if (fn.contentSearch(post)) { + html += fn.buildResult(post.permalink, post.title, post.digest); + } + }); + return html; + }; + fn.contentSearch = (post) => { + let post_title = post.title.trim().toLowerCase(); + let post_content = post.text.trim().toLowerCase(); + let keywords = fn.queryText + .trim() + .toLowerCase() + .split(/[-\s]+/); + let foundMatch = false; + let index_title = -1; + let index_content = -1; + let first_occur = -1; + if (post_title && post_content) { + keywords.forEach((word, index) => { + index_title = post_title.indexOf(word); + index_content = post_content.indexOf(word); + if (index_title < 0 && index_content < 0) { + foundMatch = false; + } else { + foundMatch = true; + if (index_content < 0) { + index_content = 0; + } + if (index === 0) { + first_occur = index_content; + } + } + if (foundMatch) { + post_content = post.text.trim(); + let start = 0; + let end = 0; + if (first_occur >= 0) { + start = Math.max(first_occur - 40, 0); + end = + start === 0 + ? Math.min(200, post_content.length) + : Math.min(first_occur + 120, post_content.length); + let match_content = post_content.substring(start, end); + keywords.forEach(function (keyword) { + let regS = new RegExp(keyword, "gi"); + match_content = match_content.replace( + regS, + "" + keyword + "" + ); + }); + post.digest = match_content + "......"; + } else { + end = Math.min(200, post_content.length); + post.digest = post_content.trim().substring(0, end); + } + } + }); + } + return foundMatch; + }; + fn.buildResult = (url, title, digest) => { + let result = fn.getUrlRelativePath(url); + let html = ""; + html += "
  • "; + html += + ""; + html += "" + title + ""; + if (digest !== "") html += "" + digest + ""; + html += ""; + html += "
  • "; + return html; + }; + fn.getUrlRelativePath = function (url) { + let arrUrl = url.split("//"); + let start = arrUrl[1].indexOf("/"); + let relUrl = arrUrl[1].substring(start); + if (relUrl.indexOf("?") != -1) { + relUrl = relUrl.split("?")[0]; + } + return relUrl; + }; + return { + init: () => { + fn.init(); + }, + setQueryText: (queryText) => { + fn.queryText = queryText; + }, + search: () => { + fn.search(); + }, + }; +})(); +Object.freeze(SearchService); + +SearchService.init(); diff --git a/js/search/meilisearch.js b/js/search/meilisearch.js new file mode 100644 index 0000000000..1e5aaa7374 --- /dev/null +++ b/js/search/meilisearch.js @@ -0,0 +1,216 @@ +let SearchService = (() => { + const fn = {}; + let search, meilisearch, timerId; + fn.queryText = null; + fn.template = ` + `; + + fn.init = () => { + let div = document.createElement("div"); + div.innerHTML += fn.template; + document.body.append(div); + + meilisearch = volantis.GLOBAL_CONFIG.search; + if (meilisearch.appId && meilisearch.apiKey && meilisearch.indexName) { + fn.event(); + fn.setAlgolia(); + } else { + document.querySelector('#u-search main.modal-body').innerHTML = 'Algolia setting is invalid!'; + document.querySelector('#u-search main.modal-body').style.textAlign = 'center'; + document.querySelector('#u-search .modal').style.maxHeight = '128px'; + } + } + + fn.event = () => { + document + .querySelector("#u-search-btn-close") + .addEventListener("click", fn.close, false); + document + .querySelector("#modal-overlay") + .addEventListener("click", fn.close, false); + document.querySelectorAll(".u-search-form").forEach((e) => { + e.addEventListener("submit", fn.onSubmit, false); + }); + document.querySelector("#meilisearch-search-input").addEventListener("input", event => { + let input = event.target.querySelector(".ais-SearchBox-input"); + if (input) { + fn.queryText = input.value; + } else { + fn.queryText = event.target.value; + } + }) + } + + fn.setAlgolia = () => { + search = instantsearch({ + indexName: meilisearch.indexName, + searchClient: instantMeiliSearch(meilisearch.appId, meilisearch.apiKey), + searchFunction(helper) { + helper.state.query && helper.search() + }, + }) + + const configure = instantsearch.widgets.configure({ + hitsPerPage: meilisearch.hitsPerPage + }) + + const searchBox = instantsearch.widgets.searchBox({ + container: '#meilisearch-search-input', + autofocus: true, + showReset: false, + showSubmit: false, + showLoadingIndicator: false, + searchAsYouType: meilisearch.searchAsYouType, + placeholder: meilisearch.placeholder, + templates: { + input: 'meilisearch-input' + }, + queryHook(query, refine) { + clearTimeout(timerId) + timerId = setTimeout(() => refine(query), 500) + } + }) + + const hits = instantsearch.widgets.hits({ + container: '#meilisearch-hits', + templates: { + item(data) { + const keyword = !!fn.queryText ? `?keyword=${fn.queryText}` : '' + const link = data.permalink ? data.permalink : `${volantis.GLOBAL_CONFIG.root}${data.path}` + const result = data._highlightResult + const content = fn.cutContent(result.text.value) + return ` + + ${result.title.value || 'no-title'} + ${content} + ` + }, + empty: function (data) { + return ( + `

    ${volantis.GLOBAL_CONFIG.languages.search.hits_empty.replace(/\$\{query}/, data.query)}

    ` + ) + } + } + }) + + const stats = instantsearch.widgets.stats({ + container: '#meilisearch-info > .meilisearch-stats', + templates: { + text: function (data) { + const stats = volantis.GLOBAL_CONFIG.languages.search.hits_stats + .replace(/\$\{hits}/, data.nbHits) + .replace(/\$\{time}/, data.processingTimeMS) + return ( + `${stats}` + ) + } + } + }) + + search.addWidgets([searchBox, hits, stats]) + + search.start() + + } + + fn.setQueryText = queryText => { + fn.queryText = queryText; + if (!search) { + fn.init() + } + search?.setUiState({ + [meilisearch.indexName]: { + query: queryText + } + }) + } + + fn.search = () => { + document.querySelector("#u-search").style.display = "block"; + document.addEventListener("keydown", event => { + if (event.code === "Escape") { + fn.close(); + } + }, { once: true }) + } + + fn.onSubmit = (event) => { + event.preventDefault(); + let input = event.target.querySelector(".u-search-input"); + fn.setQueryText(input?.value ? input.value : event.target.value) + fn.search(); + }; + + fn.cutContent = content => { + if (content === '') return '' + + const firstOccur = content.indexOf('') + + let start = firstOccur - 30 + let end = firstOccur + 120 + let pre = '' + let post = '' + + if (start <= 0) { + start = 0 + end = 140 + } else { + pre = '...' + } + + if (end > content.length) { + end = content.length + } else { + post = '...' + } + + let matchContent = pre + content.substring(start, end) + post + return matchContent + } + + fn.close = () => { + document.querySelector("#u-search").style.display = "none"; + }; + + return { + init: fn.init, + setQueryText: queryText => { + fn.setQueryText(queryText); + }, + search: fn.search, + close: fn.close + } +})() + +Object.freeze(SearchService); + +SearchService.init(); diff --git a/latex-symbols/index.html b/latex-symbols/index.html new file mode 100644 index 0000000000..1da71bd978 --- /dev/null +++ b/latex-symbols/index.html @@ -0,0 +1,4476 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Latex常用符号大全 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + + + + + + +
    +
    +

    Part1. 运算符

    +

    Div1. 基本运算

    +

    加号:,键盘上有

    +

    减号:,键盘上有

    +

    乘号(叉乘): \times

    +

    乘号(数量积/点乘): +\cdot

    +

    除号: \div

    +

    开方/N次方根: +\sqrt[N]{ABC}

    +

    乘方/N次幂: +A^N

    +

    下标: A_N

    +

    分数: +\frac{A}{B}

    +

    等于号:,键盘上有

    +

    约等号: +\approx 加粗 +\thickapprox

    +

    不等号: +\neq

    +

    恒等号/定义为: +\equiv

    +

    大于号: \gt

    +

    小于号: \lt

    +

    大于等于: +\geq

    +

    小于等于: +\leq

    +

    远大于: \gg

    +

    远小于: \ll

    +

    正负: \pm

    +

    负正: \mp

    +

    Div.2 几何表示

    +

    垂直: +\perp

    +

    平行: +\parallel

    +

    角/无标记角: +\angle

    +

    角/标记角: +\measuredangle

    +

    一般全等: +\cong

    +

    相似: +\sim,加粗 +\thicksim

    +

    三角形: +\triangle

    +

    正方形: +\square

    +

    圆: \odot

    +

    向量: +\vec_{AB} +\overrightarrow{AB}

    +

    Div.3 集合

    +

    属于: \in

    +

    不属于: +\notin

    +

    子集: +\subseteqq

    +

    真子集: +\varsubseteqq \subsetneqq

    +

    真子集/直线在平面上: +\subset

    +

    正整数集: N^* +或 N_+

    +

    并集: \cup

    +

    交集: \cap

    +

    补集: +\complement{_U^A}

    +

    Div.4 逻辑符号

    +

    因为:

    +

    所以:

    +

    存在: +\exists

    +

    不存在: +\nexists

    +

    任意/对于所有: +\forall

    +

    空集: +\varnothing

    +

    逻辑或: \cup +或 \lor

    +

    逻辑与: \cap +或 \land

    +

    逻辑非: +\lnot

    +

    充分条件/右双箭头: +\Rightarrow 大小写敏感

    +

    必要条件/左双箭头: +\Leftarrow 大小写敏感

    +

    充要条件/双向双箭头: +\Leftrightarrow 大小写敏感

    +

    Div.5 高级数学

    +

    成正比: +\propto

    +

    定积分: +\int_{a}^{b}

    +

    多重积分: +\iint_{a}^{b} +\iiint_{a}^{b}

    +

    导函数/上撇号: +\prime

    +

    求和: +\sum_{i=1}^{n}

    +

    求积: +\prod_{i=1}^{n}

    +

    字母数位/平均数: +\overline{ABCD}

    +

    整除符号: +\mid

    +

    新定义运算符: +\oplus +\otimes +\ominus

    +

    扰动值: +\tilde{K}

    +

    高德纳箭头/上箭头: 3\uparrow \uparrow 2

    +

    Div.6 常数

    +

    无穷大/无限: +\infty

    +

    圆周率: \pi

    +

    普朗克常数: +\hbar +\hslash

    +

    Div.7 注音

    +

    一声: +\bar{e}

    +

    二声/法语闭音符: +\acute{e}

    +

    三声: +\check{e}

    +

    四声/法语重音符: +\grave{e}

    +

    字母双点/德语特殊字母/特殊拼音: \ddot{u}

    +

    特殊发音符: +\tilde{a}

    +

    抑扬符: +\hat{a}

    +

    Div.8 希腊/希伯来字母

    +

    小写希腊字母

    +

    \alpha \beta \chi \delta +\epsilon +\eta

    +

    \gamma \iota \kappa \lambda \mu \nu

    +

    o \omega \phi \pi \psi \rho

    +

    \sigma \tau \theta +\upsilon +\xi +\zeta

    +

    变量希腊字母

    +

    \digamma + +\varepsilon \varkappa + +\varphi +\varpi +\varrho

    +

    \varsigma + +\vartheta

    +

    大写希腊字母(仅展示大小写字母样式有差别者)

    +

    \Delta \Gamma \Lambda + \Omega + \Phi + \Pi

    +

    \Psi \Sigma \Theta \Upsilon + \Xi

    +

    希伯来文字母

    +

    \aleph \beth \daleth + +\gimel

    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +
    + + +
    +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/linear-algebra-explicit-tutorial-ii/index.html b/linear-algebra-explicit-tutorial-ii/index.html new file mode 100644 index 0000000000..da027be510 --- /dev/null +++ b/linear-algebra-explicit-tutorial-ii/index.html @@ -0,0 +1,4310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 线性代数 简明教程 二 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + +
    + + + +
    + + + + +
    +
    +

    pandoc测试自动部署

    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +
    + + +
    +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/linear-algebra-explicit-tutorial/index.html b/linear-algebra-explicit-tutorial/index.html new file mode 100644 index 0000000000..08e730530e --- /dev/null +++ b/linear-algebra-explicit-tutorial/index.html @@ -0,0 +1,4827 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 线性代数 简明教程 一 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + +
    + + + +
    + + + + +
    +
    +

    +

    线性代数 简明教程

    +

    前言

    + + +

    第一节 +方程组与矩阵的互相转化

    +

    假设我们有一个方程组:。首先将所有未知数提到等号左侧,常数全部移到右侧。我们暂时先忽略掉等号右边的常数项。我们将每行未知数的系数提取出来,放入矩阵的第一行,矩阵的第一行就表示方程组中第一个方程的未知数系数(没有默认为0),以此类推到下边几行,最终你会得到一个列数与未知数个数相等、行数与方程个数相等的矩阵。本例中它长成这个样子:

    +

    +

    如此得到的矩阵叫做系数矩阵,顾名思义,它只表示了原方程组的系数,而忽略了常数项。它同时也是一个矩阵,一般地,对于一个矩阵(),它有列。

    +

    此时,如果我们加上等号右侧的常数项,原先的矩阵会变成的。人们为了区分常数和系数,选择在书写时将常数加入到最右侧那一列,并且在最右一列的前面加上竖线分隔系数,如此得到的矩阵叫做增广矩阵。本例中的增广矩阵形式写作:

    +

    +

    当矩阵元素不明时(通常是为了举例),我们为了简便表示矩阵本身,采用右下角元素+括号的方式。例如一个矩阵,可以写作:

    +

    第二节 矩阵的基本运算

    +

    1. 矩阵加法

    +

    仅限构造相同的矩阵,也就是说进行加法运算的两个矩阵行列数必须相同,这样的两个矩阵是同型的。相加时同一行同一列的元素相加即可(增广矩阵同理)。

    +

    例如:

    +

    矩阵加法满足:结合律、交换律

    +

    2. 矩阵减法

    +

    矩阵减法是矩阵加法的逆运算,因此对于两个矩阵的形式要求同上,只是相同位置的元素相减而已。

    +

    矩阵减法满足:结合律、交换律

    +

    3. 标量乘法/矩阵数乘

    +

    矩阵的数乘也很简单,让矩阵中每个元素乘以这个数就可以了。

    +

    例如:

    +

    矩阵数乘满足:交换律、结合律、分配律

    +

    4. 矩阵转置

    +

    矩阵转置就是将原矩阵的行变成新矩阵的列,直观理解就是顺时针旋转90度后再水平镜像过去。转置用上标表示。

    +

    例如:,则

    +

    矩阵的主对角线(左上-右下)元素转置前后不变,且具有可逆性[]、数乘不变[]、分配律[]。

    +

    有一类特殊矩阵,它转置后恰好就是它自身。这类矩阵被称为对称矩阵,它是自转置的,即。对称矩阵的元素恰好关于主对角线对称,并且是一个的正方形矩阵。这两条性质是对称矩阵的两个基本性质。

    +

    5. 矩阵乘法

    +

    该内容将在第二章涉及。

    +

    第三节 消元

    +

    按照一般思路(就是我们在小学学的方法),我们会选择通过方程互相加减各自的倍数,达到消去未知数的目的。这种方法在矩阵上同样适用,而且它有一个贼高坤的名称:高斯消元法(Gaussian +Elimination)。

    +

    回忆一下我们从出生就会用的消元原理,我们的目标就是让每个未知数都对应一个常数项,那么它的值就可以直接用常数除以系数的方式求出。矩阵中也是如此,为了能够化简出可直接求解的矩阵,我们在此引入初等行变换的概念:

    +
      +
    1. 交换某两行
    2. +
    3. 把矩阵的某一行同乘以一个非零的数
    4. +
    5. 把某行的若干倍加和到另一行
    6. +
    +

    这三条很容易理解。第一条:相当于交换方程组顺序,不影响计算;第二条:相当于对某一行方程放缩某倍,它等价于原方程;第三条:相当于前两条的融合,也是消元的关键一招。这三条规则在之后的初等矩阵内容中会再次出现。

    +

    首先从一个例子讲起,让读者感受一下初等行变换的魅力:

    +

    考虑这个方程组:

    +

    +

    按照如上所述,将它转写成增广矩阵的形式:

    +

    +

    我们总结一下常用的消元原理,应用到矩阵上就是:

    +
      +
    1. 枚举每一列,选出无序组中第列系数绝对值最大的一行,并移到无序组的最上边。(变换规则一)
    2. +
    3. 行通过自乘,将第列的系数变成,并标记为有序。(变换规则二)
    4. +
    5. 通过加减有序组中某一行的非零倍,将之后所有行的第列系数化为。(变换规则三)
    6. +
    +

    令矩阵(有序组用绿色表示)

    +

    枚举第一列,。开始时,所有行均无序。选出绝对值最大的那一项,本例中为第二行,进行移动,原矩阵变为:

    +

    +

    第二步,自乘并标记有序,因此第一行除以,原矩阵就变成了:

    +

    +

    第三步,将无序组的第列消成。本例中,我们让第二行减去二倍第一行;第三行直接减去第一行,得到:

    +

    +

    枚举第二列,此时。第一步,选出第二列系数绝对值最大的那一行,移到无序组最上端。本例中无需移动,自乘,标记有序,原矩阵为:

    +

    +

    最终的最终,第三行减倍第二行,得到我们心心念念的化简后的矩阵:

    +

    +

    为什么把矩阵化简成这种金字塔型的形式呢?你会发现:最后一行仅有一个带系数的未知数,我们直接求,。向上一行,现在相当于常数,移到常数中与合并,也可直接求了……经过如上的反代操作,三个未知数都会被求出来。至此我们才发现这个三角形矩阵的魅力之处。

    +

    一般地,对于一个矩阵,如果它的非零系数呈阶梯形分布,则称这类矩阵为行阶梯形矩阵。将非零系数挑出来,它们组成的是一个上三角形矩阵;对应地,零项就会组成下三角矩阵。上三角矩阵通常以表示、下三角矩阵通常用表示。

    +

    原方程组有唯一解:

    +

    +

    第四节 秩

    +

    类比一元二次方程的根存在性判别法——判别式法,即对于一元二次方程,根的个数。那么,矩阵方程是否也有类似的根存在性判别方法呢?

    +

    答案是有的,而且不止一种,这意味着“矩阵是否有解”这样的问题会有多种解决方案。现在介绍的是最为简单常用的一种——秩。

    +

    在线性代数中,一个矩阵A的列秩是A的线性独立的纵列的极大数目。类似地,行秩是A的线性无关的横行的极大数目。即如果把矩阵看成一个个行向量或者列向量,秩就是这些行向量或者列向量的秩,也就是极大无关组中所含向量的个数。

    +

    ……咱们抛掉这种看也看不懂的高级语文句法,听我给你总结:

    +

    通俗来讲,把一个矩阵化成最简形式(特指行阶梯形)后,非零行的个数就是矩阵的秩。这其实是秩的最大线性无关组的定义。再次白话总结:如果存在三个行向量(列向量一样的,保证所有向量都是行/列向量即可):。根据高中数学中立体几何的知识——显然是共线的(就是值的最简比相同,本例中均为)像这样共线的两个向量,拉到线性代数中就说他们是线性相关的;反之是线性无关的,例如本例中这两组向量互相不共线,它们互相都是线性无关的。

    +

    矩阵的秩用表示[等均可]。

    +

    现在明白了吧,如果一个矩阵的某两行线性相关,它们都会被初等行变换第三条狠狠薄纱——在乘/除一个非零数后相减,其中一行就会被全部消成0,从方程组角度来看就是,带什么值都成立(相当于浪费了一行)。

    +

    当然上边这一段也有表述不准确之处,假设有一个增广矩阵。初等行变换第三条秒了第一、第二行,然而事情有些不对劲了……

    +

    +

    第二行不乐意了,它还存留这最后一点倔强,好像在说:“你总结的不对呢~真是雑鱼~”。但是明眼人都看得出来,这种事情是绝对不可能发生的,也就是无解。按照刚刚说的,这个增广矩阵的秩,可是它对应的系数矩阵的秩,就有,于是我们就找到了矩阵无解的一个条件了。矩阵无解的充要条件是

    +

    再考虑有无穷解的情况:无非就是出现了的情况,此时可以代任何值。与无解不同,这次的最简行阶梯形矩阵,无论是系数矩阵还是增广矩阵形式,它们的秩都是相同的,并且都浪费了至少一行方程式。我们知道:一个三元一次方程组是无法用相异的(行向量形式表示下不共线)两个方程解出唯一值的,相反,解形如:表明确定、而又由确定,然而这俩都不确定,导致这两个数可以取无穷多的值,也就导致矩阵有无穷组解。综上:矩阵有无穷组解的充要条件是为未知数个数)

    +

    最后就是有唯一解:如果一切进行顺利的话,既没有全零行,也没有无解行。那么此时系数矩阵和增广矩阵的秩会相同,且等于未知数个数,即

    +

    总结,假设一个由个未知数组成的最简行阶梯形矩阵、以及它的增广矩阵。矩阵解的个数

    +
    +

    例1.1.1 Delivery Mathematics 快递员的数学题

    +
    +

    「稻妻狛荷屋的人气跨国快递员绮良良在送货途中遇到了一个难题,你作为无所不知无所不晓的旅行者自然是乐意地接下了她的委托。当你来到委托地点时,你发现这是一道解谜题目……」

    +

    稻妻号称最难的方块解谜是一组由个正方体可旋转方块组成的阵列,击打其中的某个方块会使得与之相关联的其他方块共同旋转一个特定角度。在这个谜题中,每个方块每次仅能水平顺时针旋转90度,传动方式在下图给出。问若要使所有方块同时朝向北方,需要如何击打方块?给出任意可行解,但需要保证每个方块旋转的次数不超过4(不击打也可以,相当于次数为0)。

    +

    由于钟离先生远在海那一头的璃月喝茶听评书、宵宫也正忙着制作夏日祭的烟花而无法抽身、香菱在万民堂做饭、安柏在侦察蒙德郊区、芙宁娜忙着吃蛋糕……总之没有其他人召唤物能帮你解决这个问题,你只能凭借自己的力量解开这个谜题。

    +
    +
    +图1.3.1 + +
    +

    问题分析:首先我们要搞清楚传动规则,我们会发现当你击打了一个方块,包括它在内、再按顺时针方向数两个方块都在旋转相同的角度。这也是这道题被称作难题的原因之一,只用想象力是很难想象的出来的……于是为了用代数方法解决该问题,我们选择用四个未知数、四个方程表示每个方块操作后的状态,问题解决的标志既为四个方块的状态均为表示北方)。

    +

    算法设计:考虑到单个方块每旋转四次就相当于一次循环,因此我们重定义方向标,从北开始,顺时针方向将方位标记为。这么做可以避免一些复杂的取模运算。接着我们根据传动规则表示每个方块的状态,令方块1-4被击打次数分别为。以方块1为例:击打自己、3号和4号都会导致1号顺时针旋转90°,再算上1号初始朝向为,得到:。其他方块以此类推,解析出的方程组对其求解即可。这样的矩阵一定有唯一解,每个未知数都以表示,将一个自然数代入值即可解出答案。

    +

    :设方块1-4的击打次数分别为,设朝向从北方按顺时针方向分别为

    +

    根据传动规则,有如下线性方程组:

    +

    +

    增广矩阵形式为:

    +

    +

    (化简过程略),行阶梯形式为:

    +

    +

    因为系数矩阵的秩与增广矩阵的秩相同且都等于未知数个数,因此矩阵有唯一解。易知的合法值满足的数学关系,此处求最小值,令,得到

    +

    因此,最佳方案是暴击击打2号和3号方块各两次。

    +

    后日谈:有些读者可能会问,这个难道不是有无穷解吗?为什么上边说这个矩阵只有唯一解?其实这个矩阵确实只有唯一解,因为,造成它有无数组解的原因是这个自然数。我们在开头只为这个矩阵设定了四个未知数,因此矩阵只有四个元,因而有唯一解。

    +
    +

    洛谷习题:

    +
      +
    1. P3389 [模板] +高斯消元法
    2. +
    3. P2455 [SDOI2006] +线性方程组
    4. +
    5. P4035 [JSOI2008] +球形空间产生器
    6. +
    +
    +

    第二章 矩阵乘法

    +

    第一节 什么是矩阵乘法

    +

    你经常能在各种线性代数的书上看到这样一串定义式:。这对于自学者(比如说我自己)其实是非常不友好的。他们在举例计算时很容易被绕进去,不仅计算速度慢不说,还很容易出错……那我在此举出一个简记方法:

    +

    将左边的矩阵的每一行看作每个未知数都代了确定值的方程、右边的矩阵每一列看作是前者方程的未知数系数。二者相乘本质上就是让未知数和系数匹配上,并计算出结果放入结果矩阵的特定位置。这个特定位置也有讲究——计算时我们需要固定一个行/列,相对应地我们需要遍历另一个矩阵的列/行,遍历的方向就是这个“特定位置”的排布方向,当遍历完一轮,开始下一轮时,这个“特定位置”的起始点将移到下一行/列,若固定一列则右移一列;反之下移一行。看以下例子来加深理解:

    +
    +图2.1.1 + +
    +

    这是固定特定列求值的例子,固定行求值留给读者自行实操。不想再做图了,我太懒了

    +

    那么什么样的矩阵才能进行乘法运算呢?答案是一个和一个的矩阵,观察规律,我们发现前矩阵的列数需要等于后矩阵的行数。根据如上概括的矩阵乘法的意义——即搭配未知数与系数。显然,当后一个矩阵的列数大于前一个矩阵的行数时,我们进行系数配对时就会发现多出几个失配的系数。矩阵乘法国不养闲人,这种单身汉显然是不可以光天化日下大摇大摆出来遛弯的。因此保证其中一个矩阵的行数等于另一个矩阵的列数后方可相乘。

    +

    类比四则运算的乘法,矩阵乘法是否也有结合律、分配律和交换律呢?很遗憾,不完全是,前二者是矩阵乘法运算所具备的性质、但最后那个交换律不是。不是所有的矩阵相乘都满足乘法交换律,举几个特例:同型零矩阵相乘、一个矩阵(可逆)和它的逆矩阵相乘,矩阵乘法满足交换律的充要条件证明过于复杂烧脑,此处不做陈述主要是我也不会证qwq……

    +

    证明:一般矩阵不满足乘法交换律

    +

    假设一般矩阵,一般矩阵,则可以进行,因为的行数和的行数均为。得到的乘积是一个矩阵;反过来,无法进行,因为的列数不等于的行数,即

    +

    假设均可进行,假设乘积为。当时,根据矩阵乘法的计算式,得到;当时,根据计算公式得。一般情况下,。得证。

    +

    矩阵和数字一样,也有幂次方的计算。特殊地,任意非零矩阵的零次幂都是一个的单位矩阵。主对角线的值全是1,其余元素均为0的矩阵叫做单位矩阵,用字母表示;零矩阵的任何非零正整数次幂都是一个零矩阵,零矩阵的元素全部是0,用字母表示。一个的单位矩阵是这样的:。在算法设计中,经常用类似于大数快速幂(位运算版本)的方式快速计算矩阵的幂次方。

    +
    +

    例2.1.1 Akasha Browser with Irminsul Kernel +世界树搜索引擎

    +
    +

    你作为刚刚清除了须弥世界树痼疾的英雄旅行者,突然对虚空终端的运作方式有了兴趣。你从大贤者那里了解逼问到,虚空终端实质上是一个仅显示搜索结果的前端程序,但关键词搜索功能却是基于须弥地下空间的世界树。带着这个疑问,你再次来到了世界树前,见到了小吉祥草王大人,希望能让她告诉你世界树的运作方式……

    +
    +

    背景知识: +一般浏览器的结果返回功能大多数依赖于矩阵运算,这里属于最简单的一种——我们只需要矩阵的乘法运算(某些情况下会用到转置)。然而随着科技的快步发展,数据量的快速增加,这种方式如今只在很小的范围内被使用(由于码量小思维简单,它有时会在个人博客的关键词搜索功能中被用到);目前广泛使用的一种是向量相似性搜索,它本质上是在一定范围内搜索与目标向量辐角最为接近的已有向量,在“矩阵的几何表示”章节中会涉及到。这里介绍的是简单匹配搜索。

    +

    问题分析:因为矩阵乘法本质上是未知数和系数的配对求值,我们需要构造一个方法来使得“搜索内容”和“已有内容”配对。并且搜索引擎总会返回与你搜索的内容最为相似的结果,搜索“比尔·盖茨”,第一条肯定是关于他个人的介绍,而绝对不可能是一则寻狗启示……因此,我们设计的矩阵必须能在经历一轮运算后能够正确返回每个关键词出现的频率(简单点说就是出现次数),这样虚空终端才能对频率进行排序,并返回频率最大的那个结果。

    +

    算法设计:不妨考虑这样几个矩阵——其中一个存储关键词、另一个存储搜索内容。比如我需要将几篇论文(为方便使用英文表示,并且假设词根相同的单词为同一个单词,即不考虑词汇变形)《Basic +Structure of Elemental Monuments》(元素方碑的底层构造)、《Junior +Elemental Reaction》(初等元素反应)、《Advanced Elemental +Theory》(高等元素论)、《Architectural Structure in the Mausoleum of +King Deshret》(赤王陵的建筑结构)以及《Advanced Sumeru Linguistic +Analysis》(高等须弥语音学解析)。我们在此次挑选一些关键词存储(方便读者观察):StructureElementJuniorAdvanced。为每篇论文编号1-5,矩阵如下图:

    +
    +图例2.1.1 + +
    +

    假如热爱学习的艾尔海森来到了教令院的大图书馆,它想测试一下这全新开发的文献查询系统,输入了Advanced一词。假设已录入数据库就是以上形式,我们如何构造一个“查询矩阵”来和数据库矩阵进行运算呢?

    +

    首先根据矩阵乘法的前提要求,这个查询矩阵必须是四行。不妨让每行代表我们的词库词语,艾尔海森输入的是Advanced——即对应数据库矩阵的第四列(未知数),我们要配对它的系数,因此它必须在第四行,才能保证系数正确匹配未知数。同理,查询矩阵的第一行对应Structure、第二行Element、第三行Junior。他输入了一个Advanced,因此我们的查询矩阵如下图:

    +
    +图例2.1.2 + +
    +

    乘法的目的是将二者匹配起来,得到的结果如下图:

    +
    +图例2.1.3 + +
    +

    返回矩阵的数字代表关键词在对应数据库项中的出现次数,也就是说,如果此时再加入一篇论文《Advanced +Usage of the Word +Advanced》(“Advanced”一词的进阶用法),返回矩阵的最后一行(第六行)会出现一个。经过虚空终端的一轮排序,它自然就会来到第一位的位置。如果要分别查询两个不同关键词,在查询矩阵右侧再加一列即可,返回矩阵中多出的一列就是新关键词的出现次数;如果需要同时查询两个关键词,在同一列对应位置写入即可……

    +

    后日谈可靠情报称——愚人众第二席执行官“博士”伙同教令院高层贤者向世界树中加入了大量带有重复词语标题的、正文中充满了强烈心理暗示的催眠文献,须弥民众所佩戴的虚空终端中写入的关键词查询算法自动按关键词出现频率返回结果、其内置的播放功能在结果返回后自动激活,播放其中内容,导致须弥大范围民众出现意识不清、报告称出现“重复经历同一天”、“既视感”等异常现象。后续调查正持续跟进中……——《蒸汽鸟报》记者 +夏洛蒂 +须弥的大范围“失控”已被证明是须弥民众针对教令院的一次毫无意义的武装暴动,目前已被教令院大贤者和“博士”联合镇压。主要组织者纳西妲、旅行者已被尽数羁押等候问讯。——教令院

    +

    例2.1.2 Light Novel Query 轻小说查询

    +
    +

    八重堂的主编八重神子最近在为轻小说的事情发愁……并不是因为销量不够,正相反:八重堂最近推出了一项跨国销售项目,各种经典作品被远销往了枫丹廷。这就牵涉出一个问题——枫丹的市民们不想远离枫丹城区、横穿须弥沙漠、翻越璃月高山、躲避稻妻雷暴就为了看一看有哪些轻小说符合自己的独特口味……于是八重神子找到了见多识广的你,希望你能帮她做出一套轻小说内容检索系统。当然作为报酬给你的原石和摩拉是肯定是不会少的……

    +

    当然,这套系统有一定要求。因为有很多轻小说为了吸引读者,取的标题和内容是完全对不上号的,神子的想法是做一套正文内容检索——每本轻小说的总字数在出版时就统计好了,但是苦于稻妻的信息存储技术不是很发达,神子希望存储在数据库矩阵里的数据尽可能小。请问该如何设计符合要求的存储算法?

    +
    +

    问题分析:每本书中特定的词可能重复出现成百上千次(同样用英文单词表示,且同词根不同词形的两个词算作同一个单词参与计数),我们的要求是让数据尽可能小,既然总字数都已经给出了,我们不妨使用指定词出现的频率来表示这个词的出现次数(单词出现次数=全书总词数×出现频率)。这样的搜索方法叫做相对频率搜索。

    +

    算法设计:大致原理和例2.1.1里的一模一样,只是数据库矩阵存储的不再是出现总次数,而是对应词的相对频率。因而图例2.1.3可以变化为如下形式:

    +
    +图例2.2.1 + +
    +

    明显一看,第三篇文章出现Advanced的频率最高,应该优先返回。但是这个例子并不是很好(明明说了按内容搜索你还在这搜索标题),但是当加入大量的正文内容时,这个方法的优势也就体现出来了。这里由于篇幅图太大耗我洛谷高级图床空间,我也懒得写那么多字原因就不举过长的例子,本例仅作对相对频率搜索的原理的理解。

    +

    后日谈:八重堂轻小说搜索引擎被教令院照搬去做了论文的查询系统……

    +
    +

    第二节 初等矩阵与矩阵递推

    +

    假设存在一个的单位矩阵,对只进行一次初等行变换得到的矩阵叫做初等矩阵,通常用表示。一个矩阵的行变换和列变换都可以用初等矩阵的乘法进行。

    +

    仅交换了两行的单位矩阵称作第I类初等矩阵(只进行了初等行变换第一条),将它左乘到一个矩阵前,可以进行相应的行运算;右乘到一个矩阵后可以进行相应的列运算。比如,一个第I类初等矩阵(交换第一、二行),和一个矩阵。左乘就是(交换一、二行);右乘就是(交换一、二列)。

    +

    仅将某一行乘以一个非零倍数的矩阵叫做第II类初等矩阵(只进行了初等行变换第二条),左乘行运算、右乘列运算。例如一个第II类初等矩阵(第一行乘3)和一个矩阵(第一行乘3);(第一列乘3)。

    +

    仅将某一行的非零倍加到另一行上的矩阵叫做第III类初等矩阵(只进行了初等行变换第三条),同样是左乘行运算、右乘列运算,但是有一点点小不同,不要根据思维定势随便写答案!例如一个第III类初等矩阵(第二行乘2加到第一行)和祖传的矩阵第二行的2倍加到第一行);第一列的2倍加到第二列)。注意初等矩阵的行列变换与乘法后矩阵的行列变换,哪一行/列乘了倍数、哪一行/列被加上了!

    +

    因此我们可以不必使用高斯消元,仅使用初等矩阵乘法也可以达到将普通矩阵消元变成最简行阶梯形矩阵!而且它可以进行列运算,甚至比高斯消元法更高级一点。

    +

    接下来是我们的矩阵递推。大家都知道斐波那契数列,它的前两项均为1,此后的每一项都是前两项之和,即。大多数信息竞赛生在学习到递归算法时都会被要求写程序求解斐波那契数列的某一项,当然代码也非常的简单,如下:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <bits/stdc++.h>
    using namespace std;

    long long fib(int n) {
    if (n == 1 || n == 2) return 1;
    return fib(n - 1) + fib(n - 2);
    }

    int main() {
    int n;
    cin>>n;
    cout<<fib(n)<<endl;
    return 0;
    }
    +

    这段代码其实就是照搬了上面的通项公式,但是递归有个弊端就是效率和内存,当为百万级别、甚至十亿级别时它就显得很小丑了。那么我们如何用矩阵加速计算呢?我们用斐波那契数列的递推来向读者介绍矩阵递推的操作方法:

    +

    首先我们将通项公式变成我们想要求的形式,为了便于输出,要求结果矩阵的第一个元素就是答案,因此结果矩阵就是:。又因为,并且。我们还需要保证初始矩阵在经历一轮变换前后,始终都是同型的,这里是的矩阵,操作后也应该是的矩阵。于是我们的递推矩阵应该是一个矩阵。不妨将递推矩阵的每一行从上至下分别表示为的系数,由以上二式可得:。别急,左边还有一列未填满——我们希望每次操作都会把矩阵元素整体向左移一个位置,就好像一个滑动窗口(但不是单调队列),我们的第一列也可以求出来了。最终就是

    +

    那么求数列第项——每次右乘都相当于多求出一项,并且当只被乘了一次时,结果矩阵的第一个元素是。因此要让第项来到第一个位置,我们需要进行次乘法,也就是的第一行第一列元素。可以写出如下代码:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    #include <bits/stdc++.h>
    #define MOD 1000000007
    #define N 15
    using namespace std;

    typedef long long ll;

    int n = 2; // 递推矩阵行列数均为2

    struct Matrix {
    ll mat[N][N];

    Matrix() {
    memset(mat, 0.0, sizeof mat); // 初始化时内部变量自动置零,无需每次定义变量时再置零
    }

    void I() {
    for (int i = 1; i <= n; i++) mat[i][i] = 1; // 构造2×2单位矩阵
    }
    };

    Matrix operator *(const Matrix &l, const Matrix &r) {
    // 重载乘法运算符,实现矩阵乘法
    Matrix res;
    for (int k = 1; k <= n; k++) {
    for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
    // res.mat[i][j] = (res.mat[i][j] + l.mat[i][k] * r.mat[k][j] % MOD) % MOD; // 取模用这个
    res.mat[i][j] += l.mat[i][k] * r.mat[k][j];
    }
    }
    }
    return res;
    }

    Matrix qpow(Matrix a, ll b) {
    Matrix res;
    res.I();
    while (b) {
    if (b & 1) res = res * a;
    a = a * a;
    b >>= 1;
    }
    return res;
    }

    int main() {
    int a;
    cin>>a;

    Matrix A;
    A.mat[1][1] = A.mat[1][2] = 1; // 初始矩阵
    Matrix M;
    M.mat[1][2] = M.mat[2][2] = M.mat[2][1] = 1; // 递推矩阵
    A = A * qpow(M, a - 1);
    cout<<A.mat[1][1]<<endl;
    return 0;
    }

    +

    它的时间复杂度可以做到是递推矩阵长/宽,这里是是幂指数。因此这里的时间复杂度是:,比朴素斐波那契递推的强了不少!

    +
    +

    例2.2.1 Lost Control! Blubberbeast's Reproduction +膨膨兽泛滥危机

    +
    +

    由于枫丹水质的大幅改善,膨膨兽的天敌数量锐减,枫丹城区近海的膨膨兽也得到了更多的食物,进而开始大量地繁殖。水质改善的第一年,已登记的膨膨兽数量是6765头,恰好是斐波那契数列的第20项。第二年,膨膨兽数量没有变化,之后的每一年,膨膨兽数量都是前两年之和的,已知膨膨兽的平均寿命是15年、枫丹廷近海能承载的最大膨膨兽数量是90万只。那么请问15年后近海的膨膨兽数量是多少?这15年内枫丹廷是否需要向近海投放膨膨兽的天敌以遏制后者疯狂繁殖?(结果出现出现小数则向上取整)

    +
    +

    问题分析:这是一道标准的矩阵快速幂递推问题,它基于斐波那契数列递推、却比它更高级。首先,它的初始值不再是而是,其次,从第三项起,每一项都是前两项和的一个倍数,这里是。那我们怎么构造递推矩阵来解决问题呢?

    +

    算法设计: 已知初始矩阵。根据题目描述很容易写出通项公式:。我们要保证初始矩阵经过一次递推后,得到的新矩阵与初始矩阵同型,因此根据矩阵乘法定义,我们的递推矩阵必须是一个矩阵。于是拿出祖传单位矩阵模板开始构造递推矩阵!

    +

    对于前项和的问题,前面已经给出了,因而我们的递推矩阵变成了;接下来解决倍数问题——根据通项公式,的系数都是,我们构造递推矩阵时也要考虑到这一点,当时,递推公式展开如下:。如果第一行代表的系数、第二行代表的系数,第二列显然应该同时乘以0.85,左边一列的作用是使原矩阵整体向左移一个位置。最后我们的递推矩阵就是。直接将初始矩阵右端乘以递推矩阵的幂次方就可以了。注意因为初始矩阵的右侧是第二年的膨膨兽个数,乘以递推矩阵本身(一次方),会让第二年的膨膨兽个数移到结果矩阵的前端,要想让第一项变成第15年的个数,递推矩阵的幂必须是,即

    +

    代码实现上,仅需将矩阵和矩阵的初始值改变就可以了。

    +

    最终结果:875076。结果小于90万,因此不需要投放天敌。

    +

    后日谈:那如果将系数改变为呢?输出的结果将是977427,接近100万了。因此但凡枫丹水质再好那么一点点,使得这个系数升高了0.1,那么枫丹廷说不定都会变成膨膨兽的第二家园了!

    +
    +

    洛谷例题:

    +
      +
    1. P3390 [模板] +矩阵快速幂
    2. +
    3. P1962 +斐波那契数列
    4. +
    5. P1349 +广义斐波那契数列
    6. +
    7. P1939 +矩阵加速(数列)
    8. +
    9. P3216 [HNOI2011] +数学作业
    10. +
    +
    +

    第三章 矩阵的逆

    +

    第一节 浅谈矩阵的“逆”

    +

    “逆”这个词相信你早已听说过:同余意义下存在乘法逆元,大多数矩阵也存在逆矩阵。“逆”普遍用来描述不同意义下的“倒数”的概念,倒数一般满足的性质,即本体×本体的逆=单位一。矩阵中的“单位一”是单位矩阵,也因此我们的逆矩阵需要满足这个式子:,并且这个式子倒过来也必须成立(为数不多的满足矩阵乘法交换律的情况之一)。

    +

    如果对于一个矩阵,存在另一个矩阵,使得:成立。则称矩阵可逆的,或称之为非奇异的,矩阵是矩阵逆矩阵,通常表示成。特殊地,单位矩阵的逆矩阵是它本身,即零矩阵不可逆,或称之为奇异的,即不可能存在矩阵,使得。类比实数运算,的倒数永远是它本身、没有倒数,因为分母为,没有意义;,同时

    +

    第二节 行列式

    +

    行列式是一种函数,写出来有点像矩阵的绝对值。它可以用来判断一个矩阵是否有解、也可以定量分析线性变换对原向量的影响。矩阵的行列式通常用或者是表示。这一节主要介绍行列式判断矩阵是否可逆。

    +

    矩阵的行列式为。特殊地,矩阵的行列式就是的值。当一个矩阵的行列式为时,它是奇异的、也就是不可逆的;反之则非奇异/可逆。

    +

    那我们在上边只提到了两种方阵,那对于的方阵又该怎么办呢?答案是分而治之——分治!

    +

    第三节 代数余子式

    +

    我们拿出祖传的矩阵,我们随机在其中挑选一位受害者。我个人看第二行第一列的元素不太顺眼,作为矩阵的定义者,我有权利将它变成自己所喜欢的样子,因此我把元素拿掉。可是拿掉以后它还是个!于是我将它所在的那一行以及那一列全部剔除,把剩下的元素按照原来的相对顺序靠拢,组成一个新的矩阵。现在整个矩阵没有元素了,看上去清爽多了~~~

    +

    像上边这样,将阶行列式中元素)所在的第行、第列所有元素删去,剩下元素组成的新阶行列式叫做原行列式的余子式,用表示,代表它是删去原矩阵第行和第列得到的余子式。它通常将一个高阶行列式拆分为一个个低阶行列式便于计算,这其中就是用到了分治(子问题递归)的思想。

    +

    我们要计算整个矩阵的行列式,就需要拆开余子式。最终分治成多个的矩阵求其行列式并加和起来。有一个定理:当时,一个的方阵的行列式可以表示成任意行/列的余子式展开,即:

    +

    +

    日常做题时,通常选取最多的那一行/列进行展开以减少计算量。

    +

    第四节 矩阵的逆

    +

    第一节解释清楚了逆矩阵的概念,那么如何求逆矩阵呢?首先是前提——判断矩阵是否可逆!我们引入矩阵行等价的概念:

    +

    如果一个矩阵能经过有限次初等行变换得到另一个矩阵,则称行等价的。比如说你交换一个矩阵的两行(初等行变换第一条)得到的矩阵本质上还是原来的矩阵,因为如果当你把变换前后的矩阵拆分成一个个行向量,它们在坐标系上的关系不变(交换两行向量不变,同乘倍数向量共线还挺押韵)。联系到第二节的初等矩阵知识,初等行变换可以转化为矩阵左乘初等矩阵,定义可以转换为如下的数学语言:如果存在矩阵和矩阵,使得成立,则称是行等价的;相应的,初等矩阵右乘就对应两个矩阵列等价

    +

    矩阵行等价有反身性、传递性。例如:行等价,行等价,则以下两条均成立:

    +
      +
    1. 行等价
    2. +
    3. 行等价
    4. +
    +

    相应的,若有方程组,使得。在等号两端同时乘一个符合乘法运算条件的矩阵,新的方程与先前的方程的解相同。第二个方程与第一个方程就是一组等价方程组

    +

    当且仅当是等价方程组时,增广矩阵行等价。这个推论的证明需要用到一个定理:为一个初等矩阵,则它是非奇异的,且是同类型矩阵

    +
    +

    证明:根据初等矩阵的定义,它是由单位矩阵经过单次初等行变换而来。根据行变换类型的不同,分为三种情况讨论:

    +

    第一种,为第I类初等矩阵。假设它由单位矩阵交换第和第行而来,左乘同样的矩阵,进行相应行运算——右边的矩阵将交换行,因为原本就是交换行得来的。因此左乘后原式,根据逆矩阵的定义:的逆矩阵就是它本身,即,因此二者同类型,都是第I类初等矩阵。

    +

    第二种,为第II类初等矩阵。假设的第行乘一个非零数而来,构造新的初等矩阵,若想使得,用于进行行运算的左矩阵必须要让第行乘上回到。因此的第行同乘以非零数,得到。因此二者都是第II类初等矩阵。

    +

    第三种,为第III类初等矩阵,且是的第行加上第行的倍得到的。因此构造初等矩阵,作为左矩阵,它的效果是让右矩阵的第行减去倍第行,因此,且是将第行乘加到第行得到的。二者同为第III类初等矩阵。

    +

    定理得证。

    +
    +

    两个非奇异矩阵等价的条件是:假设为一个的方阵,所以下面三条命题等价:

    +
      +
    1. 是非奇异的
    2. +
    3. 只有平凡解
    4. +
    5. 行等价
    6. +
    +

    在矩阵运算中,的零解就是这个方程的一个平凡解(因为实在是太显而易见了所以很平凡)

    +
    +

    证明:首先证第一条可以导出第二条。假设为非奇异方阵,是方程的一个解。因此。因为的一个解,因此,原式。因而原方程仅有平凡解。

    +

    再证第二条可以导出第三条。可以化简成行阶梯形矩阵,方程变为。因为严格三角形矩阵可以通过变换得到单位矩阵,所以需要证明是否是严格三角形矩阵。如果的主对角线出现了,那肯定不是严格三角形矩阵。因为阶梯形矩阵要保证每一行都比它的上一行前边的元素多,因为是方阵,到最后一行时只能全部为。此时矩阵有无数组解,因为实际上他只列出了个方程,最后一行的方程不被计入系数矩阵和增广矩阵的秩,导致。因此有无数组解;反之若的主对角线全不为,它可以被化简成单位矩阵(使用高斯消元即可)。因此行等价、行等价,传递得行等价。

    +

    最后证第三条可以导出第一条。根据行等价的定义,必有。根据方才证明的结论:初等矩阵是非奇异的,根据单位矩阵的性质:单位矩阵也是非奇异的。因而也是非奇异的,且

    +

    证毕

    +
    +

    根据第三条,我们就可以知道一个求逆矩阵的方法了:既然,我们给等号两端同时乘一个,得到。因此又与行等价。前两个方程是一对等价方程,我们换元,假设,两个方程如下:。因此增广矩阵可以被化简为。我们只需高斯消元将分隔线左侧化成,右侧自然就是逆矩阵了。

    +
    +

    例3.4.1 How Aranaras Measure Timeflow +兰那罗的时间观念

    +
    +

    你在须弥冒险时,遇到了森林可爱的孩子们——兰那罗。这些小小的生物有着与世无争的纯净心灵、以及大大的胸怀。你们一同冒险,击败了桓那兰那故土的污秽化身,拯救了须弥森林。然而,在和兰那罗对话期间,除开他们奇妙的比喻之外,还有一件事情是你久久无法忘怀的——他们的时间单位。你听过最多的是“种子长成大树”、“太阳升起又落下”、“落落梅从出生到长大”、“大树长成雨林”……

    +

    假如你们经过很长一段时间的交谈,你渐渐明确了各种时间描述词之间的数学关系,关系如下表。请你求出每个描述词所对应的时间间隔

    +
    +

    已知大树长成雨林的时间是种子长成大树的50倍;树木从种子长成大树的期间,落落莓已经生长过整整15次了(由种子出生到果实成熟和从成熟到下一颗种子扎根生长的时间相同);兰那罗从种子长成大树期间,普通人已从黑发少年变为白发苍苍的老人了;普通人从青年到老年的时间足够让三颗种子先后成长为大树;一片树木生长成为雨林,不仅足够让个人先后从少年变为老年,而且还需要额外的60年时间完全长成一片健康的雨林。请问“大树长成雨林”、“树木从种子长成大树”、“兰那罗从种子变成大树”、“落落莓从扎根到成熟”以及“普通人从少年到老年”所经过的时间各是多少年?(四舍五入到最近整数,单位:年)

    +

    问题分析:既然各个描述词对应时长的倍数关系都已给出,我们可以两两列出方程组求解。这里我们用到矩阵的逆来方便求出方程的解。

    +

    算法设计:首先将各个描述词用未知数表示出来,再用数学关系表示出题干中各个描述词的关系,如此得到的5个方程恰好能使矩阵有唯一解。因为一般的方程可以写成的形式,所以求出的逆矩阵,再对常数项组成的列向量进行左乘即可。

    +

    :设“大树长成雨林”、“树木从种子长成大树”、“兰那罗从种子变成大树”、“落落莓从扎根到成熟”以及“普通人从少年到老年”的时间分别为年。根据题干描述。可以得到如下关系:

    +

    +

    整理得:

    +

    +

    对应系数矩阵。常数矩阵,未知数矩阵。对应方程为

    +

    两侧同时乘以得:。根据逆矩阵求法,初始矩阵为

    +

    高斯消元后,将消成形式,得:的逆矩阵就是

    +

    根据方程,得到,此时

    +

    +

    因此,“大树长成雨林”的时间是年、“树木从种子长成大树”需要年、“兰那罗从种子变成大树”需要年、“落落莓从扎根到成熟”需要年、“普通人从少年到老年”需要年。

    +

    最后,森林会记住一切。

    +

    第五节 行列式的性质

    +

    感谢初等矩阵的加持,我们需要记背的知识点又多了不少呢……

    +

    我们在第三节说了,用余子式计算矩阵行列式时,需要按照同一列或者是同一行展开。为什么不能沿对角线或者是其他花里胡哨的顺序算余子式呢?下面有个引理告诉你原因:

    +

    的方阵,表示的代数余子式,则:

    +

    +

    不难发现,的情况就是沿同一列的余子式展开。假如,原式就是沿第一行、从第一列到第列元素的余子式之和。而这恰好是一个矩阵的余子式展开(人家行列式就是这么算出来的,肯定是对的),因而结果等于。当时,就是上边说的花里胡哨的展开。为了证明它,我们假设一个新的矩阵。它的第行被替换成原矩阵的第行,这样的话这个余子式展开就是的正确的余子式展开,也就是说它的结果等于。然而有两行是相同的,也就是说它不可逆(最简阶梯形的最后一行全为0),因而,结果也就是

    +

    假如,那如果有一个初等矩阵左乘它进行行变换,乘积的行列式是否也等于呢?接下来就来探究这个问题:

    +

    假如为一个的第I类初等矩阵,且是单位矩阵交换第一、二行得来的。假设为一个的方阵。那么,那么,而,所以

    +

    推广到矩阵,假设方阵交换一、三行得来的。那么按照第二行展开余子式就是:

    +

    根据矩阵行列式的性质有

    +

    因此对于的方阵,交换其中两行对行列式的影响是改变其符号。其余两类矩阵自行证明,总规律如下:

    +

    ,且

    +
    +

    洛谷例题:

    +
      +
    1. P7112 [模板] +行列式求值
    2. +
    3. P4783 [模板] +矩阵求逆
    4. +
    +
    +

    第四章 向量空间

    +

    第一节 欧几里得向量空间

    +

    简称欧氏空间表示一个维欧氏空间。我们在高中立体几何部分接触了向量在空间内的表示方法,一般来说它们都使用行向量表示一个由原点指向的向量。线性代数中为了区分,大多数时候使用列向量来表示与上边相同的行向量。

    +

    如果仅把描述成由原点指向的有向线段,显然是不太合理的。根据向量知识,一段由指向的有向线段也可以用来表示。因此对于一个列向量,它可以在对应维度空间内画出无数个起点和终点各不相同的向量图像来。如果根据这个原理,列向量表示法就失去了唯一性……

    +

    事实不然,我们发现,无论这个向量的起点如何变化,它们的方向(辐角)、长度(模长)相同,它们可以经过平移变换成同一个向量。只要确定以上这两项的值,一个维向量也就随之确定了。

    +

    +

    (向量可以通过平移变为向量,这两个向量是相等的,都可以用表示)

    +

    根据勾股定理可以计算出向量的长度,这叫做向量的模长的模长一般写作,数值上等于。若是上的一个普通向量,就有。这些是我们高中时期就学习过的内容。

    +

    高中数学教材在虚数那一章还有一个选学知识(2023版)——辐角。尽管它标成“选学”,其实我们早在三角函数的几何表示里就接触过辐角了:一个起点是原点的向量可以看作是它从轴正半轴逆时针旋转得来的,这里的就是向量的辐角。它很有用——是算法中单位根操作的灵魂,被广泛用于电子设备的自然信号处理,你桌面美化包里的频谱图的底层实现就是算法。讲解见此

    +

    我们定义向量的数乘运算:辐角不变,模长相乘。图示:

    +

    +

    +

    我们定义向量的加法,参见高中物理合力与分力的知识。矢量(既有方向又有大小的量)的加法遵循平行四边形法则,平行四边形法则如下图:

    +

    +

    即以要进行加法的两个共起点向量为平行四边形的相邻边,做出完整的平行四边形,它们的和向量的起点与前两个向量起点相同,终点是平行四边形的对角顶点。上图中

    +

    和平行四边形法则等价的还有三角形法则:

    +

    +

    即将其中一个向量的起点平移到另一个向量的终点处,和向量的起点是后者的起点,终点是前者的终点。上图中,注意向量的字母表示有先后顺序,因此不可颠倒变成,事实上

    +

    在向量表示中:。因此向量相加,坐标相加

    +

    减法则是坐标相减,将减数向量做反向同模长的反向量再进行加法运算即可。

    +

    由于矩阵可以拆分成一个个列向量和行向量,而且矩阵的加法与数乘均与刚刚介绍的向量的加法与数乘规则相同。因此矩阵具备表示向量组的条件,称之为向量空间。向量空间中定义的加法和数乘需要满足如下几条(假设为向量,为标量/常数):

    +
      +
    1. +
    2. +
    3. +
    4. +
    5. +
    6. +
    7. +
    8. +
    +

    好多啊ccc,其实就是需要把“加法”定义成正统的加法(满足交换律、结合律);“数乘”定义为正规的数乘(满足结合律、分配律,没有交换律)。可以发现矩阵的加法和数乘和它完美匹配!因此矩阵可以作为一个向量空间。

    +

    于是,向量空间中的元素称作向量。因为这个空间需要包罗万象,就像宇宙空间要包含我们赖以生存的地球一样……它包括我们所需要的向量,因此向量运算最基本的两种——加法与数乘运算所导出的结果必须也在向量空间内,这叫做向量空间内加法和数乘的封闭性,向量空间必定符合这个性质。如此一来,向量空间就足以作为向量所生存的“宇宙空间”了。

    +

    当然有时我们并不需要那么多空间,好比一个人住一个城市……先不提城市各项环节能否正常运作,如果只是用来溜达的,那也是太过巨大了,有些地方可能你一辈子也取不到,还不如开始就不要。向量空间其实也可以像这样压缩范围,并且压缩后的向量空间也必须是全集的子集。根据向量空间的定义,该空间内的向量做任意加法和数乘运算得到的结果都得是空间内的向量。若向量空间的子集满足加法和数乘运算的封闭性,那么的一个子空间。特殊地,都是的子空间,称作零子空间,其他非零且不等于的子空间称作真子空间(类比集合的空集、子集和真子集概念)。

    +

    在矩阵中,也存在零空间。它表现为矩阵方程上的解集。我们首先验证数乘封闭性,;紧接着是加法封闭性:。封闭性得证,因此的子空间。这种空间被称作矩阵的零空间,通常用表示的零空间。

    +
    +

    例4.1.1 Merusea Village Portal 海露村传送门

    +
    +

    自从你来到枫丹,知晓了水仙十字结社的秘密之后,奇怪的事情开始在你身边上演……

    +

    你在海露村遇见了抽象派美露莘大画师玛梅赫、以及一只发条机关狗西摩尔。很不巧,玛梅赫的作画颜料用完了,于是你们前去收集更加纯净的矿物颜料,期间玛梅赫邀请你们进入一个粉色的漩涡虫洞。或许是因为你前一天冒险到深夜,在这个温暖且舒适的环境下来了困意。一闭眼,再一睁眼,迎接你的不是如同往常一般的新地下区域——而是一片温暖的、舒适的粉色幻境——你被一个人丢在这个传送通道里了!

    +

    为了不让派蒙着急,同时也为了你能尽快在下一次困意席卷前逃出这个空间,你需要确定这个传送门是否为“同维度空间卷曲型”——即传送过程中不发生维度的变化。你需要证明你身处的空间是一个三维空间的子空间,这样才能使用正确的方法逃出生天。你发现你的身高和体宽的比值是原来的一半、但是体宽不变。请证明你所在的空间是是三维空间的子空间。

    +
    +

    问题分析:首先要根据已有的信息判断该向量空间是否为三维向量空间的子集,然后再验证加法与数乘的封闭性,只有当二者均成立时才能够证明该空间是三维空间的子空间。

    +

    算法设计:根据题干最后一句话,我们不妨将主人公设为三维坐标系原点,按照三个坐标轴来建立变换关系。比如说“身高体宽比减半”代表的是现在的轴是轴的一半,假设原身高在轴上有个单位,而现在只有两个单位,证明现在的轴被拉伸了一倍。最后关于封闭性的证明,设出几个具有普遍性的向量证明即可。

    +

    :根据变换关系,得到该向量空间的集合形式。因此的子集,令, +数乘:;令,封闭性得证。

    +

    因此,所在空间是三维空间的一个子空间。

    +

    后日谈:其实是你网卡了渲染出错了……和什么三维不三维空间没啥关系……

    +
    +

    第二节 基底、张成与张集

    +

    假设中有向量,那么称作向量 +的线性组合。向量的所有线性组合构成的集合叫向量张成

    +

    我们都知道,个不共线向量唯一确定一个维平面。假如有向量:。它们的张成就是(注:最好是验证两个向量在三维空间里的张成,既直观还符合常规认知)它们围成的维平面。方才的的张成如下图:

    +

    +

    如果,则称张成。用表示。有以下两条性质:

    +
      +
    1. ,则的子空间
    2. +
    3. 向量平面中一组向量的张成是中包含这组向量的最小子空间
    4. +
    +

    对于第一条,因为你怎么拟合平面,都不可能让你的平面比整个空间的维度更高,而且无论以什么系数搭配向量,它们所得的新向量都在整体空间内,第一条就能很简明的证明了。第二条性质,首先空间内向量的张成必为整个空间的子空间,毕竟用的都是数乘和加法,用的向量也都在空间内,总不能算一下加法向量就跑到空间外边去了吧,此外,因为数乘和加法的封闭性,任何经过这两个向量的空间都包含其张成,因此它是最小的。

    +

    和张成相对,如果张成,则张集

    +

    基底,大家在高中立体几何部分学过了。当时的定义是:平面内不共线的两个向量叫做这个平面的一组基底。然而这段话可以用线性代数的语言原原本本描述出来:“维向量空间中有个线性无关的向量,则称它们是向量空间的一组基”。线性无关的概念,之前已经简单讲过,总的来说就是向量不共线,即不存在标量,使得;线性相关则反之,指的是两个向量共线,即成立。正如在高中课堂上学的一样,给出一个维空间的一组基底,该空间上所有的向量都可以用这组基底唯一地表示出来。比如下边这个例子:

    +
    +

    例4.2.1 Al-Ahmar's Trial 赤王的试炼

    +
    +

    你和婕德一行人在圣显厅前击败了图谋不轨的镀金旅团,并在他们搭起的营帐里发现了一封密信。上面写着若想进入圣显厅,需先过三关试炼。为了能够一探黄金梦乡的秘密,你接下了完成三重试炼的任务,然而当你真正进入到第一重试炼时,却发现事情并没有这么简单……

    +

    你进入了试炼场地,却发现整个世界天旋地转。最终安定下来,你发现赤王的神奇科技把你带入了一个维空间内。这还没完,四周又有整齐排列的空气墙阻挡了你的通路。经过好一顿摸索,你终于发现这是一个维空间,于是你开始建立空间坐标系,五个坐标轴分别是,假设你现在所在的地方是原点,通关点。四周的空气墙限制了你仅能沿着与向量平行的方向行动。请问如何安排前进方向使得你能够从起点到达终点

    +
    +

    问题分析:这个问题明显是让我们用来表示出从起点(原点)到终点的一个向量,因为这五个向量不共线,可以作为五维向量空间的一组基底。又因为基底可以唯一地表示出平面上的所有向量,考虑列方程组求解每个基向量的系数关系。

    +

    :明显地,题中五个向量互相线性无关,因此可以作为该平面的一组基。由于向量加法和数乘运算的封闭性,且路径向量在该平面上,因此可以拆分成这些基向量的倍数和形式。

    +

    ,则有方程组,方程组的解:

    +

    因此,应在方向上移动,在方向上移动,在的反方向上移动,在方向上移动,在的反方向上移动就可以到达终点。

    +
    +

    因此一旦选定了平面的基底,该平面上所有的向量都可以用这组基底唯一表示出来,具体操作是使待求向量,接着解方程求出系数的值即可。

    +

    基底可以表示平面内所有的向量,故维平面的基张成

    +

    第三节 线性基

    +

    第二节里我们讲了向量空间的基底,基底其实还有一个名称叫线性基。平面中所有向量唯一对应一种基底的线性组合。在OI中常常被用于求第大异或和的问题。为了和实数四则运算的线性基区分,这种线性基下称异或线性基

    +

    一组值的异或和可以看做该空间内异或线性基的向量的异或组合,由于基底表示向量的唯一性:原集合中的数可以通过异或线性基里的基向量唯一确定。它有如下几个性质,事实上,它和普通平面内的实数线性基有相似之处:

    +
      +
    1. 原序列中任何元素都可以通过异或线性基内的元素异或得到
    2. +
    3. 异或线性基不存在重复元素,且在保证性质一的前提下,它的元素最少
    4. +
    +

    异或运算也有一个特殊性质,若,则

    +

    根据以上性质构造计算方法:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void insert(ll x) {
    for (int i = 63; i >= 0; i--) {
    if ((x >> i) & 1) { // 要存放的数的当前位为1
    if (!p[i]) {
    p[i] = x; // 异或线性基该位为0,二进制下该位置为1
    break; // 已找到位置存放,退出循环
    }
    x ^= p[i]; // 异或线性基该位为1,为化为下三角形矩阵形式方便计算置为0
    }
    }
    }
    +

    由于一般题目中数据范围是1e18,而转换为二进制位就有位,因此数据类型最好选用无符号长长整型unsigned long long,线性基p数组至少需要60位。

    +

    有时并不是所有的插入操作都会成功,因为要保证异或线性基里的向量互相线性无关。存储操作本质上是拆分二进制位,然后将它尽量表示为已有基向量的异或和,好像除去每个人身上的共同特征,只保留人的独特个性一般。如果拆到最后再也拆不了了,证明它是独特的,可以加入其中。反之,这个数就可以被其他数通过异或运算代替,没必要加它,返回插入失败。可以有下面的代码:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    bool insert(ll x) {
    for (int i = 63; i >= 0; i--) {
    if ((x >> i) & 1) {
    if (!p[i]) {
    p[i] = x; // 异或线性基该位为0,二进制下该位置为1
    break; // 已找到位置存放,退出循环
    }
    x ^= p[i]; // 异或线性基该位为1,为化为下三角形矩阵形式方便计算置为0
    }
    }
    return x; // 若被异或分解为0,则证明它可以被现有元素计算得到,为保证异或线性基元素互相线性无关,不予插入
    }
    +

    如果是求一个数能否被这个异或线性基表示出来,将最后一行改为return !x;即可(能表示即不可插入,不能表示即可以插入)。若某次插入失败,证明可以被表示出来,在求最小值是要额外关注!我们在此维护一个布尔值flag = false,在插入失败后设为true表示需要特判

    +

    线性基用于求解一组数的异或和最值问题,有下面求最值的三个例子。它们无一例外使用了贪心法:

    +

    1. 求最大值

    +
    1
    2
    3
    4
    5
    6
    7
    ll xorMax() {
    ll ans = 0;
    for (int i = 63; i >= 0; i--) {
    ans = max(ans, ans ^ p[i]);
    }
    return ans;
    }
    +

    为什么从高位开始遍历?我们都知道如果一个数字的某位数大于另一个数字相同位置的数(两数数量级相同,即十进制下位数相同),那么前者是大于后者的。根据异或的运算法则:“不同为,相同为”。如果ans的高位此时是0,若进行异或运算的同位数字是0,即二者相同,结果为0,不会变得更小;反之若异或运算的对应二进制位为1,当前位异或结果是1,变大了,因此;如果ans高位为1,运算数对应位为0,结果为1,不会变得更大;若运算数当前位是1异或结果为0,变小了,所以

    +

    2. 求最小值

    +
    1
    2
    3
    4
    5
    6
    7
    ll xorMin() {
    ll ans = 0;
    if (flag) return 0; // 特判0
    for (int i = 0; i <= 63; i++) {
    if (p[i]) return p[i];
    }
    }
    +

    我们知道,可以通过任意组合(异或运算)异或线性基中的元素来得出各种新的元素,若无法被表示出来,我们找到异或线性基里最小的元素即可,因为异或线性基里的每个元素也是原序列中某些元素的异或和;反之返回

    +

    3. 求第小值

    +

    这才是异或线性基的高级玩法

    +

    为了求第小值,首先要对异或线性基进行一轮清扫。将它高斯消元化简为最简形式,称作重构rebuild

    +
    1
    2
    3
    4
    5
    6
    7
    void rebuild() {
    for (int i = 63; i >= 0; i--) { // 从高位开始按位扫
    for (int j = i - 1; j >= 0; j--) { // 遍历右移
    if ((p[i] >> j) & 1) p[i] ^= p[j]; // 保证p[i]是异或线性基里第i位最小的那个,通过不断异或可以变小
    }
    }
    }
    +

    接着我们需要特判,如果每一次插入都可以成功进行,向量之间互相线性无关,也就无法表示。在求小值时,若,也就是说求最小值,明显应该返回,如果按照常规思路返回就是错误的,因为这个做法的前提是。所以如果先前的插入操作出现失败的情况,就要对进行特判,原先的实为

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    ll queryKMax(ll k) {
    if (k == 1 && flag) return 0; // 特判
    if (flag) k--; // 特判0,f(k)实为f(k-1)
    rebuild(); // 重构异或线性基
    ll ans = 0;
    for (int i = 63; i >= 0; i--) {
    if (p[i]) {
    // 对k进行二进制分解
    if (k & 1) ans ^= p[i]; // 位为1,异或
    k >>= 1;
    }
    }
    return ans;
    }
    +

    除了求值,异或线性基还可以合并,甚至于求它和另一个异或线性基的交集与并集。所以异或线性基是一种数据结构。封装在一个结构体XorBase里:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    struct XorBase {
    ll p[64];
    bool flag;

    XorBase() {
    flag = false;
    memset(p, 0, sizeof p);
    }

    bool insert(ll n) {
    for (int i = 63; i >= 0; i--) {
    if ((n >> i) & 1) {
    if (!p[i]) {
    p[i] = n;
    break;
    }
    n ^= p[i];
    }
    }
    if (!n) flag = true;
    return n;
    }

    void rebuild() {
    for (int i = 63; i >= 0; i--) {
    for (int j = i - 1; j >= 0; j--) {
    if ((p[i] >> j) & 1) p[i] ^= p[j];
    }
    }
    }

    ll getMin() {
    if (flag) return 0;
    for (int i = 63; i >= 0; i--) {
    if (p[i]) return p[i];
    }
    }

    ll getMax() {
    ll ans = 0;
    for (int i = 63; i >= 0; i--) {
    ans = max(ans, ans ^ p[i]);
    }
    return ans;
    }

    ll MaxK(ll k) {
    if (k == 1 && flag) return 0;
    if (flag) k--;
    rebuild();
    ll ans = 0;
    for (int i = 63; i >= 0; i--) {
    if (p[i]) {
    if (k & 1) ans ^= p[i];
    k >>= 1;
    }
    }
    return ans;
    }
    };

    +

    4. 并集

    +

    思路就是枚举异或线性基的内容,将其中元素全部加入到中。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    XorBase Union(XorBase A, XorBase B) {
    XorBase res = B;
    for (int i = 0; i <= 63; i++) {
    if (A.p[i]) {
    res.insert(A.p[i]);
    }
    }
    return res;
    }

    +

    5. 交集

    +

    如果一个异或线性基里的元素插入到另一个异或线性基里会失败,则将它插入到交集异或线性基中。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    XorBase Intersect(XorBase A, XorBase B) {
    XorBase res;
    for (int i = 0; i <= 63; i++) {
    if (A.p[i]) {
    if (!B.insert(A.p[i])) res.insert(A.p[i]);
    }
    if (B.p[i]) {
    if (!A.insert(B.p[i])) res.insert(B.p[i]);
    }
    }
    return res;
    }
    +
    +

    例4.3.1 DMG Bonus 核爆

    +
    +

    作为一名资深神原玩家,你希望能在新限定五星角色初进卡池时尽快拿下全网首个999w核爆记录,以此证明自己的实力。现在你已经在游戏里做好了很多伤害加成型的食物,准备在boss战时一展身手。战斗开始时,你首先给角色吃下了基础食物(每局开始前必吃的食物),它的效果是在300秒内单角色爆发伤害增加,但是同时它有一个副作用……

    +

    基础食物生效期内,如果角色吃下其他伤害加成型的食物,总伤害加成的百分比数值将是各种食物的伤害百分比数值的异或之和,即表示为异或符号。各种食物的伤害加成在下边给出,如果不吃任何加成型食品(也不吃基础食品),爆发伤害期望值为。吃完所有食物后,如果你用增伤角色施加了的爆发增伤。请问你的最大爆发伤害能否达到,即?若不能,最高伤害是多少?(令每种食物只有一份,且食物效果均可叠加,结果四舍五入到万位)

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    编号加成效果
    1270%
    2200%
    3280%
    4200%
    5180%
    6150%
    775%
    +

    问题分析:题干信息已经很明显了,这是一道异或线性基的最大和问题。根据上文所述程序计算即可。

    +

    算法实现:这里使用的是结构体封装版本的异或线性基计算代码:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    #include <bits/stdc++.h>
    using namespace std;

    typedef unsigned long long ll;

    struct XorBase {
    ll p[64];
    bool flag;

    XorBase() {
    flag = false;
    memset(p, 0, sizeof p);
    }

    bool insert(ll n) {
    for (int i = 63; i >= 0; i--) {
    if ((n >> i) & 1) {
    if (!p[i]) {
    p[i] = n;
    break;
    }
    n ^= p[i];
    }
    }
    if (!n) flag = true;
    return n;
    }

    void rebuild() {
    for (int i = 63; i >= 0; i--) {
    for (int j = i - 1; j >= 0; j--) {
    if ((p[i] >> j) & 1) p[i] ^= p[j];
    }
    }
    }

    ll getMin() {
    if (flag) return 0;
    for (int i = 63; i >= 0; i--) {
    if (p[i]) return p[i];
    }
    }

    ll getMax() {
    ll ans = 0;
    for (int i = 63; i >= 0; i--) {
    ans = max(ans, ans ^ p[i]);
    }
    return ans;
    }

    ll MaxK(ll k) {
    if (k == 1 && flag) return 0;
    if (flag) k--;
    rebuild();
    ll ans = 0;
    for (int i = 63; i >= 0; i--) {
    if (p[i]) {
    if (k & 1) ans ^= p[i];
    k >>= 1;
    }
    }
    return ans;
    }
    } A;

    int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int n;
    cin>>n;
    for (int i = 1; i <= n; i++) {
    int x;
    cin>>x;
    A.insert(x);
    }
    cout<<(1400000 * (A.getMax() + 60 + 70) / 100)<<endl;
    return 0;
    }
    +

    运行代码,在输入框输入:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    7
    270
    200
    280
    200
    180
    150
    75
    +

    结果输出:8162000.000。小于所给的。因而不能达到目标,最高伤害816万。

    +
    +

    洛谷例题:

    +
      +
    1. P3812 [模板] +线性基
    2. +
    3. P4570 [BJWC2011] +元素
    4. +
    5. P4301 [CQOI2013] +新Nim游戏
    6. +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +
    + + +
    +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/magic-show-with-josephus/index.html b/magic-show-with-josephus/index.html new file mode 100644 index 0000000000..f22a7d3fc6 --- /dev/null +++ b/magic-show-with-josephus/index.html @@ -0,0 +1,4363 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 约瑟夫环——春晚魔术表演原理解析 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + +
    + + + +
    + + + + +
    +
    +

    +

    (操作没成功の尴尬,图片来自知乎

    +

    前言

    +

    这篇文章从数学方面推导刘谦2024年央视春晚上表演的第二个魔术的秘密、分析尼格买提错误之处,并在已知信息的加持下尝试推测尼格买提手上所剩的两张半面扑克牌的牌型。有一说一撒贝宁是真的会测假

    +

    对应魔术节目:《守岁共此时》的回看请戳这里,在一小时十分整处。

    +

    魔术步骤

    +
      +
    1. 四张牌面向下,并打乱。
    2. +
    3. 对折四张牌,并沿折痕撕开,得到两批半牌,每批四个共八个半牌 +(反过来折是为了方便撕开)。将左右手的两批牌按同一个方向叠在一起。
    4. +
    5. 根据自己名字的字数,从上端挨个拿出一个牌放到最底端,执行字数次。
    6. +
    7. 拿起最上面三张,插进其他牌的中间(意思是这三张看作一个整体,不能放在最上面或者最下面,必须夹在其他牌中间)。
    8. +
    9. 拿起最上边的牌,藏起来不要看魔术常规操作之不要看
    10. +
    11. 继续从最上边拿牌:南方人拿一张、北方人拿两张、不确定就拿三张。然后像第四步那样插进中间位置。
    12. +
    13. 还是从最上边拿牌:男生拿一张、女生拿两张。然后将拿出的牌扔出去。
    14. +
    15. 「见证奇迹的时刻」——每一次操作,将最上边的牌移到最下边,每次仅移动一张牌,进行七次。
    16. +
    17. 「好运留下来,烦恼丢出去」——对于每次操作:第奇数次,将牌移到最下边;第偶数次,丢出去。最后直到只剩一张牌
    18. +
    19. 最后拿出藏起来的牌,如果你的名字在四个字及以内、且操作无误,你会发现这两张半牌是严丝合缝的,他们可以拼成一张牌!
    20. +
    +

    列数模拟

    +

    先不管你拿了哪几张牌,也不管打乱前它们的先后顺序如何——因为它们都跟魔术本身、也和我们的推导无关。我们只着眼于打乱后的牌,将它们按照上下依次编号为1~4。如下图:

    +

    1234

    +

    沿折痕撕开,假设第1号牌撕成的两张半牌编号为1和A(数字在上字母在下),八张半牌叠在一起,得到的牌堆是这样的:

    +

    1234ABCD

    +

    接下来的推导就围绕上面这个牌堆开展。

    +

    对应第三步——从上边拿出和自己名字字数相同的牌,放到最下边。假如我拿出三张,也就是编号为1、2、3的三张牌,放到最下边。牌堆变成这样:

    +

    4ABCD123

    +

    第四步——再拿出最上边三张牌,卡到中间去:

    +

    CD4AB123

    +

    第五步——藏起最上边的牌,也就是编号为C的牌。

    +

    第六步——根据南北方人拿牌。因为我祖籍北方出生在南方,我这里就拿三张牌插入到中间位置(B和1之间):

    +

    ABCD4123

    +

    我是男生,丢最上边的一张牌,也就是说丢出编号为A的那张(此时内心默默丢掉了两张牌):

    +

    男:BCD4123 女:CD4123

    +

    然后是见证奇迹的时刻。此时男生手里剩下7张牌、女生则是6张。这里其实无需说出那句咒语:如果你是男生,就不做操作;如果是女生,就将最上边的牌放到最下边。

    +

    男:BCD4123 女:D4123C

    +

    最后是好运留下来、烦恼丢出去。按照规则,我们要轮流进行两个操作:移动最上边的牌到最下边、丢掉最上边的牌。如此操作直到只剩下一张牌。这其中涉及到一个知识点——约瑟夫环问题

    +

    约瑟夫环问题

    +

    百度百科 约瑟夫问题

    +

    简而言之,就是从特定编号出发,每经过个数便将此时的数字挑出,剩下的数重新编号(保证起始编号相同),问最后剩下的编号是什么。这个环节的操作在这个例子下可以被抽象成:从D开始,每两次操作,丢出第二张牌。

    +

    也就是说,七个人围成一圈,“1、2、1、2……”的报数,最后剩下的是几号。这里有一个巧算的方法,适用于“1、2、1、2……”报数模型。首先找出不大于人数7的最大的2的整数幂,因为,所以令当最终剩下个人的时候,第一个报数的就是最后一个被留下的,因此有公式:

    +

    对于男生,最后剩下的牌就是最下边的那一个,编号3

    +

    对于女生,剩下的是第个,同样是3

    +

    拿出藏起来的牌C,我们开头就知道了:第三张牌被分成了3和C。也就是说它们可以拼合成同一张牌!魔术成功了!

    +

    回顾总结

    +

    不妨从一开始就观察3C的变换规律,可以发现3号牌自从第三步结束后被移动到最下边以来就几乎没改变过位置;而前四步则是合力将C拉到了最前边好让它被顺利地挑出去。然而最为精妙的还是对“1、2、1、2……”报数约瑟夫环模型的应用。那么为什么尼格买提的操作会失败呢?看下图:

    +

    如果你是罕见的“第三性别”,想要在第七步里面丢三张牌,也是可以的,因为这样并不会改变最后一张牌3。事实上,这个魔术最多可以在第七步丢掉七张牌,这样下来就只会剩下一张牌3,全部完成之后还是可以和C配对成功的。

    +

    +

    右上角是他的操作:他在“南方人和北方人”的操作里拿了三张牌,但是插入的时候错误将其中两张牌插到了最下边并且这两张牌和另外的那一张牌分开了(原规则是一起插到中间)。

    +

    因此这堆牌的底端变成了黑桃Q,不久之前,他藏起了一张黑桃A。所以,他最后拿出的牌是对不上的,一张是黑桃A,一张是黑桃Q。

    +

    下面是从班级群里偷的几张图,以实际证明这个理论是成功的:

    +

    +

    当然,如果就某位“客串见证人”的失误而大做文章的话,显然是极其招人嫌恶的。刘谦本人的魔术并没有什么问题,尼格买提可能也只是太过关注自己接下来在春晚上的表现而有些分神罢了。如果这个失误真的导致2025年春晚刘谦不被总导演邀请上台的话,这种毫无底线夸大其词的舆论只会是雪上加霜,让所有人更不好过而已……事后小尼本人也道了歉,因此已经没有必要再抓住谁人的过错不放,只是从科学的角度出发,论证这个魔术的成功之处。毕竟少有节目能如此调动起屏幕内外所有人的互动热情,如此看来,刘谦的魔术也是非常成功的了。

    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +
    + + +
    +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/memes/index.html b/memes/index.html new file mode 100644 index 0000000000..53568ac8d1 --- /dev/null +++ b/memes/index.html @@ -0,0 +1,4266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 高2023级一班热梗总结 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + + + + + + +
    +
    +

    2023.9

    +

    1. 吃饱啦

    +

    九月初的某节语文课,当语文老师问及苏轼的个人形象时,国祯和小又肥同时说出了“优雅”二字,国祯更是以一个屁总结了自己的观点。此后不久,国祯和冰正在激烈地讨论老八秘制小汉堡的事情,正当所有人因为思考语文老师提出的问题而陷入短暂沉寂时,冰向后一靠,把手垫在脑后,说了一句:“吃饱啦!”。便如此得名。

    +

    2. 电饭煲

    +

    国祯表示历史老师长得很像电饭煲,于是得名

    +

    3. 干饭

    +

    9月4日,一班真正意义上进行了一次以教室为起点的干饭行动,基本上一分钟内能够到达食堂。

    +

    4. Global Reading

    +

    张伟水课的新型套路——不讲正课天天喊我们拿出Global +Reading来看,久而久之成为英语课和扣分的代名词。

    +

    5. 手套月饼

    +

    9月28日周四晚,东辰组织制作月饼,有人在月饼里放狠料咖啡粉、硬币、长尾夹(后被取出)。事后国祯将此事传开,被茂华得知,被张伟处分。

    +

    6. +巨人熊猫,孔子牙膏(富兰克林,酱香瑞幸)

    +

    张伟最爱罚背的几篇Global +Reading上的文章,国庆放假前被总结为这句口头禅

    +

    2023.10

    +

    7. 奖励

    +

    张伟扣分前的口头禅,后演变为罚背的代名词

    + + +
    + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/misc/index.html b/misc/index.html new file mode 100644 index 0000000000..083cbd6b7a --- /dev/null +++ b/misc/index.html @@ -0,0 +1,4246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 机房管理助手 v9.x已成功破解 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + + + + + + +
    +
    +

    任务管理器已解禁,您也可以自由使用注册表和组策略进行其他操作

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +
    + + +
    +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/new-year-crack/index.html b/new-year-crack/index.html new file mode 100644 index 0000000000..102cde5d5a --- /dev/null +++ b/new-year-crack/index.html @@ -0,0 +1,4451 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2023年度总结——机房管理软件的破解经验 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + +
    + + + +
    + + + + +
    +
    +

    +

    文中提到的核心程序代码及食用方法在文章末尾处,或者访问我的云剪贴板来复制代码

    +

    +

    极域——世界上最弱小最单纯的机房软件

    +

    注意,极域由C/C++语言开发。对于极域的反编译工作可以基本认定为徒劳且耗费大量时间的。

    +

    开始的开始,我的脱控方式还仅限于最原始的taskkillntsd。这种做法不仅有时会失效,而且一旦老师发现你的机子的监控屏幕是纯黑一片、且无法控制,他就会气急败坏地冲向你对你进行一顿输出,结果自然是被班主任教训一顿、这学期的信息课停上。

    +

    令人欣慰的是:这种低级脱控方式已经在学子之间渐渐隐没不见,取而代之的是层出不穷的脱控软件,例如JYTrainer、还有本人开发的ClassX(doge)等等……

    +

    因为本人不会那些所谓的网络IP、频道更改之类的高科技东西,另一方面实现如上的功能多半需要辅助程序(容易被反脱软件检测到进程名)。本着精简实现、不易查封的原则,我从非exe层面出发,编写了一套脱控程序供大家伙们免费使用,毕竟人生苦短,及时行乐嘛(doge)。

    +

    板块一 TD到底是啥的缩写?

    +

    你知道明明U盘里装着几个G的学习资料却无法在计算机课上给周边的同学炫耀是怎么样一种感觉吗?你知道明明想要打开小破站观看最爱的coser投稿的新擦边视频却被提示“该网站已被禁止”是什么样的感觉吗?

    +

    出于以上两种痛苦的经历,我立志要写出能够禁止极域牛马功能的脚本。就先从U盘解禁和网络解禁两个方面入手!

    +

    Windows服务概述:打开任务管理器,选项卡里不仅有经典的“进程”选项、也有装机大佬们引以为傲的“性能”选项,可是我们今天的主角:“服务”选项却几乎无人问津。

    +

    类似于cmd的打开方式,服务管理器则需要在Win+R后输入services.msc来使用;你也可以通过任务管理器“服务”选项卡进入。那么什么是服务呢?

    +

    Windows服务是指系统自动完成的,不需要和用户交互的过程,可长时间运行的可执行应用程序。这些服务可以在计算机启动时自动启动,可以暂停和重新启动而且不显示任何用户界面。一个词概括就是:“幕后黑手”。开头立的flag就需要通过这种方式巧妙解决。

    +

    定位到极域安装目录:会发现下面有好多TD打头的文件,而当你在服务里面搜索时,你会发现一个惊人的巧合:TDNetFilterTDFileFilter早已在你的机器上悄然运行了很久。看到它的名字,容易知道前者禁掉了你的网络、后者ban掉了你的U盘。如何终止服务呢?这也非常的简单:

    +

    在Windows系统中,与服务有关的命令是sc。要想停止某个服务,只需安装如下模式输入指令:sc stop [NAME]NAME是服务名称)。于是我在ClassX的开头加入了如下的指令:

    +
    1
    2
    sc stop tdnetfilter
    sc stop tdfilefilter
    +

    这样就结束了吗?然而并没有……

    +

    板块二 可疑的程序

    +

    上一节里遗留了一个小问题:停止了服务后他就真的解禁了吗?事实并非如此:没过几秒,你的网络又会恢复到先前的状态、U盘再次被封杀。一切的一切都是因为两个不起眼的可疑程序……

    +

    ProcHelper64.exeMasterHelper.exe——《我们俩》

    +

    有人问我当时是怎么发现的。首先需要知道,每个版本的Windows系统几乎都有一套特别的图标主题(图标存放在Shell32.dll中),现如今大部分机房电脑使用的是Win10系统,然而上述两个进程使用的是WinXP风格的图标,直接一眼丁真掏出taskkill秒了。真是实力坑队友

    +

    因此ClassX里面还有这一段代码:

    +
    1
    2
    3
    4
    5
    :a
    taskkill /f /t /im ProcHelper64.exe
    taskkill /f /t /im MasterHelper.exe

    goto a
    +

    :a定义了一个函数a,中间是函数体,最后一行的goto a则是调用这个函数,注意goto a写在了a函数内部,起到了while (true) {...}的死循环作用。你也可以在空行出添加一段TIMEOUT /T 1,即延时一秒,因为这两个程序的复活时间大概在1秒左右(终止后一秒就会重启)。

    +

    板块三 拒绝访问什么鬼?

    +
    第一种情况:钩子程序
    +

    如果你是Win7及以下的系统,且直接使用任务管理器结束进程,那么很有可能会出现像标题这样的提示。这是因为极域启动了一个系统钩子(四川人莫笑,Hook翻译过来的确是钩子的意思)。

    +

    Windows钩子概述:类似于游戏(以及Scratch)的消息机制,Windows中存在一种事件系统,Win+R弹出运行、输入eventvwr.exe/eventvwr.msc打开事件管理器,你会看到本机所有事件的发生时间及概况。把Windows系统的事件系统比作一条河流,最上游是系统,负责抛出事件,事件信息顺流而下;把应用程序比作渔夫,它们在河岸两侧用网捞特定类型的事件,大多数情况下自行处理后再放回到河中。

    +

    对于极域来说,它在一个名叫NtTerminateProcess的系统函数上下钩,检测这个函数的传入信息,即终止对象的进程名,是否是StudentMain.exe(极域主程序),若是,就返回false,也就是失败。因而导致开头所说拒绝访问的情况,而把钩子钩在此处的,就是我们的TD圈大佬LibTDProcHook.dll。因为本人使用Win10系统,这个钩子对于Win7以后的系统都会失效,因此Win8/10/11用户可以直接用任务管理器。对于Win7系统用户,在这里使用WinAPI终止这个TD模块。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    #include <bits/stdc++.h>
    #include <windows.h>
    #include <tlhelp32.h>
    #include <processthreadsapi.h>

    using namespace std;

    DWORD GetPID(const char* proc) {
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

    if (Process32First(snapshot, &entry) == TRUE) {
    while (Process32Next(snapshot, &entry) == TRUE) {
    if (stricmp(entry.szExeFile, proc) == 0) {
    HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
    DWORD pid = GetProcessId(hProc);
    CloseHandle(hProc);
    return pid;
    }
    }
    }
    }

    int main() {
    HMODULE hook = GetModuleHandle("LibTDProcHook64.dll");
    FreeModule(hook);
    HANDLE handle = OpenProcess(PROCESS_TERMINATE, FALSE, GetPID("StudentMain.exe"));
    TerminateProcess(handle, 0);
    return 0;
    }

    +
    第二种情况:时代变了
    +

    自从学校机房的极域从2014版更新到了2020版,上述朴素解决方案已经不见效了。我也不知道从哪一年的版本开始,它给自己的服务加了一层防护,普通地运行bat脚本还木有用。但是它解决起来也简单,右键文件“以管理员模式运行”即可。

    +

    除此之外,你还可以在脚本开头加入:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    >nul 2>&1 "%SYSTEMROOT%\System32\cacls.exe" "%SYSTEMROOT%\System32\config\system"


    if %errorlevel% == 0 (
    echo Admin Switched!
    ) else (
    echo Level Ascending... Restart

    powershell -command "Start-Process '%0' -Verb RunAs"
    exit
    )
    +

    来实现UAC自动提权管理员!

    +

    板块四 挂起进程

    +

    有一天我的同学给我推荐了这个方法,说是用一个命令行程序Suspend来命令层面挂起极域进程实现随意脱控,亲测有效。如果使用性能监视器也可以达到相同效果。

    +
    挂起为何物?
    +

    大家可能有过这样的经历:当你用WPS做PPT或者正在用WPS演示PPT时,有时它会莫名其妙地卡掉,尤其是你画了太多墨迹注释时,看着永不停歇转动的“繁忙”鼠标图标,你也许会耐不住性子直接任务管理器结束进程,并发誓要下载一个破解版的微软Office全家桶来用。像这样,程序的卡死就是挂起的一个形式,当然,当CPU面临有限的内存分配问题时,它会优先分配运存给那些需要内存的重要程序而把不那么重要的进程挂起,表现为对用户操作无响应等。

    +

    那么你可能已经猜到了这一方法的逻辑了:我们挂起极域主进程。这样当教师端发送指令(黑屏安静、全屏广播等)时,你这边的极域接收端(学生端)就无法对指令作出响应,自然也就不会被控制。桌面监控同理,也会被影响,不同的是,教师端的监控小窗只会定格在你挂起极域前传输过来的最后一帧画面,总之瞒天过海是基本上没问题的了……

    +

    根据上述原理,我们有两种方式来挂起一个进程(其实本来还有Win32API这种方法,留给读者自行研究):

    +
    第一种 性能监视器
    +

    你可以打开任务管理器,在“性能”一栏的左下角可以看到“性能监视器”选项(Win10),对于Win11用户,则需点击“性能”栏右上角三个点,然后选中“性能监视器”;也可以Win+R输入perfmon.exe /res直接打开(万能)。还有几种方法见百度百科

    +

    在性能监视器中,我们在最上面“进程”列表中找到StudentMain.exe(一般来说有两个同样的进程),接着挨个右键点击“暂停进程(S)”即可。

    +

    +

    但是这样的话,你在教师端那边的小窗口上就会显示出一个性能监视器的窗口,感觉不太完美,怎么能优化一下呢?

    +
    第二种 Suspend命令行
    +

    PS +Suspend - Microsoft Learn

    +

    PS +Suspend微软官方下载地址

    +

    下载后的压缩文件里面有一个.cmd文件,用记事本打开:

    +
    1
    2
    3
    4
    5
    chcp 65001
    @set suspend_targets=osu!.exe DDLC.exe
    @suspend.exe %suspend_targets%
    pause
    @suspend.exe -r %suspend_targets%
    +

    其实我们真正需要修改的内容是第二行:它使用bat批处理脚本设置变量suspend_targets,传入需要挂起进程的进程名称话说DDLC是真的生草……。这里我们修改参数值为StudentMain.exe

    +
    1
    2
    3
    4
    5
    chcp 65001
    @set suspend_targets=StudentMain.exe
    @suspend.exe %suspend_targets%
    pause
    @suspend.exe -r %suspend_targets%
    +

    pause之后的那一行是解除挂起的代码,因为bat执行到pause语句后会等待用户输入任意字符后才继续进行,因此如果遇到紧急情况需要解除挂起,只需在命令行窗口点击任意键即可。

    +

    需要注意的是,一定要把下载好的压缩包里面的所有文件放到同一个目录下,否则缺失任何文件这个工具都是无法正常运行的。

    +

    板块五 留给2024的一个小问题

    +

    那天我在思考如何一劳永逸的结束极域进程,我打开了服务列表,在里面看到两个纯大写拼成的服务名GATESRVSTUDSRV。可惜的是那天放学,我没能来得及探究清楚这两个服务与极域的关系,目前已知的信息就是它们绝对是极域自己启动的两个服务。

    +

    这个问题就留给2024的我解决吧

    +

    // TODO

    +

    红蜘蛛软件——可曾听闻我绿蜘蛛脚本的厉害?

    +

    在本人印象中,红蜘蛛似乎就仅仅只是一个吉祥物,只有在开机后那么几秒,它拖着上世纪复古风的“高清”启动界面在我的眼前一闪而过,然后静静地躲在任务栏的小图标里,践行它大隐隐于市的人生信条……

    +

    说实话要不是同学提醒我还真忘了机房里还有这位叫红蜘蛛的朋友,于是我着手开始破解它。红蜘蛛:我吃柠檬

    +

    1. 这玩意怎么跟2345一个德行?

    +

    知道2345全家桶的同学们肯定对它恨之入骨,尤其是那些下载了2345的同学们。2345号称天朝第一大流氓软件,在无数人的电脑中如同鬼魂一般挥之不去。捆绑安装、弹窗广告、强制修改系统文件、浏览器劫持……无奇不有,关键是它的公司甚至推出极其出生的“推广包”机制来诱惑不良商户分发2345毒瘤软件。这篇文章介绍了清除2345的一种方案。

    +

    回到本节主题上来,为什么会取这样一种怨气十足的标题呢?是因为它和2345伪装成系统文件类似,红蜘蛛属于是反向利用了系统文件来给自己加上一层保护网。

    +

    打开任务管理器,除了霸占后台程序第一行的红蜘蛛本体,下面还有两个附属程序,名叫“3000soft通用组件”,如果直接终止进程,它很快会再次冒出来。将它们展开后发现叫做checkrs.exerscheck.exe的程序。那么运用上边经常用到的服务搜查法,我们发现了两个命名规则极其相似的服务:appcheck2checkapp2

    +

    +

    然而我事后才发现红蜘蛛官网早已自报家门了……血亏!

    +

    常规思想:我们使用sc命令结束这两个服务,然而……

    +

    // TODO

    +

    显示无法停止,那怎么办呢?

    +

    考虑到这两个进程是红蜘蛛死掉后无限重启的命根,并且这两个进程也跟红蜘蛛主程序一样杀了就会重启……很明显,根本原因就是那两个服务,但是sc命令不管用了,咋办呢?(抠头)

    +

    这时我们就需要绕道而行,既然命令不行,我们转战注册表!打开注册表管理器,定位到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services文件夹,它有很多个子文件夹,在下面定位到appcheck2checkapp2,它的文件结构类似于这样(这里用别的服务替代一下):

    +

    +

    (注意,这个并不是红蜘蛛的服务,是我临时找别的替代的,它们的文件名相同,只是数据不同而已)

    +

    容易发现:ImagePath项指向了服务的根文件地址,也就是俗称的万恶之源,既然每次终止组件后它会自动重启服务,那我们为何不破坏这个ImagePath,让它指向一个不存在的地址,这样它就启动不了任何东西了。在我的绿蜘蛛inf文件里如此写到:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [Version]
    Signature="$CHICAGO$"
    Provider=justpureh2o@outlook.com, 2023

    [DefaultInstall]
    DelReg=Delete
    AddReg=RedSpiderService.ValueModify

    [RedSpiderService.ValueModify]
    HKLM,"SYSTEM\CurrentControlSet\Services\appcheck2","ImagePath",0,"C:\Windows\SysWOW64\rschck.exe"
    HKLM,"SYSTEM\CurrentControlSet\Services\checkapp2","ImagePath",0,"C:\Windows\SysWOW64\chekrs.exe"

    +

    然后你就可以用任务管理器终止两个通用组件,紧接着就可以终止红蜘蛛了!

    +

    由于本人目前对红蜘蛛知之甚少,可以看这篇文章了解更多!

    +

    学生机房管理助手——闻着臭吃着香

    +

    1. 不用逆向,能得到什么结论?

    +

    其实一开始我以为它和极域一样是基于C++/C开发的因此无法反编译,直到回家之后我自己下载了一个。杀毒软件报毒删除了set.exe,打开main.exe主入口程序时它突然弹出了一条C#式的通知框提示set.exe未找到。于是果断打开dnSpy开启后面的破解,反编译破解的内容将在后面涉及到。

    +

    首先看到他的文件目录↓

    +

    +

    其中zy文件夹中存放的是各种浏览器的exe可执行文件,猜测是覆盖现有的高版本浏览器,以便它操作注册表禁止各种功能。

    +

    有一定经验的同学想必会一眼看到可疑的yl.reg注册表文件,但是先别急着合并注册表。首先,你的机器可能已经被禁用了注册表和任务管理器;第二,这个文件里也不是你心心念念的破解注册表(虽然后面我们会利用它破解机房管理助手)。对于未知的事物,最好还是保持谨慎勿近的态度为好……

    +

    除此之外,一个名叫jfglzs.exe的程序吸引了我,根据我多年混迹于首拼梗圈的我一秒钟就反应过来,知道它就是“机房管理助手”的首拼。我们之后的破解也围绕着这个东西进行。

    +
    第一问 +任务管理器、注册表、组策略咋解
    +

    +

    本人Win11系统,正常情况下任务栏设置上端会有一个任务管理器选项。

    +

    如果你稍微懂一点高级知识,你也许会使用Win+R,并输入taskmgr试图使用任务管理器。然而这不可能奏效,因为你会接到一则提示:

    +

    +

    输入regedit(注册表)和gpedit.msc(组策略管理器)也是一样的道理。很少很少的高材生会使用mmc试图加载组策略,但是这样也不可能奏效。搜索资料发现,修改注册表的某些键值可以实现禁用组策略、注册表、任务管理器的功能。深度分析yl.reg时就会发现这些东西:

    +

    +

    第一行翻译过来就是:“禁用任务管理器”,它的值被设置成了1,也就是true。这一块还有禁止更改密码、禁止切换用户的设置等等。对于组策略,它的两个值则是存放在注册表:HKEY_CURRENT_USER\Software\Policies\Microsoft\MMC中的RestrictToPermittedSnapins;和它的子目录HKEY_CURRENT_USER\Software\Policies\Microsoft\MMC\{8FC0B734-A0E1-11D1-A7D30000F87571E3}中的Restrict_Run。如果不出意外,它们的值都是非零的,意味着组策略被禁用了。要想破解,我们就需要用一个不直接调用注册表的方式来添加/更改注册表值,这也就是下面将要提出的inf安装文件法。

    +

    INF安装文件的机制

    +

    提起绿色版软件,大家应该不会陌生,它省去了冗杂的dll等库文件,仅仅一个exe文件驱动整个程序。在绿色版软件安装时,有时就是用的inf文件安装法。一个可运行的inf文件包含几个项:

    +
    1
    2
    3
    [Version]
    Signature="$CHICAGO$"
    Provider=somebody
    +

    Version段包含inf文件的基本信息,其中Signature指定了文件的适用系统,常见的值有MSWindowsNT等,这里我们使用CHICAGO获得最广泛的支持(注意美元符号和引号的书写)。

    +
    1
    2
    3
    [DefaultInstall]
    DelReg=Delete
    AddReg=Add
    +

    这一段声明了安装时所需的函数,DelReg负责删除注册表,AddReg负责创建/修改注册表。基本语法如下:

    +

    DelReg[ROOT] [PATH] [NAME]ROOT就是注册表中HKEY开头的那些,你可以写全称,也可以写缩写形式(HK+后两个单词的首字母,HKEY_LOCAL_MACHINE=HKLM);PATH是包含指定键值的文件夹路径;NAME就是键值的名字。

    +

    AddReg[ROOT] [PATH] [NAME] [TYPE] [VALUE]TYPE指定了注册表值的类型(0相当于缺省,默认字符串;1DWORD值,设置十六进制值时只需两个数字一组,中间逗号分隔开,一定保证输入的十六进制为8位,一定记得写前导0!);VALUE即为键值,值为字符串时需要在前后打上半角双引号。

    +

    等号右侧的值相当于C++中的typedef,用来重命名函数,因此,在后续的安装代码中,我们的字段标识符都要与等号右侧的值相符才可,在我们的inf中,它表现为这样(inf文件的注释用分号表示):

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [Delete]
    HKCU,"Software\Policies\Microsoft\MMC","RestrictToPermittedSnapins"
    HKCU,"Software\Policies\Microsoft\MMC\{8FC0B734-A0E1-11D1-A7D30000F87571E3}","Restrict_Run"

    [Delete]
    HKCU,"Software\Microsoft\Windows\CurrentVersion\Policies\System","DisableRegistryTools"
    HKCU,"Software\Microsoft\Windows\CurrentVersion\Policies\System","DisableTaskMgr"
    HKCU,"Software\Microsoft\Windows\CurrentVersion\Policies\System","DisableChangePassword"
    HKCU,"Software\Microsoft\Windows\CurrentVersion\Policies\System","DisableCMD"

    [Delete]
    HKCU,"Software\Microsoft\Windows\CurrentVersion\Policies\System","DisableSwitchUserOption"
    HKCU,"Software\Microsoft\Windows\CurrentVersion\Policies\System","HideFastUserSwitching"
    +

    在记事本里编辑即可,记得保存为.inf文件,而后右键“安装”,或者在cmd里运行:InfDefaultInstall + inf文件地址(前提是你的cmd没被禁止)。

    +

    除此之外,我们发现了一些好玩的东西:yl.reg的最后几十行,将常用浏览器的起始界面通过注册表的方式修改成了它的官网,学有余力的娃们可以通过刚才介绍的AddReg函数把它的值改成你想要的值,在这里我换成了我精心制作的嘲讽页面:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    [Add]
    HKLM,"SOFTWARE\Policies\Microsoft\Internet Explorer\Main","Start Page",0,"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23"
    HKLM,"SOFTWARE\Microsoft\Internet Explorer\MAIN","Start Page",0,"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23"
    HKLM,"SOFTWARE\Microsoft\Internet Explorer\MAIN","First Home Page",0,"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23"
    HKLM,"SOFTWARE\Wow6432Node\Baidu\BaiduProtect\LockIEStartPage","Start Page",0,"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23"
    HKLM,"SOFTWARE\Wow6432Node\Software\Microsoft\Internet Explorer\Main","Start Page",0,"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23"
    HKLM,"SOFTWARE\Wow6432Node\Software\Microsoft\Internet Explorer\Main","Default_Page_URL",0,"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23"
    HKEY_USERS,".DEFAULT\Software\Microsoft\Internet Explorer\Main","Start Page",0,"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23"
    HKEY_USERS,".DEFAULT\Software\Microsoft\Internet Explorer\Main","First Home Page",0,"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23"
    HKEY_USERS,"S-1-5-18\Software\Microsoft\Internet Explorer\Main","Start Page",0,"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23"
    HKEY_USERS,"S-1-5-18\Software\Microsoft\Internet Explorer\Main","First Home Page",0,"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23"
    +

    yl.reg——队友坑害全队的典型例子。

    +

    当一切完成之后,你就可以自由使用任务管理器了,被锁定了cmd的同学们也可以尽情使用taskkill了!诶等等,事情好像有点不对劲……

    +
    第二问 我的taskkill去哪了
    +

    可是我的taskkill还好好地躺在System32文件夹里啊

    +

    机房管理助手一启动,所有使用taskkill的脚本/程序都会失效,属于是老阴B了。如果不逆向破解,我还真不清楚这是怎么做到的。总之你可以在网站上下载一个taskkill(对上网下载一个下来),或者顶住巨大的学习难度学习WinAPITerminateProcess函数)写出一个拔山盖世的C++程序来。这一节就不多赘述其他内容了……

    +
    第三问 yl.reg到底写了啥
    +

    其实最扎眼的就是它里面写的宣(补)战(贴)名单各种脱控工具箱,说实话那些工具箱软件我基本上一个都没见过……

    +

    这些注册表项有一个很普遍的特征,它们无一例外指向了注册表HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\safer\codeidentifiers\0\Hashes下很多以GUID形式命名的文件夹,那么这些文件夹具体起什么作用呢?

    +

    这其实是组策略管理器的黑名单,具体见此,没错,组策略可以限制指定软件的运行。但是很遗憾,这些配置全部存放在上述的注册表里面。你可以把注册表看做系统的配置文件,操作系统几乎所有配置信息、甚至包括大部分软件程序的配置都存放在注册表中。这么看来除了BIOS没别的安全地方了

    +

    如果想要禁用这些项,并不需要挨个将每个文件删去,而是看到他的其中一个父文件夹codeidentifiers。它里面有一个二进制值authenticodeenabled,它指定组策略黑名单的ID标识符,也就是codeidentifier文件夹下以数字命名的文件夹,只有当子文件夹的名称与ID标识符相同时才会启用该文件夹下的配置。因此我们釜底抽薪,直接更改authenticodeenabled的值:

    +
    1
    2
    [Add]
    HKLM,"SOFTWARE\Policies\Microsoft\Windows\safer\codeidentifiers","authenticodeenabled",1,00,11,45,14
    +

    假如我掏出逆向工具,阁下又该如何应对?

    +

    正如开头所说,学生机房管理助手由C#开发,因此可以用dnSpy反编译它的可执行文件,得到源码。那么我们就开始吧!

    +
    第一框 密码是啥
    +

    正如大多数软件那样,机房管理助手对它的源代码进行了一轮套壳,也就是代码混淆。为了让代码变成我们都容易看的形式。我们使用C#脱壳软件NET +Reactor Slayer进行反混淆(代码混淆工具为NET Reactor)。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    using System;
    using System.Security.Cryptography;
    using System.Text;
    using System.IO;

    public class Program
    {
    public static void Main()
    {
    // 更改这里的内容
    string string_3 = "12345678";
    // Class6.smethod_0()
    string value = "C:\\WINDOWS";
    string s = value.Substring(0, 8);
    string s2 = value.Substring(1, 8);
    DESCryptoServiceProvider descryptoServiceProvider = new DESCryptoServiceProvider();
    descryptoServiceProvider.Key = Encoding.UTF8.GetBytes(s);
    descryptoServiceProvider.IV = Encoding.UTF8.GetBytes(s2);
    MemoryStream memoryStream = new MemoryStream();
    CryptoStream cryptoStream = new CryptoStream(memoryStream, descryptoServiceProvider.CreateEncryptor(), CryptoStreamMode.Write);
    StreamWriter streamWriter = new StreamWriter(cryptoStream);
    streamWriter.Write(string_3);
    streamWriter.Flush();
    cryptoStream.FlushFinalBlock();
    memoryStream.Flush();
    string string_4 = Convert.ToBase64String(memoryStream.GetBuffer(), 0, checked((int)memoryStream.Length));
    // Class6.smethod_3()
    StringBuilder stringBuilder = new StringBuilder();
    for(int i = 0; i < string_4.Length; i++)
    stringBuilder.Append((char)(string_4[i] - 10));
    string_3 = stringBuilder.ToString();
    // Class6.smethod_2()
    MD5CryptoServiceProvider md5CryptoServiceProvider = new MD5CryptoServiceProvider();
    byte[] array2 = md5CryptoServiceProvider.ComputeHash(Encoding.Default.GetBytes(string_3));
    stringBuilder.Clear();
    for (int i = 0; i < array2.Length; i++)
    stringBuilder.Append(array2[i].ToString("x2"));
    string str = stringBuilder.ToString().Substring(10);

    Console.WriteLine(str);
    }
    }
    +

    同时,机房管理助手的密码MD5文件存放在注册表HKEY_CURRENT_USER\Software下的字符串值n里面。更改即生效!

    +

    代码环节

    +

    ClassX

    +

    使用方法:另存为.bat文件直接运行

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    @echo off

    >nul 2>&1 "%SYSTEMROOT%\System32\cacls.exe" "%SYSTEMROOT%\System32\config\system"


    if %errorlevel% == 0 (
    echo Admin Switched!
    ) else (
    echo Level Ascending... Restart

    powershell -command "Start-Process '%0' -Verb RunAs"
    exit
    )

    sc stop tdnetfilter
    sc delete tdnetfilter
    sc stop tdfilefilter
    sc delete tdfilefilter
    sc stop GATESRV
    sc delete GATESRV
    sc stop STUDSRV
    sc delete STUDSRV

    regedit /c /s usb_reg.reg
    echo Unhook through Regedit

    :a
    taskkill /f /t /im MasterHelper.exe
    taskkill /f /t /im ProcHelper64.exe
    TIMEOUT /T 1
    goto a
    +

    绿蜘蛛

    +

    使用方法:另存为.inf文件→右键安装;任务管理器先结束进程3000soft通用组件,再结束红蜘蛛软件

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    [Version]
    Signature="$CHICAGO$"
    Provider=justpureh2o@outlook.com, 2023

    [DefaultInstall]
    DelReg=Delete
    AddReg=RedSpiderService.ValueModify

    [RedSpiderService.ValueModify]
    HKLM,"SYSTEM\CurrentControlSet\Services\appcheck2","ImagePath",0,"C:\Windows\SysWOW64\rschck.exe"
    HKLM,"SYSTEM\CurrentControlSet\Services\checkapp2","ImagePath",0,"C:\Windows\SysWOW64\chekrs.exe"
    +

    学生机房管理助手通用破解

    +

    使用方法:另存为.inf文件→右键安装

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    [Version]
    Signature="$CHICAGO$"
    Provider=justpureh2o@outlook.com, 2023

    [DefaultInstall]
    DelReg=Delete
    AddReg=Add

    [Delete] ; 大坏蛋,放开那个组策略管理器!
    HKCU,"Software\Policies\Microsoft\MMC","RestrictToPermittedSnapins"
    HKCU,"Software\Policies\Microsoft\MMC\{8FC0B734-A0E1-11D1-A7D30000F87571E3}","Restrict_Run"

    [Delete] ; 注册表和任务管理器我来接手,你可以卷铺盖走人了!
    HKCU,"Software\Microsoft\Windows\CurrentVersion\Policies\System","DisableRegistryTools"
    HKCU,"Software\Microsoft\Windows\CurrentVersion\Policies\System","DisableTaskMgr"
    HKCU,"Software\Microsoft\Windows\CurrentVersion\Policies\System","DisableChangePassword" HKCU,"Software\Microsoft\Windows\CurrentVersion\Policies\System","DisableCMD"

    [Delete] ; 我就要切换用户!
    HKCU,"Software\Microsoft\Windows\CurrentVersion\Policies\System","DisableSwitchUserOption"
    HKCU,"Software\Microsoft\Windows\CurrentVersion\Policies\System","HideFastUserSwitching"

    [Delete] ; 如果把我桌面搞乱了张伟会清理掉我的文件滴
    HKCU,"Software\Microsoft\Windows\CurrentVersion\Explorer","DesktopProcess"

    [Add] ; 加点料才香~
    HKLM,"SOFTWARE\Policies\Microsoft\Windows\safer\codeidentifiers","authenticodeenabled",1,00,11,45,14
    HKLM,"Software\Microsoft\Windows\CurrentVersion\Policies\System","NoConfigPage",1,00,00,00,01
    HKLM,"Software\Microsoft\Windows\CurrentVersion\Policies\System","NoDevMgrPage",1,00,00,00,01

    [Add] ; 嘲讽一波这sb管理助手,关键你就算换成自己的网页学校的破网也加载不出来(笑)
    HKLM,"SOFTWARE\Policies\Microsoft\Internet Explorer\Main","Start Page",0,"https://justpureh2o.github.io/misc/"
    HKLM,"SOFTWARE\Microsoft\Internet Explorer\MAIN","Start Page",0,"https://justpureh2o.github.io/misc/"
    HKLM,"SOFTWARE\Microsoft\Internet Explorer\MAIN","First Home Page",0,"https://justpureh2o.github.io/misc/"
    HKLM,"SOFTWARE\Wow6432Node\Baidu\BaiduProtect\LockIEStartPage","Start Page",0,"https://justpureh2o.github.io/misc/"
    HKLM,"SOFTWARE\Wow6432Node\Software\Microsoft\Internet Explorer\Main","Start Page",0,"https://justpureh2o.github.io/misc/"
    HKLM,"SOFTWARE\Wow6432Node\Software\Microsoft\Internet Explorer\Main","Default_Page_URL",0,"https://justpureh2o.github.io/misc/"
    HKEY_USERS,".DEFAULT\Software\Microsoft\Internet Explorer\Main","Start Page",0,"https://justpureh2o.github.io/misc/"
    HKEY_USERS,".DEFAULT\Software\Microsoft\Internet Explorer\Main","First Home Page",0,"https://justpureh2o.github.io/misc/"
    HKEY_USERS,"S-1-5-18\Software\Microsoft\Internet Explorer\Main","Start Page",0,"https://justpureh2o.github.io/misc/"
    HKEY_USERS,"S-1-5-18\Software\Microsoft\Internet Explorer\Main","First Home Page",0,"https://justpureh2o.github.io/misc/"
    ; TODO 再给你多附赠几个浏览器hh
    HKCU,"Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppContainer\Storage\microsoft.microsoftedgedevtoolsclient_8wekyb3d8bbwe\MicrosoftEdgeMain","Start Page",0,"https://justpureh2o.github.io/2023/12/24/cracked-23-12-23" ; Edge 浏览器主页
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +
    + + +
    +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/number-theory-junior/index.html b/number-theory-junior/index.html new file mode 100644 index 0000000000..5a644e0780 --- /dev/null +++ b/number-theory-junior/index.html @@ -0,0 +1,4902 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 信竞初等数论导论 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + + + + + + +
    +
    +

    +

    引入

    +

    如果说数论是数学体系中专门用来研究数字性质的一个分支,那么初等数论则是对整数的性质进行系统性的探讨与研究。千万不要因为其中的“初等”二字小瞧这初等数论尽管名称和学习难度上都没有高等数论那么有逼格,就像初等数学之于高数,数论的所有内容均筑基于此。其中欧几里得证明的算数基本定理(一切合数都可被分解为有限个质数的乘积)在质数筛、GCD(以及LCA)计算、无理数证明等问题上均有用武之地。可以说高等数论奠基于初等数论。它同时也是初学者接触数论的必经之路。

    +

    Part1.  前置知识

    +

    Div1. 数论有关定理

    +

    算术基本定理:每一个合数都可以被分解为有限个质数的乘积。即对于任意合数,都存在:

    +

    ,其中为质数。

    +

    推论一:正整数的正因数集合为:

    +

    +

    推论二:正整数的正因数个数为:

    +

    推论三:正整数的所有正因数之和为

    +

    +

    质数分布定理:区间中,当时,质数个数

    +

    费马小定理:是一个质数,则为同余符号)。

    +

    欧拉定理(费马小定理扩展):互质),则有,其中为欧拉函数。

    +

    Div2. 同余

    +

    同余,顾名思义,两个数分别除以一个正整数后得到相同的余数。即。但是它的定义给出了这样一句话:“对于正整数,若能被整除),则称对模同余,记作。当然以上两种说法是等价的。

    +

    同余具有以下三种基本性质:

    +
      +
    1. 反身性:对于任何正整数
    2. +
    3. 对称性:即对于,有
    4. +
    5. 传递性:若,且,有
    6. +
    +

    当然,它可以延申到计算机的模运算(毕竟出现了)。模运算有三种基本运算:

    +
      +
    1. 加运算:
    2. +
    3. 减运算:
    4. +
    5. 乘运算:
    6. +
    +

    还有两个推论:

    +
      +
    1. 幂运算:
    2. +
    3. 求和运算:
    4. +
    +

    同余消去原则:

    +
    +

    若同余号两端的项相等,且都与模互质,则可以同时消去

    +
    +

    举例:,如果,则

    +

    Part2.  质数

    +

    质数的判断:除了它自身以及以外,不存在其他正整数使得

    +

    Div1.  质数判断

    +

    试除法: +这是三种方法中,唯一一种能做到100%正确的质数判断方法。对于给定数,遍历所有间的正整数,若出现则证明它不是质数,因为质数只能被1以及它本身整除

    +
    1
    2
    3
    4
    5
    6
    bool isPrime(int n) {
    for (int i = 2; i * i <= n; i++) {
    if (n % i == 0) return false;
    }
    return true;
    }
    +

    复杂度:

    +

    适用范围:普及、提高

    +

    试除法の大胜利!

    +

    费马素性检验: +是上述费马小定理的实际运用,它与常规算法思想有所不同:它主张在中随机选取一个数。若出现与费马小定理不符的情况,那么一定为合数;若每次均符合定理,称为 +费马伪素数 ,因为它很大概率是一个质数。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    bool isPrime(int n) {
    if (n <= 2) return false;
    int k = 10;
    while (k--) {
    srand(time(0));
    int a = rand() % (n - 2) + 2;
    if (__gcd(a, n) != 1) return false;
    if (qpow(a, n - 1, n) != 1) return false;
    }
    return true;
    }
    +

    复杂度:,其中为随机数检验次数,是因为使用了快速幂算法。

    +

    适用范围:提高T2及以下(慎用)

    +

    为什么用该方法判断的质数 大概率 +是个质数呢?不妨测试一下561(3)、1105(5)、1729(7)(括号内为它的最小因子),你会发现函数的返回值均为true,即都为质数。可见这个算法不是100%正确的,这些“漏网之鱼”被称为“Carmichael数”。它们极其罕见,一亿范围内仅255个。也因如此,你可以通过打表特判的方式抠掉这些特例(你保证记得住就行)。2016年中国物流工人余建春给出了一个Carmichael数的判断准则,这个标准目前在国际上得到了广泛认同。

    +

    对于优化,你可以在函数起始点加入类似于if (n % 2 == 0 || n % 3 == 0) return false;的特判,进一步降低复杂度。

    +

    Miller-Rabin算法: +该算法同样无法保证结果100%准确,慎用!

    +

    MB算法实质上是对费马素性检验算法的效率和准确度优化。算法流程如下:

    +
      +
    1. 分解为的形式,其中为奇数
    2. +
    3. 中选取整数,称为“基数”
    4. +
    5. 计算的值,若结果为,则可能为质数,继续检验
    6. +
    7. 若结果不等于,计算……的值,若结果等于,则可能为质数,继续检验
    8. +
    9. 若都不等于,则一定是合数。称为强费马证据
    10. +
    +

    当然,它同样有特例,称为强伪质数,如2047(23)、3277(29)、4033(39)等(括号内为它的最小因子)。

    +

    Div2.  质数筛

    +

    常见的质数筛法有:试除法、埃氏筛、线性筛。

    +

    试除法:从质数定义出发,即存在一个正整数,对于任意间的正整数,总有成立。代码实现只需枚举间所有正整数,并让对其取余。若取模运算出现则代表它不为质数,没有出现则为质数。

    +
    1
    2
    3
    4
    5
    6
    bool isPrime(int n) {
    for (int i = 2; i * i <= n; i++) {
    if (n % i == 0) return false;
    }
    return true;
    }
    +

    复杂度:

    +

    适用范围:普及T2及以下

    +

    这里所展示的试除法代码实际上经过一轮优化。若严格根据质数定义,第二行的循环上限应为。考虑到如下性质:,若,则一定有。因此可以将循环上限压缩至

    +

    埃氏筛:全称叫埃拉托斯特尼筛法,老哥生活在2200年前的古希腊,不借助望远镜就计算出了地球的周长(与真实值偏差仅0.96%)、同时他也是第一位根据经纬线绘制出世界地图的人、也是最先提出将地球根据南北回归线分为“五带”的大人物。他提出的筛法核心思想如下:

    +

    第一步:列出从2开始的一列连续数字;第二步:选出第一个质数(本例中为2),将该质数标记,将数列中它的的所有倍数划去;第三步:若数列中的末项小于它前一项的平方,则质数已全部筛出;否则返回第二步

    +
    1
    2
    3
    4
    5
    6
    7
    8
    void get(int n) {
    for (int i = 2; i <= n; i++) {
    if (!vis[i]) {
    prime[cnt++] = i;
    }
    for (int j = 2; i * j <= n; j ++) vis[i * j] = true;
    }
    }
    +

    其中,prime数组存储质数,vis数组用于标记(即上文中“划去数字”),变量cnt则存储中质数的个数。

    +

    复杂度:

    +

    适用范围:普及T2及以下

    +

    但是继续观察算法发现:我们其实无需将所有的倍数删去,只需删去前一步得出的质数的所有倍数即可。 +这与前文介绍的埃氏法核心相符。因此将循环迁移至条件判断中即可:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    void get(int n) {
    for (int i = 2; i <= n; i++) {
    if (!vis[i]) {
    prime[cnt++] = i;
    for (int j = i + i; j <= n; j += i) vis[j] = true;
    }
    }
    }
    +

    优化复杂度:

    +

    适用范围:普及T3及以下

    +

    线性筛/欧拉筛:实质是埃氏筛的线性优化。因为在埃氏筛中,有些数字被重复筛了多次(例如30会被2、3、5筛到)。本着线性优化的原则,我们需要找到一个方法,使得每个合数仅被筛选一次。主要思想如下:

    +

    我们发现,线性筛和埃氏筛均使用了质数的倍为合数的结论。我们只需要保证每一个数仅被它自身的最小质因数筛出即可。即对于数字是一个合数,且只会被筛出。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void get(int n) {
    for (int i = 2; i <= n; i++) {
    if (!vis[i]) prime[cnt++] = j;
    for (int j = 1; prime[j] <= n / i; j++) {
    vis[prime[j] * i] = true;
    if (i % prime[j] == 0) break;
    }
    }
    }
    +

    复杂度:

    +

    适用范围:普及、提高

    +
    +

    例题:

    +
      +
    1. P5736 +【深基7.例2】质数筛
    2. +
    3. P5723 +【深基4.例13】质数口袋
    4. +
    +

    Part3.  因数

    +

    因数定义: 对于一个数,若存在一个正整数使得,则称的因数。

    +

    Div1.  因数分解法

    +

    试除法:万能暴力解法。即遍历间的所有数,若可以整除,则均为的因数。特殊情况:为整数时,因数仅有本身,因此需特判。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    vector<int> get(int n) {
    vector<int> ret;
    for (int i = 2; i * i <= n; i++) {
    if (n % i == 0) {
    ret.push_back(i);
    ret.push_back(n / i);
    }
    if (n % (i * i) == 0) ret.pop_back();
    }
    sort(ret.begin(), ret.end());
    return ret;
    }
    +

    复杂度:

    +

    适用范围:普及T1

    +

    Div2.最大公约数

    +

    辗转相除法: +又是我们大名鼎鼎的欧几里得老先生提出的一套公约数算法,整个算极其简洁:核心只有一行,即:

    +
    +

    两个数的最大公约数等于其中较小的数字和二者之间余数的最大公约数

    +
    +

    可以写出:

    +
    1
    2
    3
    int gcd(int a, int b) {
    return b ? gcd(a, a % b) : a;
    }
    +

    但是为什么呢?我们可以通过以下方法证明:

    +

    假设如下关系:。其中被除数,除数,商,余数。则

    +

    首先证明充分性:令,即二者有相同因子

    +

    代入初始除法算式得:

    +

    接着由于加减乘法的封闭性,即一个整数进行加减乘运算得到的结果同样是一个整数。可以得出:。即)与有共同因子。

    +

    接下来证必要性。令

    +

    Stein算法: +上一个方法的明显缺点在于,它处理大质数的效率并不好(但总体来说是很好的),因为它使用了取余运算,这会减慢一些速度。可以理解,生在2000多年前——一个没有电脑和OI的古希腊社会,这个算法已经足够兼顾常规效率和手推难度了。但是步入21世纪,加快的生活节奏毒瘤数据使得人们对更快算法的需求空前高涨。Stein算法便应运而生。

    +

    算法流程如下:

    +
      +
    1. 任意给定两个正整数,先判断它们是否都是偶数,若是,则用2约简,若不是,则执行第二步。
    2. +
    3. 若两数是一奇一偶,则偶数除以2,直至两数都成为奇数。再以较大的数减较小的数,接着取所得的差与较小的数,若两数一奇一偶,仍然偶数除以2,直至两数都成为奇数。再次以大数减小数。不断重复这个操作,直到所得的减数和差相等为止。
    4. +
    5. 两数相等时,第一步中约掉的若干个2与第二步中最终的等数的乘积就是所求的最大公约数。
    6. +
    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    int gcd(int a, int b) {
    int p = 0, t;
    if (!(1 & a) && !(1 & b)) {
    a >>= 1;
    b >>= 1;
    p++;
    }
    while (!(1 & a)) a >>= 1;
    while (!(1 & b)) b >>= 1;
    if (a < b) {
    t = a;
    a = b;
    b = t;
    }
    while (a = ((a - b) >> 1)) {
    while (!(1 & a)) a >>= 1;
    if (a < b) {
    t = a;
    a = b;
    b = t;
    }
    }
    return b << p;
    }
    +

    这个算法的优点在于:它大大优化了大质数的运算。但可惜的是,它的代码量膨胀了8倍,因此不太建议赛时使用。毕竟C++都给你内置了__gcd()函数嘛,干嘛不偷个懒?

    +

    Div3. 最小公倍数

    +

    我们可以简单概括成一句话:

    +
    +

    两个数的最小公倍数等于这两个数的乘积与这两个数最大公约数的商

    +
    +

    即:

    +

    凭啥呀?

    +

    我们假设两个数有最大公约数,则,且。并且一定互质(若不互质,的最大公约数就不会是,而是一个比大的值)。

    +

    由乘法交换律,可知:

    +

    消去得:。因为互质,所以或者即为两个数的最小公倍数。得证。

    +
    +

    例题:

    +
      +
    1. P1075 [NOIP2012 +普及组] 质因数分解
    2. +
    3. P2424 约数和 +(需要逆向思维)
    4. +
    +

    Part4. 欧拉函数相关

    +

    Div1. 欧拉函数推导

    +

    问:论牧师欧拉有多么的高产

    +

    答:平均每年800页数学论文你说高不高产嘛

    +

    欧拉函数,记作。表示中与互质的数的个数,即,满足的总个数即为的值。举个例子,,因为在中,均与互质。特殊地,

    +

    欧拉函数有如下计算公式:若可被表示为(算术基本定理分解式)的形式,则

    +

    推导思想即为用减去所有中所有与不互质的数。在计算机上实现,首先需要分解质因数。思路如下:首先抛出第一个质因数,那么将中所有的的倍数删去,因而可以保证筛出的数一定是的质因子,否则他们将存在最大公约数。那么能被整除的数的个数(也就是以内的倍数个数)为——其中的中括号代表整除。

    +

    因此我们离解出欧拉函数就进了一步了,我们的过渡式子就是

    +

    好耶

    +

    别急着好耶,我们可以发现一个小小的推导谬误(可能并不是很容易发现)。当我们用去筛数时,使用的算式仍然是。对于形如的数,会被重复筛去多次,导致多减,最终结果会小于。有些抽象,我们来看这张图:

    +
    +容斥原理 + +
    +

    易知中可被整除的数字共有个,能被整除的数字共有个。但是如果说能被整除的数字共有个,显然不合常理,因为都既能被整除,也能被整除,如果不加排除,他们将会被减去2次。因此需要补偿损失,正确的计算方法是(仅计算能被整除的数的总个数):

    +
      +
    • 能被整除的:
    • +
    • 能被整除的:
    • +
    • 同时被整除的:
    • +
    • 总个数:个(就是被绿圈和橙圈捆住的的数的个数)
    • +
    +

    那么对于整除问题,中间的被重复加了3次,需减去两次平衡收支。此即容斥原理的简单思想表示。

    +

    回到欧拉函数推导上来:过渡公式中的容斥问题可以解决一部分了。对于可同时被两个不同质数整除的数(例如),我们加上它的总个数。 +得到

    +

    当然这又有一个小问题没完没了了是不是?对于的公倍数,会被先减去3次,然后被上一步的操作加上3次,总体不加不减。还是回到上图:中间的会被每个颜色的圈先减去一次、共3次,上一步的补偿操作,可以看作又被橙绿圈(橙圈和绿圈的交集)、蓝绿圈、蓝橙圈一共加上了3次。减3次加3次相当于没动,为了让它被算上,我们需要加上它,对于则是全部减去(因为括号外有减号需要变号,不要忘记是由一系列不合规的数字个数相减得来的)。得到我们的过渡态3:

    +

    又是如上的容斥判断,这里我们省去讨论。将最终的产物合并得到:!(我不会合并,但是你可以把括号拆开看看是不是上述形式。总之,欧拉牛逼!)

    +

    ,好耶!终于可以好耶了……

    +

    Div2. 欧拉函数代码实现

    +

    主要是如果压成一个Div会非常的长,因此这里新开一个Div2

    +

    我们明确了欧拉函数的推导,接下来就是整理思路写代码的时间了!我们也只需跟着原始思路走就可以了。再次回忆一下:首先我们需要筛出质因数,除去它的所有倍数,再用公式代入就可以了。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    long long eular(int n) {
    long long res = n;
    for (int i = 2; i * i <= n; i++) {
    if (n % i == 0) {
    res = res * (i - 1) / i;
    while (n % i == 0) n /= i;
    }
    }
    if (n > 1) res = res * (n - 1) / n;
    return res;
    }
    +

    时间复杂度:

    +

    适用范围:All Clear

    +

    Div3. 欧拉函数推论

    +
    +
      +
    1. 为质数,则
    2. +
    +
    +

    让我们回到欧拉函数的定义上去:中与互质的数的个数(特殊地,)。那么对于这个质数,有多少数与它互质呢?

    +

    很显然,答案是个!因为的质因子只有本身,若不止一个质因子,很显然它不是一个质数。因此

    +
    +
      +
    1. 假设是一个质数,(或),且的值已知,那么
    2. +
    +
    +

    凭啥呀?

    +

    因为已经是一个质数,换句话说:在这个条件下的一个质因子。在计算时,就已经作为一个质因子以的形式乘进去了。此时可以写作

    +

    +

    那么函数值多乘了一个

    +

    +

    我们发现:(2)式中包含了(1)式,只是头上乘以了。因而得到

    +
    +
      +
    1. 假设是一个质数,(或),且的值已知,那么
    2. +
    +
    +

    这东西长得和性质2很相似,唯一不同的是不再是的一个质因子了。但是变成了的质因子。因此我们计算的值时,不仅需要在头部乘上,而且还需要将乘进去:

    +

    +

    因为,所以得到性质3,即

    +

    这三个性质将作为重点性质出现在欧拉函数筛法中。

    +

    Div4. 欧拉函数线性筛

    +

    我们已经接触了简单的欧拉函数计算方法,那么又该如何解决形如:“给定一个正整数,求的值”的问题呢?

    +

    考虑继续使用上面的朴素算法,时间复杂度将会是。明显无法满足需求,更何况,每个数与每个数之间的值之间有一种推导关系,使得我们无需每次重新计算值,而是用已经求出的来线性推出的值。

    +

    欧拉函数涉及到质因子的拆分,我们又需要在线性时间内求各种质数。自然而然想到了先前所学的线性筛:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    int primes[N];
    bool st[N];
    int cnt = 0;

    void sieve(int n) {
    for (int i = 2; i <= n; i++) {
    if (!st[i]) primes[++cnt] = i;
    for (int j = 1; primes[j] * i <= n; j++) {
    st[primes[j] * i] = true;
    if (i % primes[j] == 0) break;
    }
    }
    }
    +

    我们运用这段代码可以得出范围内所有的质数,用st[N]数组可以筛出所有的合数。也就是说对于筛出的合数,我们能够得知组成它的质因子是什么,比如st[primes[j]*i]=true;这一行代码。接着套用上述三种性质,我们可以得出值。

    +

    此时我们就需要新建一个phi[N]数组来存储每个数的值,并且在代码中三个地方加入对于三种性质的公式:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    typedef long long ll;

    ll primes[N];
    bool st[N];
    int cnt = 0;
    ll phi[N];

    void phi_sieve(int n) {
    for (int i = 2; i <= n; i++) {
    if (!st[i]) {
    primes[++cnt] = i;
    phi[i] = i - 1;
    }
    for (int j = 1; primes[j] * i <= n; j++) {
    st[primes[j] * i] = true;
    if (i % primes[j] == 0) {
    phi[primes[j] * i] = phi[i] * primes[j];
    break;
    }
    phi[primes[j] * i] = phi[i] * (primes[j] - 1);
    }
    }
    }
    +

    没错我开了long long防止爆int

    +

    时间复杂度:

    +

    适用范围:普及&提高

    +

    对于开头提出的求和问题,遍历phi[1]phi[n]的所有值求和即可。

    +

    Div5. 欧拉定理

    +
    +

    若正整数互质,则有

    +
    +

    对于它的证明,百度百科中如此写到:

    +
    +

    的缩系,故也为的缩系。有

    +
    +

    通俗来讲就是这样:

    +
      +
    1. 中取所有与互质的数,很容易知道这样的共有个(根据欧拉函数定义得来)。它们都与互质。
    2. +
    3. 给这列数同时乘上,得到。它们也都和互质,并且各不相同。
    4. +
    5. 提出括号里乘了次的,得到以下关系式:
    6. +
    7. 那么根据同余号两端的消去原则(左右两端两个项相同且与模互质),可以消去。得到,欧拉定理得证。
    8. +
    9. 特殊地,如果是一个质数,有。这被称作费马小定理(先前的费马素性检验就是基于这个原理编写的)。
    10. +
    +

    真不知道明明可以写得通俗点为什么非得省那点空间写看起来那么高深莫测的专业术语,真的是只写给自己看的。

    +

    Div6. 降幂算法

    +

    尤其对于绿题以上的题目,题面中可能出现“答案可能很大,请对大质数取余”的字样。这意味着题目可能涉及到大规模的幂运算,需要我们用简便的方法计算幂。对于一般的题目,我们使用快速幂。

    +

    快速幂:快速幂思想如下:

    +

    +

    我们将指数分解为若干的和(二进制表示),例如:,因为。因而不必将连续乘11次,效率大幅提升。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    typedef long long ll;

    int qpow(int a, int k, int p) {
    int res = 1;
    while (k) {
    if (k & 1) res = (ll) res * a % p;
    a = a * a % p;
    k >>= 1;
    }
    return res;
    }
    +

    时间复杂度:

    +

    适用范围:基本All Clear

    +

    欧拉降幂:上面方法一个缺点在于无法处理过大的指数,在处理类似于的计算时将会疯狂掉san。接下来介绍一种使用上面讲到的欧拉定理来解决大指数幂运算的方法。

    +

    欧拉降幂核心公式:(又称 +扩展欧拉定理

    +

    也就是说:我们只需要算出的值,再用快速幂算法,将作为新指数带入计算即可。当然,这里的可能会爆long long,因此可以选择使用字符串进行高精度计算。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    typedef long long ll;

    ll primes[N];
    bool st[N];
    int cnt = 0;

    int qpow(int a, int k, int p) {
    int res = 1;
    while (k) {
    if (k & 1) res = (ll) res * a % p;
    a = a * a % p;
    k >>= 1;
    }
    return res;
    }

    ll eular(int n) {
    ll res = 0;
    for (int i = 2; i <= n; i++) {
    if (!st[i]) {
    primes[++cnt] = i;
    res = res * (i - 1) / i;
    while (n % i == 0) n /= i;
    }
    for (int j = 1; i * primes[j] <= n; j++) {
    st[i * primes[j]] = true;
    if (i % primes[j] == 0) break;
    }
    }
    if (n > 1) res = res * (n - 1) / n;
    return res;
    }

    int edp(int a, string k, int p) {
    ll phi = eular(p);
    int drop = 0;
    for (int i = 0; i < k.length(); i++) {
    drop *= 10;
    drop += k[i] % phi;
    }
    drop += phi;
    return qpow(a, drop, p);
    }
    +

    其中eular(int n)函数用于计算欧拉函数的值、edp(int a, string k, int p)用于计算降幂后的指数、qpow(int a, int k, int p)是快速幂算法。

    +

    时间复杂度:

    +

    适用范围:所有

    +

    扩展欧拉定理可谓是欧拉定理的一般形式,它的定义如下:对于任意正整数,满足:

    +$a^k + +

    $

    +

    其中第二个式子就是欧拉降幂的核心公式。

    +

    扩展欧拉定理的证明见这里因为太复杂了我不会证

    +
    +

    例题:

    +
      +
    1. P2158 [SDOI2008] +仪仗队 (欧拉函数板子)
    2. +
    3. P1447 [NOI2010] +能量采集(上一个问题的变式)
    4. +
    5. P1226 [模板] +快速幂
    6. +
    7. P5091 [模板] +扩展欧拉定理 (欧拉降幂)
    8. +
    9. P4139 +上帝与集合的正确用法 (欧拉降幂+递归)
    10. +
    +

    Part5. 同余方程的解法

    +

    这里会涉及到一元线性同余方程,一元线性同余方程组和高次同余方程的算法解法。

    +

    Div.1 裴蜀定理

    +

    很多人会把他读成裴除(chú)(比如我的某位好友),这个名词正确的读法是裴蜀(shǔ)。或者可以直接改称作“贝祖定理”,它的提出者艾蒂安·裴蜀估计怎么也没想到后人居然连他的名字都读不对(想想如果这种事情发生到你身上会怎么样)。你也可以读他名字的法语发音(显得你很优雅且有文化)。

    +

    切入正题,裴蜀定理表述为:对于任意正整数,总有整数,使得,其中等价于,是数论中最大公约数的表述方式。

    +

    首先可以知道,因为都具有约数,让他们分别乘上另两个数并不会改变这一约数。所以假设,有。在这里,

    +

    Div2. 扩展欧几里得(EXGCD)

    +

    加了“扩展”二字是不是感觉逼格上来了?

    +

    扩展欧几里得算法用于求出线性同余方程的解。线性同余方程,即形如的方程,我们需要求出的值。

    +

    回忆一下欧几里得算法的核心思路:

    +

    再看看刚刚讲到的裴蜀定理,发现。根据余数的定义,有:

    +

    那么我们的任务就是求出这里的值,因此拆开括号,整理出的系数:。观察裴蜀定理的形式:,我们得出的式子中,变成了。因此每次递归时需要将的值减去

    +

    既然我们设计的是一个递归算法,我们就必须明确它的递归出口。根据欧几里得算法,当时,。我们把代入发现:,得到,此时可取任意整数值,。这里我所取的解是

    +

    最后,因为这本质上还是一个欧几里得算法,所以返回是有必要的(事实上exgcd算法返回的将作为推导式中的参与运算)。我们可以写出如下函数。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int exgcd(int a, int b, int &x, int &y) {
    if (!b) {
    x = 1;
    y = 0;
    return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
    }
    +

    时间复杂度:

    +

    但是,题目中一般不会给出裴蜀定理那样的形式,而是形如的形式,让你求出的值,并且上述方法仅求出了一元线性同余方程的一组特解,如果题目中让你求出最小正整数解呢?接下来就是解决上述问题的方法:

    +

    1. 同余—等式互转(自己起的名字):

    +

    在上面的介绍中,我们遇到了一个问题:如何将这样的同余式变为这样的二元一次不定方程的裴蜀定理形式呢?

    +

    考虑到同余方程的定义(或者你可以把以下关系死记住),得到。接着由余数定义,得到,移项得到:。提出负号,令,则。它有解的充要条件是。经过如上变换后就变成了裴蜀定理的形式,可以直接用exgcd求解

    +

    2. 最值解问题

    +

    二元一次不定方程通解的证明

    +

    Div3. 中国剩余定理(CRT)

    +

    又称孙子定理(但我认为还是中国剩余定理听起来更有实力一些),最早见于《孙子算经》中“物不知数”问题,首次提出了有关一元线性同余方程的问题与解法。

    +

    对于一元线性同余方程:,可以构造以下方法求出通解。

    +

    首先,令

    +

    然后,令,即除了外所有的乘积。

    +

    接着,令在模意义下的逆元,即

    +

    所以,的通解为:

    +

    Div4. Baby Step Giant +Step算法(BSGS)

    +

    这个算法用于解决一元高次同余方程问题,模意义下的对数也可以求。又称“北上广深算法”(想出这种名字的人真是人才)

    +

    高次同余方程长成这个样子:

    +

    +

    发现跑到了指数上边真是变态呢。这种问题显然没公式解,于是苦恼的人们只得选择一条略显暴力的求解道路,即搜索。严格来说,BSGS所使用的是双搜索,其中的一个变量的搜索步长会长于另一个变量的搜索步长,因而得名“大步小步算法”。或者叫北上广深/拔山盖世算法!

    +

    朴素BSGS互质):不妨令,原式为。根据消去原则,两边同乘

    +

    接下来我们对同余号右侧的部分求值,再任命一个固定的值,使得左侧模的值等于右侧模的值。为了快速比对左右侧的值,我们选择将右侧预先计算出来的值存入一个哈希表中,让(键为,对应值为)。接着就是选择值,计算并比对了。

    +

    关于哈希表冲突,我们希望找到的最小值,因而需要尽可能大。每次冲突即代表一个更大的值被发现了。因此无需处理冲突问题。

    +

    对于的选择。可以发现个可能的取值,个。时最佳。因此代码就可以写出来了。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    ll bsgs(ll a, ll b, ll m) {
    unordered_map<ll, ll> hash;
    ll bs = 1;
    int t = sqrt(m) + 1;
    for (int B = 1; B <= t; B++) {
    bs *= a;
    bs %= m;
    hash[b * bs % m] = B;
    }
    ll gs = bs;
    for (int A = 1; A <= t; A++) {
    auto iter = hash.find(gs);
    if (iter != hash.end()) return A * t - it->second;
    gs *= bs;
    gs %= m;
    }
    return -1;
    }
    +

    时间复杂度:

    +

    扩展BSGS不互质):

    +
    +

    例题:

    +
      +
    1. P1082 [NOIP2012 +提高组] 同余方程 (exgcd)
    2. +
    3. P5656 [模板] +二元一次不定方程 (exgcd)
    4. +
    5. P1495 [模板] +中国剩余定理(CRT)/ 曹冲养猪
    6. +
    7. P1516 +青蛙的约会 (CRT+exgcd)
    8. +
    9. P3846 [TJOI2007] +可爱的质数/ [模板] BSGS
    10. +
    11. P2485 [SDOI2011] +计算器 (欧拉降幂+乘法逆元+BSGS)
    12. +
    13. P3306 [SDOI2013] +随机数生成器 (等比数列推导+BSGS)
    14. +
    15. P4195 [模板] 扩展 +BSGS/exBSGS
    16. +
    +

    Part6. 乘法逆元

    +

    乘法逆元定义如下(注意和矩阵求逆不是一个东西):

    +
    +

    ,且互质,则在模条件下的乘法逆元,记作

    +
    +

    简单来说乘法逆元就是模意义下的的倒数。

    +

    费马小定理求逆元:大部分题目会给出一个质数模数,因而互质是可以保证的。此时我们的乘法逆元就是使式子成立的值,考虑到模数为质数,可以带回开头所说的费马小定理中。

    +

    得到,由于互质,消去得:,所以乘法逆元为

    +
    1
    2
    3
    int inv(int a, int p) {
    return qpow(a, p - 2, p);
    }
    +

    扩展欧几里得求逆元:这是万能的方法,对任意模数均成立。它不像上面费马小定理那样限制模数必须是质数,因而只要时间充裕,都建议使用这种求逆元的方式。

    +

    因为,运用同余-等式互转可以得到。符合exgcd的形式。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    int exgcd(int a, int b, int &x, int &y) {
    if (!b) {
    x = 1;
    y = 0;
    return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
    }

    int inv(int a, int m) {
    int x, y;
    exgcd(a, m, x, y);
    return (x + m) % m;
    }
    +

    递推求逆元

    +
    +

    例题:

    +
      +
    1. P3811 [模板] +模意义下的乘法逆元 (递推求逆元)
    2. +
    +

    来张弔图

    +

    +

    Part7. 矩阵相关

    +

    矩阵,是一个按照长方排列的实数或复数集合。它最早用来表示方程组中的系数和常数,简单理解就是它将元一次方程组中的系数,按照未知数的顺序依次挑出它们的系数组合为矩阵的某一行。元一次方程的矩阵有列,而行数则取决于方程组中方程的个数。

    +

    Div1. 初等行变换

    +

    考虑这个方程组:

    +

    +

    按照如上所述,将它转换为系数矩阵(只有的系数)就是:

    +

    +

    你也可以写成增广矩阵(与系数矩阵相比多了一列常数,即等号右边的常数,这里用竖线隔开)的形式:

    +

    +

    不难看出第一列代表了的系数,第二列和第三列是的系数。那么如果需要求解这个矩阵(得到方程组的解),我们应该通过初等行变换将它变成方便我们求解的模式。初等行变换内容如下(最好用方程组消元的思想简化理解):

    +
      +
    1. 交换某两行
    2. +
    3. 把矩阵的某一行同乘以一个非零的数
    4. +
    5. 把某行的若干倍加和到另一行
    6. +
    +

    假设我们有一个元线性方程组,如何设计算法使计算机能够快速求出它的解呢。我们需要引入三角矩阵的概念:

    +

    顾名思义,系数排列看起来像一个三角形的矩阵,叫做三角矩阵。分为上三角矩阵和下三角矩阵。前者的非零系数均分布在对角线的右上方、后者都在左下方,例如矩阵:就是一个上三角矩阵(这里是增广矩阵)。通常用字母表示,求解线性方程组时经常化为这种形式方便求解:本例中当最后一个未知数(见最后一行)已知时,可以通过向上代入求解每一行中待求的未知数值。

    +

    那么如何将一个一般矩阵转换为上三角矩阵呢?答案是前面介绍过的初等行变换!步骤如下:

    +
      +
    1. 枚举每一列,选出无序组中第列系数绝对值最大的一行,并移到无序组的最上边。
    2. +
    3. 行通过自乘,将第列的系数变成,并标记为有序。
    4. +
    5. 通过加减有序组中某一行的非零倍,将之后所有行的第列系数化为
    6. +
    +

    文字还是太抽象,我们来举个例子:

    +

    令矩阵(有序组用绿色表示)

    +

    枚举第一列,。开始时,所有行均无序。选出绝对值最大的那一项,本例中为第二行,进行移动,原矩阵变为:

    +

    +

    第二步,自乘并标记有序,因此第一行除以,原矩阵就变成了:

    +

    +

    第三步,将无序组的第列消成。本例中,我们让第二行减去二倍第一行;第三行直接减去第一行,得到:

    +

    +

    枚举第二列,此时。第一步,选出第二列系数绝对值最大的那一行,移到无序组最上端。本例中无需移动,自乘,标记有序,原矩阵为:

    +

    +

    最终的最终,第三行减倍第二行,得到我们心心念念的上三角矩阵:

    +

    +

    我们假设从左到右,分别为的系数,竖线右侧为常数。矩阵可以改写成方程组的形式:

    +

    +

    根据最后一行,显然。将代入2式,解得,以此类推,由下向上代入解出的值即可,本例的唯一解是:

    +

    然而心细的你估计发现了疏漏之处:“求一元二次方程时都要先检验根是否存在(判别式法)再来作答,你这里怎么没有讨论根的分布情况呢?”

    +

    事实上,矩阵的解的分布确实不止一种情况,这里是矩阵有唯一解的情况。类比高中立体几何求平面法向量的情景,我们通常都要令某个坐标为或者是其他方便于计算的值,这里就是矩阵有无数组解的经典例子。要想系统分析矩阵方程解的数量情况,我们需要引入的概念。

    +

    Div2. 秩

    +

    在上一节中我们通过初等行变换求出了矩阵的解,然而并不是所有矩阵都能轻而易举求出唯一解,因为它可能无解、也有可能无唯一解(默认最高次数为一)。类比一元二次方程中的判别式法,矩阵是否也有判断根存在性的方法?

    +

    答案是:有滴!在矩阵运算中,我们使用来描述矩阵的一些关于解的个数的关系。秩被定义为:将矩阵通过初等行变换后形成的梯形矩阵中非零行的个数。试看如下例子:

    +

    定义一个的矩阵:

    +

    经过初等行变换后出现了这样的情况:

    +

    (第二行减去乘3的第一行,第一行乘2减去第三行)

    +

    第二行变成了纯的一行,一、三行说什么都无法消成一个未知数的形式。如果写成方程组就是:

    +

    +

    它有无数组解,原因是:矩阵的秩与矩阵增广矩阵的秩相等且小于了它的阶。简单来说就是你用两个方程去求三个未知数的值(初一内容),当然是有无数多组解。

    +

    规定对于矩阵,它的秩用表示(均可)。因此令方程组的阶增广矩阵秩为,系数矩阵的秩为。矩阵有无数组解的条件就是(严格来说:有无数组解的充要条件是

    +

    看第二个例子:

    +

    定义增广矩阵:;它的系数矩阵:

    +

    增广矩阵变换后:;系数矩阵:

    +

    根据定义,得到,此时。方程组无解。因而矩阵无解的充要条件是。简单理解起来就是方程组中的两个方程起了冲突,矩阵被省去的其中一步变换是:,第一行和第三行相当于要你求解如下的方程组:。显然矛盾,因此矩阵无解。

    +

    加上第一节里面的结论,我们总结出了矩阵解分布的三种情况(方程组的增广矩阵为、系数矩阵为,阶为):

    +
      +
    1. 时,矩阵有唯一解
    2. +
    3. 时,矩阵有无数解
    4. +
    5. 时,矩阵无解
    6. +
    +

    因此就有了一套组合算法:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    #include <bits/stdc++.h>
    #define N 110

    #define NO_SOLUTION -1
    #define INFINITE 0
    #define SOLVE_OK 1
    using namespace std;

    typedef long long ll;

    double mat[N][N];
    int n;
    double eps = 1e-6;

    int solve() {
    int rank = 0;
    for (int c = 0, r = 0; c < n; c++) {
    int t = r;
    for (int i = r; i < n; i++) {
    if (fabs(mat[i][c]) > fabs(mat[t][c])) t = i;
    }
    if (fabs(mat[t][c]) < eps) continue;
    for (int i = c; i <= n; i++) swap(mat[r][i], mat[t][i]);
    for (int i = n; i >= c; i--) mat[r][i] /= mat[r][c];
    for (int i = r + 1; i < n; i++) {
    if (fabs(mat[i][c]) > eps) {
    for (int j = n; j >= c; j--) {
    mat[i][j] -= (mat[r][j] * mat[i][c]);
    }
    }
    }
    r++;
    rank = r;
    }
    if (rank < n) {
    for (int i = rank; i < n; i++) {
    for (int j = 0; j < n + 1; j++) {
    if (fabs(mat[i][j]) > eps) return NO_SOLUTION;
    }
    }
    return INFINITE;
    }
    for (int i = n - 1; i >= 0; i--) {
    for (int j = i + 1; j < n; j++) {
    mat[i][n] -= mat[i][j] * mat[j][n];
    }
    }
    return SOLVE_OK;
    }

    int main() {
    cin>>n;
    for (int i = 0; i < n; i++) {
    for (int j = 0; j < n + 1; j++)
    cin>>mat[i][j];
    }
    int res = solve();
    if (res != SOLVE_OK) cout<<res<<endl;
    else for (int i = 0; i < n; i++) {
    if (fabs(mat[i][n]) < eps) mat[i][n] = fabs(mat[i][n]);
    printf("x%d=%.2lf\n", i + 1, mat[i][n]);
    }
    return 0;
    }
    +

    时间复杂度:

    +

    以后上大学解高次线性方程就可以用这段程序秒了。

    +

    Div3. 矩阵基本运算

    +

    1. 加法

    +

    +

    注意类比元一次方程组的加减消元,两个矩阵相加意味着同一位置的元素相加。需要注意:只有同型的矩阵才有加法运算(同型即行数列数相等)。

    +

    可以知道,四则运算的加法交换律和结合律仍然适用于矩阵加法。

    +

    2. 减法

    +

    +

    加法的逆运算,让矩阵同一位置的元素相减即可。也是仅限于同型矩阵之间才可做减法。

    +

    3. 数乘

    +

    +

    即矩阵中每个元素都跟数字相乘。符合乘法交换律和结合律

    +

    矩阵的加法、减法和数乘合称为矩阵的线性运算

    +

    4. 转置

    +

    矩阵的转置矩阵用表示。

    +

    +

    直观来讲就是将原矩阵旋转一下(行和列互换)。满足如下性质:

    +

    +(转置一次后再转置一次还是原来的矩阵)

    +

    +(常数转置后就是它本身)

    +

    +(上一条是它的特殊形式,类比两数乘积的幂)

    +

    5. 共轭

    +

    矩阵的共轭矩阵用表示。

    +

    +

    +

    类比共轭复数的定义:实部不变、虚部取相反数。矩阵共轭变换就是将矩阵中的所有复数变为其共轭形式。

    +

    6. 共轭转置

    +

    矩阵的共轭转置矩阵记作

    +

    +

    +

    字面意思,先取共轭,再转置。它具备转置矩阵的三条性质。

    +

    Div4. 矩阵乘法

    +

    只有一个矩阵的行数和另一个矩阵的列数相等时才可进行乘法运算

    +

    例如一个矩阵和一个矩阵。记它们的乘积。则中的某个元素。并且是一个的矩阵。

    +

    因此

    +

    它满足结合律、分配律,但是大多数情况下不满足交换律。交换律不成立可以看到下面这个例子:

    +

    首先根据定义,矩阵的行列数取决于做乘法的两个矩阵的行列数,比如矩阵和矩阵相乘,得到一个矩阵,但是将它颠倒顺序,让一个矩阵与矩阵相乘,结果将是一个矩阵,和前者行列数相反。

    +

    对于结果是正方形矩阵的,可以自己随便设置两个矩阵进行计算。但是部分矩阵仍然可以进行交换律运算:矩阵乘一个单位矩阵/数量矩阵[/]、矩阵乘它的伴随矩阵()。

    +

    Div5. 其他常用类型的矩阵

    +

    1. 零矩阵:顾名思义,由组成的矩阵称作零矩阵。零矩阵不可逆,且任何符合条件的矩阵与一个零矩阵的积均为零矩阵。

    +

    2. 单位矩阵:形如的矩阵被称作单位矩阵,通常用字母表示。单位矩阵指仅对角线系数为、且其他系数为的矩阵。阶矩阵与它的逆矩阵相乘得到的结果就是一个阶单位矩阵,即

    +

    3. 数量矩阵:形如的矩阵叫数量矩阵,可以看作实数与单位矩阵进行数乘运算后的结果,通常表示成。矩阵与一个数量矩阵的乘积满足乘法交换律。

    +

    4. 逆矩阵:如果存在一个矩阵和单位矩阵,使得,则称矩阵可逆,的逆矩阵,也可记作。单位矩阵的逆矩阵是它本身;零矩阵不可逆。阶矩阵可逆的充要条件是

    +

    5. +对称矩阵:转置矩阵与自身相等的矩阵叫做对称矩阵,特征是所有元素关于对角线对称,例如:。对称矩阵必为方形矩阵,反之不一定成立,对于一个方形矩阵必定是对称矩阵。

    +

    Div6. 矩阵的几何表示

    +

    平面直角坐标系上,一个向量可以被表示成的形式,即

    +

    计算机中,用两个不共线向量能够表示整个平面直角坐标系。运用一点高中数学的空间几何知识,这里的被称作基底(当然,如果需要描述三维空间坐标系,则需要三个不共线的基底向量)。于是我们使用矩阵来描述这个平面直角坐标系就是非常简洁明了且优雅的了。

    +

    假设我们常规想法中的平面直角坐标系是,经过一轮线性变换后得到的新坐标系是:。用一张图看一下变换后的坐标系:

    +

    +

    如果在最开始的坐标系中有一个向量,我们如何在新的坐标系中表示它呢?再根据我们高中数学所学,只需要算出的值即可。因为轴的基底,相当于上的一个单位,我们求新向量时只需求出在新的参考系中的新值和值,因而直接用方向的系数乘以一个单位即可,在这里就是,得到

    +

    抽象之后变成:

    +

    +

    +
    +

    例题:

    +
      +
    1. P3389 [模板] +高斯消元法 (上三角矩阵的转换)
    2. +
    3. P2455 [SDOI2006] +线性方程组 (前一道题的升级版)
    4. +
    +

    Part8. 组合计数

    +

    StarterDiv1. 阶乘概述

    +

    阶乘,数学中用表示,表示的值,即

    +

    特殊地,

    +

    StarterDiv2. 常用排列总结

    +

    1. 排列数:数学中用表示(,老教材记作)。表示从个数中选择个进行排列,公式为:

    +

    为啥呢?,有弔图为证↓

    +

    +

    2. 组合数:假设有个物品,从中任选出个排成一组,叫做组合;所有可能的选法总数叫做组合数。用表示,计算公式为:。简记为:乌鸦坐飞机

    +

    弔图×2↓

    +

    +

    GZ表示就凭这几张图他能速通整个组合数的内容

    +

    StarterDiv3. 二项式定理

    +

    学过初中的大家都知道:,这是完全平方和公式。高中的一些牛逼娃还知道完全立方和公式,也就是:。这些式子其实都是可以由二项式定理套出来的。

    +

    二项式定理定义式如下:

    +

    +

    这里出现的。是不是突然发现它和组合数公式的共同之处喽?但是这一章并不会用它,只是作补充知识的说……

    +

    有这三条就够了,接下来进入组合计数的内容。

    +

    Div1. 高考娃狂喜——组合数计算

    +

    一个小栗子:

    +

    宇宙榜一大学阿福大学的榜一博士后导师黑虎阿福给你出了一道难题:

    +
    +

    给你两个正整数),让你求出的值。

    +
    +

    “这还不简单?”

    +

    阿福“好的,我这里将设为设为,请你求解。”

    +

    “WTF?”

    +

    于是你决定用程序来代替人脑,阿福教授也做出了一定让步,让你求出的值。但是不幸的是,人类的计算机科学水平自从2024之后就被来自几光年外的八体星人文明发出的“侄子一号(NEPHEW +1)”探测僚机锁定了,因此你需要设计一个高效的计算方式,而不是妄想着用2077年的赛博机器运行暴力计算,来解决这个问题。

    +

    一旦你的运行时间超过一秒,阿福教授就会使用战技“乌鸦坐飞机”对你造成大量阶乘伤害。已经学习了阶乘的你想必已了解了它的威力,所以还是老老实实推导公式吧!

    +

    递推版:

    +

    组合数递推公式:

    +

    分析思路类似于动态规划问题:我们要从个物品中挑选个出来,求组合数。

    +

    +

    上图中,若包含这个红色物体,那么我们只需再从剩下的个物体里挑选,因为红色物体自身占据了个位置中的其中一个,因此留给其他物体的总名额就只有个,因此该情况下组合数:;同样地,若不包含红色物体,从剩下的个物体中选出个,因为在该情况下红色的物体不计入组合,因此剩余名额还是个,组合数就是。最后,因为从个物体里选,只有包含红色和不包含红色两种情况(就好像你的双亲,不是你的母亲就是你的父亲),因此可以做到不重不漏。所以总组合数就是

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #include <bits/stdc++.h>
    #define N 2010
    using namespace std;

    int c[N][N];

    void Csieve(int p) {
    for (int i = 0; i < N; i++) {
    for (int j = 0; j <= i; j++) {
    if (!j) c[i][j] = 1;
    else c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % p;
    }
    }
    }

    int main() {
    int a, b, p;
    cin>>a>>b>>p;
    Csieve(p);
    cout<<c[a][b]<<endl;
    return 0;
    }
    +

    时间复杂度:

    +

    适用于的大部分情况。

    +

    预处理版:

    +

    但是众所周知,递归有两大痛点:对于主观思维来说,是边界问题;对于客观条件来说,是内存。递归过程中CPU里储存了大量的未运行或者待返回的函数实例,当的值增大时,尽管它能在时间方面表现出色,但是内存就不那么理想了,反而会显得臃肿至极。当题目中给出时,建议用这种方法。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    #include <bits/stdc++.h>
    #define N 100010
    using namespace std;

    typedef long long ll;

    int fact[N], infact[N];

    int qpow(int a, int b, int p) {
    int res = 1;
    while (b) {
    if (b & 1) res = (ll) res * a % p;
    a = (ll) a * a % p;
    b >>= 1;
    }
    return res;
    }

    int inv(int a, int p) {
    return qpow(a, p - 2, p);
    }

    int C(int a, int b, int p) {
    return ((fact[a] % p) * (infact[b] % p)) % p * infact[a - b] % p;
    }

    int main() {
    int a, b, p;
    cin>>a>>b>>p;
    fact[0] = infact[0] = 1;
    for (int i = 1; i <= N; i++) {
    fact[i] = (ll) fact[i - 1] * i % p;
    infact[i] = (ll) infact[i - 1] * inv(i, p) % p;
    }
    cout<<C(a, b, p)<<endl;
    return 0;
    }
    +

    时间复杂度:

    +

    适用范围,均在int范围内的大部分情况。

    +

    Lucas定理优化版:

    +

    定理如下:为质数)。证明在此(建议直接背结论)。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    typedef long long ll;

    int p;

    int qpow(int a, int b) {
    int res = 1;
    while (b) {
    if (b & 1) res = (ll) res * a % p;
    a = (ll) a * a % p;
    b >>= 1;
    }
    return res;
    }

    int inv(int a) {
    return qpow(a, p - 2);
    }

    int C(int a, int b) {
    int res = 1;
    for (int i = 1, j = a; i <= b; i++, j--) {
    res = (ll) res * j % p;
    res = (ll) res * inv(i) % p;
    }
    return res;
    }

    ll lucas(int a, int b) {
    if (a < p && b < p) return C(a, b);
    return (ll) C(a % p, b % p) * lucas(a / p, b / p) % p;
    }

    int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int t;
    int n, m;
    cin>>t;
    while (t--) {
    cin>>n>>m>>p;
    cout<<lucas(n + m, n)<<endl;
    }
    return 0;
    }
    +

    时间复杂度:

    +

    其本质是套用定理计算,因为是模意义下的除法,因而我们使用逆元来操作除法。

    +

    适用范围,long long范围内的大部分情况。

    +

    高精度版(选修):

    +

    什么?你厌倦了组合数后面挂着的模?不妨试试高精度版的组合数计算吧!它适用于作业上的题目求解!(虽然前面几种也可以,毕竟手算的题数据很小取不取模都一样)是不是心动了呢?

    +

    常规思路来说,我们的组合数公式经过一轮分式化简可以得到:。因此我们可以实现高精度的乘除法来计算这个炒鸡长的算式,但是这样不仅效率低下,手写和调试的难度也会增加。我们急切地想知道如何简化成一种高精度算法。

    +

    我们看到了Part1里面讲的算术基本定理,将组合数转化为的质数乘积分解式,最后我们只需要解决质数头顶的指数即可。我们使用以下这个公式:

    +

    +

    用它可以计算出的个数。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    #include <bits/stdc++.h>
    #define N 10010
    using namespace std;

    typedef long long ll;

    vector<int> num;
    ll primes[N], sum[N];
    bool st[N];
    int cnt = 0;

    void prime_sieve(int n) {
    for (int i = 2; i <= n; i++) {
    if (!st[i]) primes[++cnt] = i;
    for (int j = 1; i * primes[j] <= n; j++) {
    st[i * primes[j]] = true;
    if (i % primes[j] == 0) break;
    }
    }
    }

    int get(int a, int p) {
    int res = 0;
    while (a) {
    res += a / p;
    a /= p;
    }
    return res;
    }

    vector<int> mul(vector<int> a, int b) {
    vector<int> res;
    int t = 0;
    for (int i = 0; i < a.size(); i++) {
    t += a[i] * b;
    res.push_back(t % 10);
    t /= 10;
    }
    while (t) {
    res.push_back(t % 10);
    t /= 10;
    }
    return res;
    }

    int main() {
    int a, b;
    cin>>a>>b;
    prime_sieve(a);

    for (int i = 1; i <= cnt; i++) sum[i] = get(a, primes[i]) - get(b, primes[i]) - get(a - b, primes[i]);
    vector<int> res;
    res.push_back(1);
    for (int i = 1; i <= cnt; i++) {
    for (int j = 1; j <= sum[i]; j++) {
    res = mul(res, primes[i]);
    }
    }
    for (int i = res.size() - 1; i >= 0; i--) cout<<res[i];
    cout<<endl;
    return 0;
    }
    +

    时间复杂度:

    +

    适用范围,int范围内。

    +

    有了这段代码,我们就可以完成开头阿福教授的原问题了(不模不限数据)!

    +

    Div2. +世界上最OI的IDE——Catalan数

    +

    当你翻开Catalan数的介绍文章,并大学特学了一番,感觉自己完全掌握了这神奇的数列,正当你兴致勃勃地打开题库搜索到一道Catalan数的题目正准备大展身手时,你会发现,面对这神奇的题干,不同于往常秒模板题的你,你甚至完全看不出来它和Catalan数有任何的关系,而且很有可能,你其实连Catalan数究竟是什么东西都不知道!

    +

    苏子愀然,正襟危坐而问客曰:“何为其然也?” +其实还真不能让那些博客背上黑锅,这种现象与Catalan数本身的应用有很大的关系。

    +

    Catalan数,或者习惯叫卡特兰数、明安图数,是组合数学中常用的特殊数列。数列如下:“”,它是一个无穷数列,数与数之间看起来似乎也没什么太大联系……其实它和斐波那契数列有类似之处,它们不具有特定的数学意义(只是斐波那契的递推方法简单得多罢了),只是一个十分普遍的数学规律。所以学习时应该挂靠于例子本身而不是一味依赖于定义所写,那我们就开始吧:

    +

    用最经典的例子写出来就是:

    +
    +

    给你一个的网格,你将从原点开始移动。对于每次移动,你只能向上/向右一格(坐标/坐标加一),但是需要保证你总向右走的次数不少于向上走的次数,问从原点到有多少种不同的合法路径?

    +
    +

    假设你某时刻走到了点,根据题目要求,意味着需要保证。我们拟合一条经过点的正比例函数,不难看出它的斜率。对于这个的网格,所有的点都在整数刻度上。我们接着画出直线的图像,然后尽可能画几条不合法的路径出来比对一下,你会发现:不合法的路径与直线至少有一个交点,合法路径一定与没有交点。用一张图来直观体会一下:

    +

    +

    终点,其中红线为不合法路径,蓝线为合法路径。不难发现,不合法的路径与绿线()都有至少一个交点,因为它们在某次移动后的端点与原点拟合而成的正比例函数的斜率,因此不是合法路径。

    +

    那么如何来计算合法和不合法路径的条数呢?直接求出合法路径不好求,规律不好找,因此我们计算出总路径数量,减去不合法数量即是合法路径数量。

    +

    可以看到,无论选择什么样的路径,在不左移、不下移的前提下,到达,你都只能移动次(小学内容,把横线和竖线平移到一块数格子),其中右移次、上移次。转化一下,就是在次移动中选出次进行右移操作,总数就是

    +

    因为所有路径,包括合法的和不合法的路径都最终抵达了,难以将内鬼剔除出来。我们选择将不合法路径关于判定线对称过去,它们的新终点将是,也就是。根据上面的推导方法,这里就是在轮移动中挑出次右移操作,于是不合法路径的数量就是:,合法路径数量是:

    +

    (至于为什么用右移次数而不是上移次数,是因为上移受到限制,这意味着你可以一直右移到而无需担心条件限制;但是你就不能先一直上移到,因为这不符合题目要求)

    +

    扩展:如果题干中指明向右走的次数不少于向上走的次数,则只需将判定线上下平移为即可。

    +

    那这些又和宇宙第一IDE有什么关系呢

    +

    应用场景一:括号匹配

    +

    将向右走转化为左括号“(”,向上走转化为右括号“)”。对于每一次输入,检查一下左括号输入次数是否永不小于右括号输入次数。若是,当输入最后一个右括号,使左右括号数量相同时,即为匹配成功;若不是,且左括号个数大于右括号个数,则表明括号等待补全;若不是,且左括号个数小于右括号个数,即立即宣布失配。

    +

    应用场景二:合法进出栈序列计数问题

    +

    假设一个初始为空的栈,有次操作,次进栈,次出栈,请问合法进出栈序列总数(空栈不出)是多少?

    +

    答案就是Catalan数,自行套公式计算。

    +

    应用场景三:圆的不相交弦计数问题

    +

    假设一个圆周上分布着偶数个点,对这些点两两连线,使相连的线不相交的所有方案数。其中一个合法解如下图:

    +

    +

    聪明如你,答案还是Catalan数!那么如何转化为已知问题求解呢?

    +

    我们将出发点标记为左括号“(”,从出发点引出去的线与其他线/点的所有交点标记为右括号“)”。当所有点两两连接完毕时,根据场景一的模型,一旦左右括号失配即代表不合法,否则合法。因此这个问题也就变成了:给定个左括号和右括号,求出使左右括号匹配的排列个数。在这里,如果问题无解,将会是这样:

    +

    +
    +

    例题:

    +
      +
    1. P3807 [模板] +卢卡斯定理/Lucas 定理
    2. +
    3. P5014 +水の三角(修改版) (Catalan数公式变形推导)
    4. +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +
    + + +
    +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/oi-partitioning/index.html b/oi-partitioning/index.html new file mode 100644 index 0000000000..7ff45cf8af --- /dev/null +++ b/oi-partitioning/index.html @@ -0,0 +1,4336 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OI 分块 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + + + + + + +
    +
    +

    何为分块

    +

    分块,正如其名,将一个整区间分为若干小区间进行操作。分块拥有比线段树更强的泛用性,但是时间复杂度略输一筹;分块代码更加直观、减少理解难度,但是时间复杂度稍逊风骚;分块的代码比线段树更短,但是时间复杂度惜败后者……线段树所上下传递的操作计算必须满足结合律,区间平均数、方差还行,像计算区间众数、中位数这样的问题,线段树就只能被薄纱了……

    +

    考虑到树状数组理解难度较大、较难调试,一般都选用泛用性强、码量折中、效率及格、调试简便的分块算法求解。

    +

    如何分块

    +

    不同于线段树的二分存储,分块所使用的块状数组本质上只是一个带有块起始下标和块末尾下标的普通数组,就像在一列数中间插上分割线分出区块。对于区间修改操作,只需要进行以下几步就可以:

    +
      +
    1. 判断左端点l和右端点r所在的区块
    2. +
    3. 若两个端点在同一个区块内:暴力循环更新值
    4. +
    5. 若两个端点不在同一个区块内:在l所在区块内,从l开始循环至该区块结束,暴力更新值,相应的从r开始,往回循环至该区块起始处,暴力更新值,最后将二者中间整块的区块打上更新标记
    6. +
    +

    我们会发现,分块其实就是将完全暴力的操作拆分成部分暴力的操作和部分取巧的操作。尽管看起来还是在使用暴力算法,但实际上优化了不少东西,而优化的效率还得取决于每个区块的长度。那么我们如何选择区块的长度呢?

    +

    最坏情况下,指定的左右端点就是整个数组的左右端点。假设总长度为,一般采取的区块长度是。这样一来,就有个整区块会被打上标记,而两头的区块(长度都为)暴力修改的复杂度是。这也就意味着分块是一种根号算法(时间复杂度是根号级别的算法),尽管它在时间复杂度上比不过线段树的。但是只要满足或者为询问个数),基本上就不会TLE(1s)。

    +

    既然已经知道了的来历,我们对数组进行分块时就简单了。首先循环次用以记录区块的起点和终点,但是注意如果数组长度不为完全平方数就需要将最后一个区块(编号为的区块)的终点下标设为以免访问越界。开两个长度略大于的数组sted分别记录每个区块的起点下标和终点下标;加上一个查询数组bel,用于查找第个数所属的区块编号;同时为了避免后期访问到最后一个区块时出现下标越界RE的情况,再开一个长度的数组记录每个区块长度(也可以只开一个变量存,特判是否是最后一个区块即可)。接下来就可以循环遍历整个数组了:

    +

    这是求解区间和的一段代码,init()函数中,我们把每个区块的和存在sum对应下标处

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #include <bits/stdc++.h>
    #define N 1000010
    #define SQN 1010
    typedef long long ll;

    int st[SQN], ed[SQN], size[SQN], bel[SQN];
    ll a[N], tag[N], sum[N];

    void init() {
    int sq = (int) sqrt(n);
    for (int i = 1; i <= sq; i++) {
    st[i] = sq * (i - 1) + 1;
    ed[i] = sq * i;
    size[i] = ed[i] - st[i] + 1;
    }
    ed[sq] = n;
    size[sq] = ed[sq] - st[sq] + 1;
    for (int i = 1; i <= sq; i++) {
    for (int j = st[i]; j <= ed[i]; j++) {
    bel[j] = i;
    sum[i] += a[j];
    }
    }
    }
    +

    按照如上所述的修改原理:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void update(int l, int r, int x) {
    if (bel[l] == bel[r]) {
    for (int i = l; i <= r; i++) a[i] += x, sum[bel[i]] += x;
    } else {
    for (int i = l; i <= ed[bel[l]]; i++) a[i] += x, sum[bel[l]] += x;
    for (int i = st[bel[r]]; i <= r; i++) a[i] += x, sum[bel[r]] += x;
    for (int i = bel[l] + 1; i < bel[r]; i++) tag[i] += x;
    }
    }
    +

    询问区间和的原理比较相似,同样是分lr所在区块进行讨论。只是当进行整体区块操作时,用与线段树相似的方法——将标记乘到总和中并累加即可。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ll askSum(int l, int r) {
    ll res = 0;
    if (bel[l] == bel[r]) {
    for (int i = l; i <= r; i++) res += (a[i] + tag[bel[l]]);
    } else {
    for (int i = l; i <= ed[bel[l]]; i++) res += (a[i] + tag[bel[l]]);
    for (int i = st[bel[r]]; i <= r; i++) res += (a[i] + tag[bel[r]]);
    for (int i = bel[l] + 1; i < bel[r]; i++) res += (size[i] * tag[i] + sum[i]);
    }
    return res;
    }
    +

    以上求区间和的代码可以提交到洛谷 P3372 线段树模板 +一里。与线段树相比,分块的速度慢了大约40ms,在300ms左右,还是可以接受的。

    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +
    + + +
    +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/oier-math-senior/index.html b/oier-math-senior/index.html new file mode 100644 index 0000000000..55716959e2 --- /dev/null +++ b/oier-math-senior/index.html @@ -0,0 +1,4391 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 信息竞赛 高级数学 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + + + + + + +
    +
    +
    +

    诗曰:

    +

    “高数第一杀手,考试一考就寄。复数知识一用,算成正一。朴素演算善后,死磕公式何必?考场信心十足,全错当场暴毙。”

    +
    +

    前置知识:复数、位运算

    +

    Part1. 快速傅里叶变换

    +

    Div1. 世界上最优雅的算法

    +

    FFT起源

    +

    FFT的前身是DFT,可以简单看作是一堆OIer争先恐后对DFT算法进行优化的结果。美苏冷战期间,双方都对自己的核实力有所隐瞒,就等着某一天用自己的核导弹打对方个措手不及……在一次科学议会上,有人提出在苏联国境周边安装大量地震波传感器,将传感器的数据回收处理,分析是否出现了类似于核试验产生的震波从而判断苏联是否在进行秘密核试验。但是在当时用于频谱分析的DFT算法效率太过低下,传感器又必须在短时间内分析大量的频谱数据,因此逆境出人才——当时参与会议的其中一位科学家Tukey后来找到了程序员Cooley,后者在当时是一名操作ENIAC的程序员。二者分工明确,在1965年他们提出了FFT算法(当时叫做Cooley-Tukey算法),这个算法在后来被IEEE列入他们主编的“20世纪十大程序算法”之中。

    +

    FFT在信号处理领域受到了广泛的应用,直至今日它仍然被集成在大多数波谱分析仪器中作为底层算法之一。然而在信息学竞赛中,它被广大的OIer看中,拿去优化了高精度乘法的计算。它可以将朴素的高精度乘法的复杂度大幅降低到,在处理大数据时,它将比Karatsuba乘法算法更为高效……

    +

    Div2. 系数表示法与点值表示法

    +

    我们在初中时期学过一元二次方程的函数图像。一般情况下,我们都会用形如:的解析式形式来表示它。这种表示函数的方法就叫做系数表示法——自变量的某次幂前乘一个系数得到的,一个次多项式的系数表示法定义为:

    +

    系数表示法可以直接通过值求出值,就好比生物的基因组排列,给出一个基因组,科学家就可以复原出整个生物的全貌,如果在各种函数绘制工具中输入解析式,它都唯一对应一个图像;但点值表示法就不是这样的了。它好比生物的某个性状,并且只是一个小得不能再小的特征点。比如给你两个特征:“白色毛发”和“部分呈现黑色”,不同人会做出不同的回答——动物学家会说“熊猫”、“斑马”、“美国短毛猫”一类的事物;阿宅会说:“伊雷娜”、“仆人”等等。加入其他限定词可能会使结果统一化,但是对于数学函数来说,你需要限定它的最高次数。如果你只给出了点,“求出经过点的二次函数”这样的问题显然是不合适的,因为次函数最少需要个不同的点来唯一确定。

    +

    假如我们让一个三次函数和一个四次方程相乘求卷积,得到的函数将会是一个七次函数。如果我们需要将系数转换为点值,需要取定义域上七个不相同的值进行计算,对于每次计算,要将值以不同次幂代入至多七个算式中求出值,显然时间复杂度是的。那还不如不优化

    +

    为了减少这里的复杂度,我们借助一点高一所学的奇偶函数的内容~(没学过/没学懂没关系,奇函数相当于关于原点对称、偶函数相当于关于轴对称,并且函数的取值范围也必须关于原点对称——假如能求出对应值,也必须能求出对应值)。

    +

    假如该函数是一个偶次的幂函数,幂函数的定义是。如果此处为偶数,整个函数就是一个偶函数、反之为奇函数。对于偶函数满足、奇函数。那么我们可以把原函数分解成多个偶函数和奇函数的和,例如:

    +

    函数

    +

    经过一轮拆分:。根据奇偶函数的性质:奇函数+奇函数=奇函数、偶函数+偶函数=偶函数。因此左边括号整体组成的函数是奇函数、右边括号整体组成的函数是偶函数,常数单独拆出来:

    +

    +

    这张图可以直观看出原函数(绿线)被拆分成偶项(红线)、奇项(蓝线)和常数项(橙线)后的样子。

    +

    对于奇项,代任意,求出一个值后,第二个值直接取相反数;偶项则是相反,结果相同。当然只拆一次是不够的,里面还有很多项呢,我们试着把原函数拆分成只有一项,以递归计算。我们对奇项和偶项继续进行拆分

    +

    。但是此时的取值变成了平方,相对应地,继续拆分一次,括号里的会变成。因此取相反数值不管用了(),我们急切地想要找到就算平方后也是相反数的一对数据来求值。此时高阶思维娃找到了一个东西——复数域。

    +

    Div3. 单位根

    +

    首先花一些篇幅来介绍复数的概念。我们学过:形如这样的的一元二次方程是无解的。这并不完全正确——严格来说是在实数范围内无解,这个问题自从几千年前、方程发明之初就引来了无数数学家的疑问与探索,人们找来找去就是为了能找到一个阿拉伯数字,让它的平方等于。很可惜,找不到,因为传统意义上的阿拉伯数字体系建立在实数基础上,又不在实数范围内,自然所有的尝试都会以失败告终。直到有一天,笛卡尔提出了虚数的概念,认为它是“不存在的数”、紧接着高斯使用虚数符号来表示的值,后面他又提出了“复平面”来将复数表示成平面上的一个向量。虚数这才有了立足之地。

    +

    而复数就像是实数和虚数的一次友好会面,复数域用字母表示,一个复数由实部和虚部组成。例如复数,它的实部是、虚部是

    +

    紧接着,我们的FFT之旅就要来到下一个目的地——复平面。复平面类似于平面直角坐标系,只不过轴变成了实数、轴变成了虚数。复平面的轴因而称作实轴、轴称作虚轴,刚才的复数可以看作复平面上的一个向量

    +

    比如说上一节遗留的式子,递归继续深入一层时,递归函数会变成。假如我们要让括号里的数是1,也就是这个函数在自变量为的取值(事实上取成1恰好符合单位根的定义,于是就有简便的计算方式),我们就要解决的问题,而且还必须各不相同……两边同时开根号:。展开成方程组就是:,根据的数学定义,方程1解得,方程2解得。也就是:

    +

    每次递归,函数括号中的参数的幂就会乘2。幂在数值上就是,解决次多项式的拆分需要给出个不同的值,因而递归层数满足如下关系:。因此原方程是七次方程,就需要递归三层,得到8个相异的,从而计算出8个点!

    +

    引入单位根的概念:满足的复数叫做次单位根。在复平面上,次单位根将复平面上的单位圆等分。回到上例中的四次单位根,它们在复平面上的分布如下图:

    +

    +

    和点恰好对应实数解,点与点对应复数解

    +

    如果是八次()单位根,图像如下:

    +

    +

    其中,对应复数,其余同理。由于次单位根相当于将单位圆平分为份,并且其中有一个解一定是(上图点)。联系到三角函数在单位圆中的表示,复平面单位圆上的点一定满足。因此若,则

    +

    假如我们按逆时针方向,起始点(实轴)从0开始编号,并将八次单位根和四次单位根的图像作比较,可以导出单位根的两条性质():

    +
      +
    1. (对应点关于原点对称)
    2. +
    3. (单位根次数和编号同乘2,坐标相同)
    4. +
    +

    特殊地,.

    +

    这下终于可以开始从一般例子出手推了。令

    +

    按照奇偶项分为两组(这里可以直接通过的奇偶性判断),折半次数,递归层数为1——令奇项函数为,偶项函数为(奇项提出一个避免出现小数次幂)、。将奇偶项的自变量设为以表示出原式,即未折半的函数的未知数的次数:

    +

    函数的自变量来到了,令。该轮到单位根显神通了,令,此时的,根据上述单位根的两条性质,推出如下式子:

    +

    ,根据第二条性质,次数编号同除以2,得到:

    +

    +

    如果此时原式、根据第一条性质,以及特殊情况,代入,根据第二条性质,次数编号同除以2,得到:

    +

    +

    正因此,当已知时,代入计算,那么当时的值也就明确了(根据性质第二条直接求出)。就可以将问题规模缩小一半,递归的边界就是

    +

    Div4. IFFT与蝴蝶操作

    +

    IFFT的中文名称是快速傅里叶逆变换。有些人比如刚开始接触FFT的我认为只要敲出FFT的代码,就可以解决任何函数卷积的问题了……错了,FFT主要是将系数表示法转换为点值表示法,相当于数学考试解析式求解题题干里给你的已知点坐标!卷积之路才刚刚过半,接下来介绍如何将相乘后得到的点值表示法重新转化为系数表示法。由于FFT是系数到点值的转换、这种方式是点值到系数的转换,因而称之快速傅里叶逆变换——IFFT。

    +

    我们的FFT算法已经将两个函数的卷积按照点值形式求了出来,但是一般生活中大家还是习惯性使用解析式,也就是系数表示法表示一个函数,就需要借助IFFT将卷积的点值形式重新转化为系数形式。

    +

    假设一个函数的系数形式在经历了一次FFT后变成了其点值形式。根据FFT有:。IFFT的作用就是将变成,下面是具体操作:

    +

    +

    简记为:根倒求和、倒乘积。

    +

    再加上,复数的乘积在复平面上有个奇妙的性质:复平面上一个向量可以看作是从实轴正半轴逆时针旋转特定的角度后得到的,这个角度称作向量的辐角,复数相乘时,得到的结果的辐角将是这两个向量的辐角之和、模长将是两个向量模长的乘积。简称辐角相加、模长相乘。除法作为乘法的逆运算,它在复平面上操作的结果是辐角相减、模长相除。因而单位根的倒数可以看作,也就是从实轴正半轴顺时针旋转的辐角大小。计算时就可以把原单位根关于实轴做一次对称变换,即虚部取相反数,也就是共轭。

    +

    对于代码的设计,尽管C++STL库提供了Complex<>复数类,但还是建议手写Complex。因为STL库的运行效率有时会很慢,会被卡掉,而且它的码量也不大,手写难度不高。强烈推荐手写结构体Complex。

    +

    递归Version:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    #include <bits/stdc++.h>
    #define N 6000010
    using namespace std;

    const double PI = acos(-1.0);

    struct Complex {
    double real, imag;

    Complex(double r = 0.0, double i = 0.0) {
    real = r, imag = i;
    }
    } f[N], g[N];

    Complex operator +(const Complex &l, const Complex &r) {
    Complex res(l.real + r.real, l.imag + r.imag);
    return res;
    }

    Complex operator -(const Complex &l, const Complex &r) {
    Complex res(l.real - r.real, l.imag - r.imag);
    return res;
    }

    Complex operator *(const Complex &l, const Complex &r) {
    //(a+bi)*(c+di)=(ac-bd)+(ad+bc)i
    Complex res(l.real * r.real - l.imag * r.imag, l.real * r.imag + l.imag * r.real);
    return res;
    }

    Complex operator /(const Complex &l, const Complex &r) {
    //(a+bi)/(c+di)=(a+bi)(c-di)/(c^2+d^2)=[(ac+bd)+(bc-ad)i]/(c^2+d^2)
    Complex res((l.real * r.real + l.imag * r.imag) / (r.real * r.real + r.imag * r.imag), (l.imag * r.real - l.real * r.imag) / (r.real * r.real + r.imag * r.imag));
    return res;
    }

    void FT(int len, Complex *c, int type) {
    // type=1时为FFT,type=-1时单位根纵坐标取相反数,为IFFT
    if (len == 1) return;
    Complex c1[len >> 1], c2[len >> 1]; // c1为偶项系数,c2为奇项系数,数组大小除以2
    for (int i = 0; i <= len; i++) {
    // 按奇偶性分类存储
    if (i % 2 == 0) c1[i >> 1] = c[i]; // 紧凑存储,c1、c2数组下标除以2
    else c2[i >> 1] = c[i];
    }
    FT(len >> 1, c1, type); // 处理偶项
    FT(len >> 1, c2, type); // 处理奇项
    Complex omega = Complex(cos(2.0 * PI / len), type * sin(2.0 * PI / len)); // 计算单位根
    Complex k = Complex(1.0, 0.0);
    register Complex butterfly;
    for (int i = 0; i < (len >> 1); i++, k = k * omega) {
    butterfly = k * c2[i]; // 蝴蝶操作,记录下复数乘积(现场算太慢)便于调用
    c[i] = c1[i] + butterfly; // 单位根
    c[i + (len >> 1)] = c1[i] - butterfly; // 单位根性质,系数取反得到另一半
    }
    }

    void IFFT(int len, Complex *c) {
    FT(len, c, -1);
    }

    void FFT(int len, Complex *c) {
    FT(len, c, 1);
    }

    int main() {
    int n, m;
    cin>>n>>m;
    for (int i = 0; i <= n; i++) cin>>f[i].real;
    for (int i = 0; i <= m; i++) cin>>g[i].real;
    int len = 1;
    while (len <= n + m) len <<= 1; // 得到最小递归层数
    FFT(len, f);
    FFT(len, g);
    for (int i = 0; i <= len; i++) f[i] = f[i] * g[i]; // 点值相乘得到卷积点值
    IFFT(len, f); // 卷积点值转化为系数
    for (int i = 0; i <= n + m; i++) cout<<(int) (f[i].real / len + 0.5)<<' ';
    return 0;
    }
    +

    时间复杂度:

    +

    这个代码足够通过模板题有些人说不行,只需把数组开大一点点(5e6起步)就可以了……但是这个代码其实还可以继续优化,但是这下就很棘手了,本来推来推去已经够烧脑了你还要让我优化?,考虑到递归算法有些低效,浪费了一些空间和执行效率。那么我们如何把它变成一个非递归版本呢?答案是迭代!

    +

    迭代FFT与二进制优化

    +

    我们按照奇偶下标将原多项式分为了偶项和奇项,这样做的复杂度是。我们仔细观察一下抽出的系数之间下标的联系:

    +

    递归之前,系数下标:

    +

    递归一层,系数下标:

    +

    递归两层,系数下标:

    +

    递归三层,系数下标:

    +

    既然称作二进制优化,我们来看看第三层的数字写成二进制形式是怎样的:000 100 010 110 001 101 011

    +

    没有规律……别急,我们把数字倒过来念:000 001 010 011 100 101 110。诶?他们是单调递增的,再写成十进制就是:0 1 2 3 4 5 6。我们就找到规律了:递归结束时系数下标的二进制值等于原多项式的系数下标的颠倒二进制值

    +

    常规操作,我们使用进制转换来实现二进制逆序,这样的时间复杂度是的:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int rev(int n) {
    int res = 0;
    int k = log2(n) + 1;
    for (int i = 1; i <= k; i++) {
    if (n & 1) res += pow(2, k - i);
    n >>= 1;
    }
    return res;
    }
    +

    借鉴了这篇题解的逆序思路,逆序的时间复杂度是的,处理数组的复杂度是的:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    int l,r[MAXN];
    int limit=1;
    void fast_fast_tle(complex *A,int type)
    {
    for(int i=0;i<limit;i++)
    if(i<r[i]) swap(A[i],A[r[i]]);//求出要迭代的序列
    for(int mid=1;mid<limit;mid<<=1)//待合并区间的中点
    {
    complex Wn( cos(Pi/mid) , type*sin(Pi/mid) ); //单位根
    for(int R=mid<<1,j=0;j<limit;j+=R)//R是区间的右端点,j表示前已经到哪个位置了
    {
    complex w(1,0);//幂
    for(int k=0;k<mid;k++,w=w*Wn)//枚举左半部分
    {
    complex x=A[j+k],y=w*A[j+mid+k];//蝴蝶效应(应为“蝴蝶操作”)
    A[j+k]=x+y;
    A[j+mid+k]=x-y;
    }
    }
    }
    }
    +

    以及r数组的读入:

    +
    1
    2
    for(int i=0;i<limit;i++)
    r[i]= ( r[i>>1]>>1 )| ( (i&1)<<(l-1) ) ;
    +

    当然,提高组不考,如果考到,基本上那个递归版本也够用了……

    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +
    + + +
    +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/page/2/index.html b/page/2/index.html new file mode 100644 index 0000000000..3164783810 --- /dev/null +++ b/page/2/index.html @@ -0,0 +1,4953 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    + +
    + + + + +
    +
    + + + + + + +
    + + 2023年度总结——机房管理软件的破解经验 + +
    + + + +

    + +

    + +
    + + + +文中提到的核心程序代码及食用方法在文章末尾处,或者访问我的云剪贴板来复制代码 +更新条目的链接 +极域——世界上最弱小最单纯的机房软件 +注意,极域由C/C++语言开发。对于极域的反编译工作可以基本认定为徒劳且耗费大量时间的。 +开始的开始,我的脱控方式还仅限于最原始的taskkill和ntsd。这种做法不仅有时会失效,而且一旦老师发现你的机子的监控屏幕是纯黑一片、且无法控制,他就会气急败坏地冲向... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + DC Doujin 2023 EP1 一触即发正式发布 + +
    + + + +

    + +

    + +
    + + + + + + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + +引入 +如果说数论是数学体系中专门用来研究数字性质的一个分支,那么初等数论则是对整数的性质进行系统性的探讨与研究。千万不要因为其中的“初等”二字小瞧这初等数论尽管名称和学习难度上都没有高等数论那么有逼格,就像初等数学之于高数,数论的所有内容均筑基于此。其中欧几里得证明的算数基本定理(一切合数都可被分解为有限个质数的乘积)在质数筛、GCD(以及LCA)计算、无理数证明等问题上均有用武之地。可以... + + +
    + +
    +
    + + + + + + + + + oi算法 + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 一命已出,前来还愿 + +
    + + + +

    + +

    + +
    + + + + +2023.11.11 21:10 + + + + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + Part1. 运算符 +Div1. 基本运算 +加号:,键盘上有 +减号:,键盘上有 +乘号(叉乘): \times +乘号(数量积/点乘): +\cdot +除号: \div +开方/N次方根: +\sqrt[N]{ABC} +乘方/N次幂: +A^N +下标: A_N +分数: +\frac{A}{B} +等于号:,键盘上有 +约等号: +\approx 加粗 +\thickapprox +不等号: +\neq +恒等号/定... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + DC Doujin 2023 EP1 先行预告 + +
    + + + +

    + +

    + +
    + + + DC Doujin +2023,点击访问。 +DC Doujin将在11月带来他的第一部视频作品“一触即发 A Cusp Before It +Rings”。这个视频,对日常学校干饭的情景进行真实再现。其中由木稿比你铁饰演的受伤学生受到热烈关注,其原型是初中部的一位学生,我们将其镜头化,力求最真实地表现出其强烈的反差感。 +禁止用于商业用途,转载请注明出处 DC +Doujin。 +Copyright ... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 《原神》枫丹语言考究 + +
    + + + +

    + +

    + +
    + + + 起因 +这天月假,当我正为即将到来的水神池子疯狂做任务屯原石时,在列表里看到了一个悬赏整整30原石的世界任务。本着不放过任何一个给原石的任务的宗旨,我来到了秋分山西侧,白淞镇东北方向的海边房屋处。只见一位男子全身掩埋在海沙之下、动弹不得,面前摆放着一只散发香味的甜甜花酿鸡。我看他精神失常,满嘴都是“新型美容方式”的胡话又哭又闹,呜呜呜呜,好可怜呀。于是我决定帮他一把……找出了幕后黑手,此时他举... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 常用算法模板 + +
    + + + +

    + +

    + +
    + + + 1. Trie树(字典树) +123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051#include <bits/stdc++.h>#define N 10010using namespace std;int son[N][70], idx = 0, ... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 国祯文集 + +
    + + + +

    + +

    + +
    + + + 曾茂华到底有多六 +——By 国祯 +曾茂华是中国当代著名的科学家和教育家,他以“慈父”、“良师”、“学者”等称号闻名于世。 +1:曾茂华的蠢行为 +曾茂华的蠢行为: +他在大学期间参加了一个乐队,并担任主唱。然而,不幸的是,由于自己的疏忽,他犯下了一件愚蠢的事情——用刀砍掉了对方的手指头。这件事让他成了学校里的头号人物之一。从那以后,他再也不敢做任何愚蠢的事情了。这是因为他害怕自己会被开除出乐队或者... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + CSP-J 2023 游记 + +
    + + + +

    + +

    + +
    + + + 又名:《第一次考就被小学生薄纱的一集》 +本次考场:绵阳东辰国际学校 +第一节    赛前准备 +       插一句:CSP-J +2023没有设置赛前试机环节(包括CSP-S,成都绵阳都这样),个人推测可能是由于开放自选Windows和Linux系统带来的结果。如果你听见诸如:不要操作电脑,违者将作作弊处理 +的话时,请将你按捺不住的双手安稳的放在双腿上,避免出现意料之外的事来。 +       然... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + +
    + + + + + +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/page/3/index.html b/page/3/index.html new file mode 100644 index 0000000000..ed6bd19507 --- /dev/null +++ b/page/3/index.html @@ -0,0 +1,4315 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    + +
    + + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + 本文转载自:【F444 +の 光荣历史•其二】人物传记·FRC +作者:Lucas2011 +一、简介 +曾就读于东辰「教学8班·行政11班」与我同班(两个都是哦),是我初中阶段最好的朋友。现就读于七林9班,在高中数学竞赛的道路上越走越远。喜好有Minecraft、原和一些神奇的卡牌游戏。有批判性思维,不从众,但是对自己的观点有强烈的自信,不拿出证据证明他是错的的话他绝对不会善罢甘休(但是在学校里证... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + +
    +
    + + + +

    + 3 / 3 +

    + +
    + + + + +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/picinfo/banners/index.html b/picinfo/banners/index.html new file mode 100644 index 0000000000..4a45929af9 --- /dev/null +++ b/picinfo/banners/index.html @@ -0,0 +1,4269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 网站Banner信息 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + + + + + + +
    +
    +

    1

    +

    +

    图片地址:这里

    +

    崩坏·星穹铁道 流萤 游戏内截图

    +

    2

    +

    +

    图片地址:这里

    +

    崩坏·星穹铁道 花火 游戏内截图

    +

    3

    +

    +

    图片地址:这里

    +

    崩坏·星穹铁道 流萤&星 游戏内截图

    +

    4

    +

    +

    图片地址:这里

    +

    原神 芙宁娜 同人原创作品

    +

    5

    +

    +

    图片地址:这里

    +

    原神 芙宁娜 同人原创作品

    +

    6

    +

    +

    图片地址:这里

    +

    虚拟歌姬Vocaloid 初音未来·雪 同人原创作品

    +

    画师:Lunami

    +

    Pixiv:雪·月 PID:65261833

    +

    7

    +

    +

    图片地址:这里

    +

    虚拟歌姬Vocaloid 初音未来 同人原创作品

    +

    画师:Bison倉鼠

    +

    Pixiv:ネズミク PID:79008828

    +

    8

    +

    +

    图片地址:这里

    +

    崩坏·星穹铁道 符玄 同人原创作品

    +

    9

    +

    +

    图片地址:这里

    +

    崩坏·星穹铁道 停云&驭空 同人原创作品

    +

    10

    +

    +

    图片地址:这里

    +

    画师:AutoINS

    +

    Pixiv(从左至右):もう、そんなに見つめないでよ;二ヤ一;見て見て~

    +

    PID(从左至右):112244258;113354064;112841548

    +

    11

    +

    +

    图片地址:这里

    +

    画师:AutoINS

    +

    Pixiv(从左至右):✌️;二ヤ一;いい~疲れた~なぁ~

    +

    PID(从左至右):111148418;113354064;111548585

    + + +
    + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/picinfo/index.html b/picinfo/index.html new file mode 100644 index 0000000000..6671a9da15 --- /dev/null +++ b/picinfo/index.html @@ -0,0 +1,4219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 网页图片信息 索引 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    + + + + + + + + + + + +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/qexo-deploy/index.html b/qexo-deploy/index.html new file mode 100644 index 0000000000..da7d9abacb --- /dev/null +++ b/qexo-deploy/index.html @@ -0,0 +1,4381 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Hexo云后台——Qexo搭建教程 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + +
    + + + +
    + + + + +
    +
    +

    在开始之前,首先你需要有一个自己的域名(github.io不算在内,你必须能够亲自更改DNS解析设置),并在博客仓库设置的Pages选项卡中绑定自己的域名。

    +

    部署Qexo环境

    +

    官方提供了四种方式来部署Qexo环境,其中一种允许你在本地进行部署,另外三种各自使用了不同网站提供的免费数据库服务。综合考虑操作便捷性和成功率,这里选用Vercel提供的免费PostgreSQL服务进行部署。

    +

    首先点击这里进入Vercel的仓库克隆界面。建议新建一个私有仓库进行Qexo仓库的克隆工作,第一次操作时你需要授权Vercel登录你的Github账号,在新跳出的浏览器窗口里按顺序授权即可。

    +

    设置好仓库名称后,点击Create创建,下边会有一个Deploy界面。Vercel在创建和更改仓库时会自动进行一次部署,因此创建完毕后部署将会自动启动,并且这第一次部署是一定会失败的。因为Qexo所依赖的数据库还没有配置。因此点击网页左上角的三角形符号,或者点这里快捷进入你的项目管理页面。不出意外的话,界面将是这个样子:

    +

    +

    (我这里是已经配置好了Qexo)

    +

    然后我们开始配置PostgreSQL数据库,在Storage界面可以申请,点击右上角Create Database并选择Postgres,Vercel的免费Postgre数据库仅限创建一个,如果你先前没有配置过——点击Continue进入数据库连接配置,在Connect界面选择地区为Washington DC或者USA (east)。创建完毕后,在Storage选项卡里选择进入你创建的数据库配置界面。在左侧边栏点击Project,接着点击Connect Project

    +

    +

    选择自己想要部署Qexo的仓库即可,接着回到项目管理界面,点击部署用的仓库。在Settings里面选择Domains域名选项,添加自己购买的域名。注意不要将域名指向到主页地址,如果你购买的主域名是abcd.xyz,此处建议绑定到它的子域名admin.abcd.xyz,而不能直接绑定到abcd.xyz!

    +

    当你添加了一个目标域名后,Vercel会自动对填入的域名进行DNS检查,若第一次配置,大概率会出现以下情况:

    +

    +

    此时你需要打开自己域名的DNS解析设置,添加一个A解析:主机记录为@,记录值为76.76.21.21。补充一句,这个IP地址指向vercel.app的域名服务器,然而这个域名已经处于DNS污染的状态,无法访问。Vercel的临时备用方案是将IP改成76.223.126.88,事实证明到现在这个方案还是有效的。

    +

    配置完部署域名后,转到顶端选项卡Deployment中点击Redeploy开始二次部署。一般等待一分钟左右无报错信息即可完成部署。

    +

    如果你使用的是MongoDB,有可能在二次部署开始三到四分钟后接收到部署失败的信息。如果失败信息里出现了类似于handshake failed的握手失败信息时,建议放弃该方法(很可能是国内墙掉了MongoDB的连接接口导致部署时无法访问)并转而使用上边介绍的PostgreSQL法重新部署。

    +

    查看其他部署具体步骤,见官方文档——部署;若部署时遇到报错,可以进入官方文档——常见问题排错。

    +

    初始化Qexo

    +

    Github配置

    +

    部署完毕后,切换到绑定的域名,本例中我们转到admin.abcd.xyz。如果没有出现Qexo的初始化配置界面,试着转到admin.abcd.xyz/init/。如果你使用Hexo,并在Github上托管,在Github的配置界面,你会看到这几项:

    +

    +

    (这是已经配置好的Qexo的设置界面,只是我将填写的内容删去了,但是项目是完全一致的)

    +

    Github密钥这一项,你需要在Github设置中申请。右上角选择Generate New Token,有两个选项,选择classic。接着完成身份验证。改变如下几项:

    +

    +

    Note必填,作为这个token的使用目的;Expiration是生效期限,安全起见建议设置一个较短的期限,然后定时重置,重新配置Qexo设置,这里我选择的是永久有效;在下边的生效条目里,保证repo下的复选框全部勾选,建议同时勾选workflow,但官方不建议给出所有权限。这么做的目的是保证Qexo有足够权限访问Github +API从而在线修改Github博客源码的内容。

    +

    申请完毕后复制下来,出于安全,Github仅在token初次创建完毕后给出复制选项,所以尽快保存,并填入初始化界面的“Github +密钥”文本框中。

    +

    然后在Github里新建仓库,用于存放博客源码。接着在本地转到你的博客源码文件夹中(就是你执行hexo clean & hexo g & hexo d的文件夹),右键点击git bash here,依次键入以下的代码:

    +
      +
    1. (“查看”里勾选“显示隐藏的文件”后,若源码目录下没有名为.git的文件夹,有则跳过该步骤)git init
    2. +
    3. 复制仓库的网页地址,例:https://github.com/<username>/<repo>
    4. +
    5. 输入git remote add <name> https://github.com/<username>/<repo>.git(这里的<name>任取,但保证先前未创建过,且不与已经存在的<name>重复,否则将可能不会上传当前的文件夹)
    6. +
    7. 输入git pull <name> mastermaster可更改,但保证和新建仓库的主branch同名
    8. +
    9. 输入git add .(注意有个点)
    10. +
    11. 输入git commit -m "Commit内容"(内容可更改,但需要用半角双引号包裹起来)
    12. +
    13. 输入git push <name> mastermaster保持前后一致即可)
    14. +
    +

    如果是第一次上传,按顺序执行以下七步操作;如果已经上传过了,想要提交一些个人的更改,执行第四到第七步即可。“Github +仓库”这一项就填刚刚创建并上传的源码仓库,格式是<username>/<repo>(例:mynameisabcd/BlogSourceCode)。

    +

    “项目分支”填源代码仓库的主要分支,一般是master;“博客路径”留空即可。

    +

    若使用Gitlab,或者想要通过本地进行初始化,见官方文档

    +

    Vercel配置

    +

    “VERCEL_TOKEN”一项,需要在这里生成。

    +

    +

    同样是填写token名称、生效范围(这里选择xxx's projetcs)和生效期限(建议期限短些)。完毕后点击Create生成密钥,也是需要尽快复制下来,粘贴到“VERCEL_TOKEN”里。

    +

    “PROJECT_ID”则需要回到Vercel对应的项目的Settings里,在General选项卡中向下翻到Project ID并复制内容,粘贴到PROJECT_ID中就完成Vercel配置了。

    +

    接下来你还需要设置管理员账号密码,设置完毕后就可以从admin.abcd.xyz快捷进入管理界面了。

    +

    其他设置

    +

    设置友链

    +

    在博客源码目录里打开命令行,输入hexo new page links创建友链页面,打开source/links/index.md,将front-matter修改成如下格式:

    +
    1
    2
    3
    4
    ---
    layout: friends # 必须
    title: 我的朋友们 # 可选,这是友链页的标题
    ---
    +

    并且在front-matter后的正文部分直接粘贴:

    +
    1
    2
    3
    4
    5
    <div id="qexo-friends"></div>
    <link rel="stylesheet" href="https://unpkg.com/qexo-friends/friends.css"/>
    <script src="https://unpkg.com/qexo-static@1.6.0/hexo/friends.js"></script>
    <script>loadQexoFriends("qexo-friends", "Qexo部署的网址")</script>

    +

    需要更改“Qexo部署的网址”为你方才Vercel设置里填写的域名。

    +

    部分主题有专门的主题适配选项,详情见这里

    +

    设置说说

    +

    在Hexo源代码根目录里新建页面hexo new page talks

    +

    source/talks/index.md中正文部分加入:

    +
    1
    2
    3
    4
    5
    <div id="qexot"></div>
    <script src="https://unpkg.com/qexo-static@1.6.0/hexo/talks.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/qexo-static@1.6.0/hexo/talks.css">
    <script>showQexoTalks("qexot", "Qexo部署的网址", 5)</script>

    +

    同样是更改“Qexo部署的网址”,网址后的数字代表每页展示的说说个数,可根据需要自行调整。还可以美化样式

    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +
    + + +
    +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/tags/C/index.html b/tags/C/index.html new file mode 100644 index 0000000000..3618972c1a --- /dev/null +++ b/tags/C/index.html @@ -0,0 +1,4318 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:C# - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + 开发初衷 +Phigros玩得太烂了(确信) +啊作为一名中学生最重要的还得是学习!学习为重是吧。想着开发一个C#窗口程序练练手,顺便涉足一下OpenGL图像渲染的领域。挺重要的一点是感觉自己还是太闲了,再加上PC端音游实在太少喽。就萌生了这个想法。 +图形环境 +整体基于C#的.NET窗体程序,搭配OpenGL进行图形渲染和绘制。OpenGL本身调用起来比较麻烦,涉及很多底层操作(类似于C/C++... + + +
    + +
    +
    + + + + + + + + + 开发记录 + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/tags/CSP-J/index.html b/tags/CSP-J/index.html new file mode 100644 index 0000000000..ec69e6eea1 --- /dev/null +++ b/tags/CSP-J/index.html @@ -0,0 +1,4314 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:CSP-J - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + +
    + + CSP-J 2023 游记 + +
    + + + +

    + +

    + +
    + + + 又名:《第一次考就被小学生薄纱的一集》 +本次考场:绵阳东辰国际学校 +第一节    赛前准备 +       插一句:CSP-J +2023没有设置赛前试机环节(包括CSP-S,成都绵阳都这样),个人推测可能是由于开放自选Windows和Linux系统带来的结果。如果你听见诸如:不要操作电脑,违者将作作弊处理 +的话时,请将你按捺不住的双手安稳的放在双腿上,避免出现意料之外的事来。 +       然... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/tags/DC-Doujin/index.html b/tags/DC-Doujin/index.html new file mode 100644 index 0000000000..b5c50bfcaf --- /dev/null +++ b/tags/DC-Doujin/index.html @@ -0,0 +1,4382 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:DC Doujin - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + + + +
    +
    + + + + + + +
    + + DC Doujin 2023 EP1 一触即发正式发布 + +
    + + + +

    + +

    + +
    + + + + + + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + DC Doujin 2023 EP1 先行预告 + +
    + + + +

    + +

    + +
    + + + DC Doujin +2023,点击访问。 +DC Doujin将在11月带来他的第一部视频作品“一触即发 A Cusp Before It +Rings”。这个视频,对日常学校干饭的情景进行真实再现。其中由木稿比你铁饰演的受伤学生受到热烈关注,其原型是初中部的一位学生,我们将其镜头化,力求最真实地表现出其强烈的反差感。 +禁止用于商业用途,转载请注明出处 DC +Doujin。 +Copyright ... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/DCD\345\220\214\344\272\272/index.html" "b/tags/DCD\345\220\214\344\272\272/index.html" new file mode 100644 index 0000000000..0c2b914e3a --- /dev/null +++ "b/tags/DCD\345\220\214\344\272\272/index.html" @@ -0,0 +1,4382 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:DCD同人 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + + + +
    +
    + + + + + + +
    + + DC Doujin 2023 EP1 一触即发正式发布 + +
    + + + +

    + +

    + +
    + + + + + + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + DC Doujin 2023 EP1 先行预告 + +
    + + + +

    + +

    + +
    + + + DC Doujin +2023,点击访问。 +DC Doujin将在11月带来他的第一部视频作品“一触即发 A Cusp Before It +Rings”。这个视频,对日常学校干饭的情景进行真实再现。其中由木稿比你铁饰演的受伤学生受到热烈关注,其原型是初中部的一位学生,我们将其镜头化,力求最真实地表现出其强烈的反差感。 +禁止用于商业用途,转载请注明出处 DC +Doujin。 +Copyright ... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/tags/OI/index.html b/tags/OI/index.html new file mode 100644 index 0000000000..47ac11902a --- /dev/null +++ b/tags/OI/index.html @@ -0,0 +1,4383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:OI - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + +引入 +如果说数论是数学体系中专门用来研究数字性质的一个分支,那么初等数论则是对整数的性质进行系统性的探讨与研究。千万不要因为其中的“初等”二字小瞧这初等数论尽管名称和学习难度上都没有高等数论那么有逼格,就像初等数学之于高数,数论的所有内容均筑基于此。其中欧几里得证明的算数基本定理(一切合数都可被分解为有限个质数的乘积)在质数筛、GCD(以及LCA)计算、无理数证明等问题上均有用武之地。可以... + + +
    + +
    +
    + + + + + + + + + oi算法 + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 常用算法模板 + +
    + + + +

    + +

    + +
    + + + 1. Trie树(字典树) +123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051#include <bits/stdc++.h>#define N 10010using namespace std;int son[N][70], idx = 0, ... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/tags/dp/index.html b/tags/dp/index.html new file mode 100644 index 0000000000..8a0ebe8eef --- /dev/null +++ b/tags/dp/index.html @@ -0,0 +1,4318 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:dp - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + +
    + + 闫氏DP 学习笔记 + +
    + + + +

    + +

    + +
    + + + 说在前面 +本博客中“闫氏DP”指的是2011年NOI金牌保送北京大学计算机系的算法选手闫学灿(yxc/y总)在教授动态规划时提出的“从集合角度分析DP问题的思维方式”。并非指代某类动态规划题型、也不是某种求解动态规划的固定算法。该文章仅作“闫氏DP”的学习笔记,一并附上例题的个人理解。为了使文章生动有趣,后文使用“yxc”或“y总”指代闫学灿本人。 +代码均经过本人实际测试AC后才给出,代码总... + + +
    + +
    +
    + + + + + + + + + oi算法 + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/tags/index.html b/tags/index.html new file mode 100644 index 0000000000..cc4346dd3f --- /dev/null +++ b/tags/index.html @@ -0,0 +1,4091 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 所有标签 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/tags/latex/index.html b/tags/latex/index.html new file mode 100644 index 0000000000..f70eba5711 --- /dev/null +++ b/tags/latex/index.html @@ -0,0 +1,4327 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:latex - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + Part1. 运算符 +Div1. 基本运算 +加号:,键盘上有 +减号:,键盘上有 +乘号(叉乘): \times +乘号(数量积/点乘): +\cdot +除号: \div +开方/N次方根: +\sqrt[N]{ABC} +乘方/N次幂: +A^N +下标: A_N +分数: +\frac{A}{B} +等于号:,键盘上有 +约等号: +\approx 加粗 +\thickapprox +不等号: +\neq +恒等号/定... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/tags/oi/index.html b/tags/oi/index.html new file mode 100644 index 0000000000..31a7a5d1c2 --- /dev/null +++ b/tags/oi/index.html @@ -0,0 +1,4552 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:oi - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + + + + + + + +
    +
    + + + + + + +
    + + 闫氏DP 学习笔记 + +
    + + + +

    + +

    + +
    + + + 说在前面 +本博客中“闫氏DP”指的是2011年NOI金牌保送北京大学计算机系的算法选手闫学灿(yxc/y总)在教授动态规划时提出的“从集合角度分析DP问题的思维方式”。并非指代某类动态规划题型、也不是某种求解动态规划的固定算法。该文章仅作“闫氏DP”的学习笔记,一并附上例题的个人理解。为了使文章生动有趣,后文使用“yxc”或“y总”指代闫学灿本人。 +代码均经过本人实际测试AC后才给出,代码总... + + +
    + +
    +
    + + + + + + + + + oi算法 + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + 题目传送门:P10178 +受到了题面的启发,我才想起那个早已死去的算法——SPFA +题面总结成一句话就是:最短路只能有一条。 +那么我们用最短路算法:如果有最短路,先选择最短路。如果在更新最短值时出现了冲突——即某两种方案路径长度相等时,让后来者考虑加上一个 + +范围内的值,使它变长、不再是最短路(退出奖牌争夺)就好了。 +对于加上的正整数值,不妨从 +开始加。不够就加上 ,还不够就加上 +,以... + + +
    + +
    +
    + + + + + + + + + 题解 + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + 何为分块 +分块,正如其名,将一个整区间分为若干小区间进行操作。分块拥有比线段树更强的泛用性,但是时间复杂度略输一筹;分块代码更加直观、减少理解难度,但是时间复杂度稍逊风骚;分块的代码比线段树更短,但是时间复杂度惜败后者……线段树所上下传递的操作计算必须满足结合律,区间平均数、方差还行,像计算区间众数、中位数这样的问题,线段树就只能被薄纱了…… +考虑到树状数组理解难度较大、较难调试,一般都选用... + + +
    + +
    +
    + + + + + + + + + oi算法 + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + +诗曰: +“高数第一杀手,考试一考就寄。复数知识一用,算成正一。朴素演算善后,死磕公式何必?考场信心十足,全错当场暴毙。” + +前置知识:复数、位运算 +Part1. 快速傅里叶变换 +Div1. 世界上最优雅的算法 +FFT起源 +FFT的前身是DFT,可以简单看作是一堆OIer争先恐后对DFT算法进行优化的结果。美苏冷战期间,双方都对自己的核实力有所隐瞒,就等着某一天用自己的核导弹打对方个措手不及... + + +
    + +
    +
    + + + + + + + + + oi算法 + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/tags/qexo/index.html b/tags/qexo/index.html new file mode 100644 index 0000000000..f9370b2a20 --- /dev/null +++ b/tags/qexo/index.html @@ -0,0 +1,4319 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:qexo - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + +
    + + Hexo云后台——Qexo搭建教程 + +
    + + + +

    + +

    + +
    + + + 在开始之前,首先你需要有一个自己的域名(github.io不算在内,你必须能够亲自更改DNS解析设置),并在博客仓库设置的Pages选项卡中绑定自己的域名。 +部署Qexo环境 +官方提供了四种方式来部署Qexo环境,其中一种允许你在本地进行部署,另外三种各自使用了不同网站提供的免费数据库服务。综合考虑操作便捷性和成功率,这里选用Vercel提供的免费PostgreSQL服务进行部署。 +首先点击... + + +
    + +
    +
    + + + + + + + + + 博客搭建 + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\344\274\240\350\256\260/index.html" "b/tags/\344\274\240\350\256\260/index.html" new file mode 100644 index 0000000000..9b7f2bb43e --- /dev/null +++ "b/tags/\344\274\240\350\256\260/index.html" @@ -0,0 +1,4310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:传记 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + 本文转载自:【F444 +の 光荣历史•其二】人物传记·FRC +作者:Lucas2011 +一、简介 +曾就读于东辰「教学8班·行政11班」与我同班(两个都是哦),是我初中阶段最好的朋友。现就读于七林9班,在高中数学竞赛的道路上越走越远。喜好有Minecraft、原和一些神奇的卡牌游戏。有批判性思维,不从众,但是对自己的观点有强烈的自信,不拿出证据证明他是错的的话他绝对不会善罢甘休(但是在学校里证... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\345\210\235\344\270\255\345\220\214\345\255\246/index.html" "b/tags/\345\210\235\344\270\255\345\220\214\345\255\246/index.html" new file mode 100644 index 0000000000..460fe42ccd --- /dev/null +++ "b/tags/\345\210\235\344\270\255\345\220\214\345\255\246/index.html" @@ -0,0 +1,4310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:初中同学 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + 本文转载自:【F444 +の 光荣历史•其二】人物传记·FRC +作者:Lucas2011 +一、简介 +曾就读于东辰「教学8班·行政11班」与我同班(两个都是哦),是我初中阶段最好的朋友。现就读于七林9班,在高中数学竞赛的道路上越走越远。喜好有Minecraft、原和一些神奇的卡牌游戏。有批判性思维,不从众,但是对自己的观点有强烈的自信,不拿出证据证明他是错的的话他绝对不会善罢甘休(但是在学校里证... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\345\211\215\347\253\257/index.html" "b/tags/\345\211\215\347\253\257/index.html" new file mode 100644 index 0000000000..41ddbbbd4b --- /dev/null +++ "b/tags/\345\211\215\347\253\257/index.html" @@ -0,0 +1,4331 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:前端 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + 在此记录我个人对博客的一些个性化改造 +本博客使用的Volantis(版本 6.0.0 alpha +1)改造版主题已Fork原主题: + +原主题仓库 +Fork + + +前端类 +刷新式Banner +对视差滚动插件进行改造,将原先的定时更换变为了刷新更换,以减少窗口重获焦点后重复加载图片的问题。 +在这里查看本网站的Banner信息 +OJ网站题目标签 +添加了常用OJ网站(洛谷、AcWing)的题目难度标签... + + +
    + +
    +
    + + + + + + + + + 博客搭建开发记录 + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\345\215\232\345\256\242/index.html" "b/tags/\345\215\232\345\256\242/index.html" new file mode 100644 index 0000000000..be163ec3a8 --- /dev/null +++ "b/tags/\345\215\232\345\256\242/index.html" @@ -0,0 +1,4408 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:博客 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + 在此记录我个人对博客的一些个性化改造 +本博客使用的Volantis(版本 6.0.0 alpha +1)改造版主题已Fork原主题: + +原主题仓库 +Fork + + +前端类 +刷新式Banner +对视差滚动插件进行改造,将原先的定时更换变为了刷新更换,以减少窗口重获焦点后重复加载图片的问题。 +在这里查看本网站的Banner信息 +OJ网站题目标签 +添加了常用OJ网站(洛谷、AcWing)的题目难度标签... + + +
    + +
    +
    + + + + + + + + + 博客搭建开发记录 + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + Hexo云后台——Qexo搭建教程 + +
    + + + +

    + +

    + +
    + + + 在开始之前,首先你需要有一个自己的域名(github.io不算在内,你必须能够亲自更改DNS解析设置),并在博客仓库设置的Pages选项卡中绑定自己的域名。 +部署Qexo环境 +官方提供了四种方式来部署Qexo环境,其中一种允许你在本地进行部署,另外三种各自使用了不同网站提供的免费数据库服务。综合考虑操作便捷性和成功率,这里选用Vercel提供的免费PostgreSQL服务进行部署。 +首先点击... + + +
    + +
    +
    + + + + + + + + + 博客搭建 + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\345\216\237\347\245\236/index.html" "b/tags/\345\216\237\347\245\236/index.html" new file mode 100644 index 0000000000..091785e26f --- /dev/null +++ "b/tags/\345\216\237\347\245\236/index.html" @@ -0,0 +1,4380 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:原神 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + + + +
    +
    + + + + + + +
    + + 一命已出,前来还愿 + +
    + + + +

    + +

    + +
    + + + + +2023.11.11 21:10 + + + + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 《原神》枫丹语言考究 + +
    + + + +

    + +

    + +
    + + + 起因 +这天月假,当我正为即将到来的水神池子疯狂做任务屯原石时,在列表里看到了一个悬赏整整30原石的世界任务。本着不放过任何一个给原石的任务的宗旨,我来到了秋分山西侧,白淞镇东北方向的海边房屋处。只见一位男子全身掩埋在海沙之下、动弹不得,面前摆放着一只散发香味的甜甜花酿鸡。我看他精神失常,满嘴都是“新型美容方式”的胡话又哭又闹,呜呜呜呜,好可怜呀。于是我决定帮他一把……找出了幕后黑手,此时他举... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\345\220\216\347\253\257/index.html" "b/tags/\345\220\216\347\253\257/index.html" new file mode 100644 index 0000000000..4dce723da3 --- /dev/null +++ "b/tags/\345\220\216\347\253\257/index.html" @@ -0,0 +1,4408 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:后端 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + 在此记录我个人对博客的一些个性化改造 +本博客使用的Volantis(版本 6.0.0 alpha +1)改造版主题已Fork原主题: + +原主题仓库 +Fork + + +前端类 +刷新式Banner +对视差滚动插件进行改造,将原先的定时更换变为了刷新更换,以减少窗口重获焦点后重复加载图片的问题。 +在这里查看本网站的Banner信息 +OJ网站题目标签 +添加了常用OJ网站(洛谷、AcWing)的题目难度标签... + + +
    + +
    +
    + + + + + + + + + 博客搭建开发记录 + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + Hexo云后台——Qexo搭建教程 + +
    + + + +

    + +

    + +
    + + + 在开始之前,首先你需要有一个自己的域名(github.io不算在内,你必须能够亲自更改DNS解析设置),并在博客仓库设置的Pages选项卡中绑定自己的域名。 +部署Qexo环境 +官方提供了四种方式来部署Qexo环境,其中一种允许你在本地进行部署,另外三种各自使用了不同网站提供的免费数据库服务。综合考虑操作便捷性和成功率,这里选用Vercel提供的免费PostgreSQL服务进行部署。 +首先点击... + + +
    + +
    +
    + + + + + + + + + 博客搭建 + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\345\233\275\347\245\257/index.html" "b/tags/\345\233\275\347\245\257/index.html" new file mode 100644 index 0000000000..c96bc40608 --- /dev/null +++ "b/tags/\345\233\275\347\245\257/index.html" @@ -0,0 +1,4313 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:国祯 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + +
    + + 国祯文集 + +
    + + + +

    + +

    + +
    + + + 曾茂华到底有多六 +——By 国祯 +曾茂华是中国当代著名的科学家和教育家,他以“慈父”、“良师”、“学者”等称号闻名于世。 +1:曾茂华的蠢行为 +曾茂华的蠢行为: +他在大学期间参加了一个乐队,并担任主唱。然而,不幸的是,由于自己的疏忽,他犯下了一件愚蠢的事情——用刀砍掉了对方的手指头。这件事让他成了学校里的头号人物之一。从那以后,他再也不敢做任何愚蠢的事情了。这是因为他害怕自己会被开除出乐队或者... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\345\255\246\344\271\240\347\254\224\350\256\260/index.html" "b/tags/\345\255\246\344\271\240\347\254\224\350\256\260/index.html" new file mode 100644 index 0000000000..687cad7d3b --- /dev/null +++ "b/tags/\345\255\246\344\271\240\347\254\224\350\256\260/index.html" @@ -0,0 +1,4318 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:学习笔记 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + +
    + + 闫氏DP 学习笔记 + +
    + + + +

    + +

    + +
    + + + 说在前面 +本博客中“闫氏DP”指的是2011年NOI金牌保送北京大学计算机系的算法选手闫学灿(yxc/y总)在教授动态规划时提出的“从集合角度分析DP问题的思维方式”。并非指代某类动态规划题型、也不是某种求解动态规划的固定算法。该文章仅作“闫氏DP”的学习笔记,一并附上例题的个人理解。为了使文章生动有趣,后文使用“yxc”或“y总”指代闫学灿本人。 +代码均经过本人实际测试AC后才给出,代码总... + + +
    + +
    +
    + + + + + + + + + oi算法 + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\345\255\246\346\234\257/index.html" "b/tags/\345\255\246\346\234\257/index.html" new file mode 100644 index 0000000000..6aa78bfd88 --- /dev/null +++ "b/tags/\345\255\246\346\234\257/index.html" @@ -0,0 +1,4827 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:学术 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + +诗曰: +“高数第一杀手,考试一考就寄。复数知识一用,算成正一。朴素演算善后,死磕公式何必?考场信心十足,全错当场暴毙。” + +前置知识:复数、位运算 +Part1. 快速傅里叶变换 +Div1. 世界上最优雅的算法 +FFT起源 +FFT的前身是DFT,可以简单看作是一堆OIer争先恐后对DFT算法进行优化的结果。美苏冷战期间,双方都对自己的核实力有所隐瞒,就等着某一天用自己的核导弹打对方个措手不及... + + +
    + +
    +
    + + + + + + + + + oi算法 + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 线性代数 简明教程 二 + +
    + + + +

    + +

    + +
    + + + pandoc测试自动部署 + + + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 约瑟夫环——春晚魔术表演原理解析 + +
    + + + +

    + +

    + +
    + + + +(操作没成功の尴尬,图片来自知乎) +前言 +这篇文章从数学方面推导刘谦2024年央视春晚上表演的第二个魔术的秘密、分析尼格买提错误之处,并在已知信息的加持下尝试推测尼格买提手上所剩的两张半面扑克牌的牌型。有一说一撒贝宁是真的会测假 +对应魔术节目:《守岁共此时》的回看请戳这里,在一小时十分整处。 +魔术步骤 + +四张牌面向下,并打乱。 +对折四张牌,并沿折痕撕开,得到两批半牌,每批四个共八个半牌 +(... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 线性代数 简明教程 一 + +
    + + + +

    + +

    + +
    + + + +线性代数 简明教程 +前言 + + + 前言正文 + + + + 我个人认为我自己与线性代数的渊源是极深的。差不多整一年之前,初三上册的寒假,我在启动某二字二次元风格开放世界游戏时偶然做到了一个世界解谜。与平常无脑过的难度不同,这次的解谜可谓是充满血和汗水的教训——看攻略前千万要搞清楚站位和朝向……于是一步错步步错,耗费了整整半个小时才碰巧还原到原始的... + + +
    + +
    +
    + + + + + + + + + 自学的数学 + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 2023年度总结——机房管理软件的破解经验 + +
    + + + +

    + +

    + +
    + + + +文中提到的核心程序代码及食用方法在文章末尾处,或者访问我的云剪贴板来复制代码 +更新条目的链接 +极域——世界上最弱小最单纯的机房软件 +注意,极域由C/C++语言开发。对于极域的反编译工作可以基本认定为徒劳且耗费大量时间的。 +开始的开始,我的脱控方式还仅限于最原始的taskkill和ntsd。这种做法不仅有时会失效,而且一旦老师发现你的机子的监控屏幕是纯黑一片、且无法控制,他就会气急败坏地冲向... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + +引入 +如果说数论是数学体系中专门用来研究数字性质的一个分支,那么初等数论则是对整数的性质进行系统性的探讨与研究。千万不要因为其中的“初等”二字小瞧这初等数论尽管名称和学习难度上都没有高等数论那么有逼格,就像初等数学之于高数,数论的所有内容均筑基于此。其中欧几里得证明的算数基本定理(一切合数都可被分解为有限个质数的乘积)在质数筛、GCD(以及LCA)计算、无理数证明等问题上均有用武之地。可以... + + +
    + +
    +
    + + + + + + + + + oi算法 + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 《原神》枫丹语言考究 + +
    + + + +

    + +

    + +
    + + + 起因 +这天月假,当我正为即将到来的水神池子疯狂做任务屯原石时,在列表里看到了一个悬赏整整30原石的世界任务。本着不放过任何一个给原石的任务的宗旨,我来到了秋分山西侧,白淞镇东北方向的海边房屋处。只见一位男子全身掩埋在海沙之下、动弹不得,面前摆放着一只散发香味的甜甜花酿鸡。我看他精神失常,满嘴都是“新型美容方式”的胡话又哭又闹,呜呜呜呜,好可怜呀。于是我决定帮他一把……找出了幕后黑手,此时他举... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 常用算法模板 + +
    + + + +

    + +

    + +
    + + + 1. Trie树(字典树) +123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051#include <bits/stdc++.h>#define N 10010using namespace std;int son[N][70], idx = 0, ... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\345\274\200\345\217\221\350\256\260\345\275\225/index.html" "b/tags/\345\274\200\345\217\221\350\256\260\345\275\225/index.html" new file mode 100644 index 0000000000..3af58f99f4 --- /dev/null +++ "b/tags/\345\274\200\345\217\221\350\256\260\345\275\225/index.html" @@ -0,0 +1,4407 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:开发记录 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + 在此记录我个人对博客的一些个性化改造 +本博客使用的Volantis(版本 6.0.0 alpha +1)改造版主题已Fork原主题: + +原主题仓库 +Fork + + +前端类 +刷新式Banner +对视差滚动插件进行改造,将原先的定时更换变为了刷新更换,以减少窗口重获焦点后重复加载图片的问题。 +在这里查看本网站的Banner信息 +OJ网站题目标签 +添加了常用OJ网站(洛谷、AcWing)的题目难度标签... + + +
    + +
    +
    + + + + + + + + + 博客搭建开发记录 + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + 开发初衷 +Phigros玩得太烂了(确信) +啊作为一名中学生最重要的还得是学习!学习为重是吧。想着开发一个C#窗口程序练练手,顺便涉足一下OpenGL图像渲染的领域。挺重要的一点是感觉自己还是太闲了,再加上PC端音游实在太少喽。就萌生了这个想法。 +图形环境 +整体基于C#的.NET窗体程序,搭配OpenGL进行图形渲染和绘制。OpenGL本身调用起来比较麻烦,涉及很多底层操作(类似于C/C++... + + +
    + +
    +
    + + + + + + + + + 开发记录 + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\346\220\254\350\277\220/index.html" "b/tags/\346\220\254\350\277\220/index.html" new file mode 100644 index 0000000000..6d141adc89 --- /dev/null +++ "b/tags/\346\220\254\350\277\220/index.html" @@ -0,0 +1,4310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:搬运 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + 本文转载自:【F444 +の 光荣历史•其二】人物传记·FRC +作者:Lucas2011 +一、简介 +曾就读于东辰「教学8班·行政11班」与我同班(两个都是哦),是我初中阶段最好的朋友。现就读于七林9班,在高中数学竞赛的道路上越走越远。喜好有Minecraft、原和一些神奇的卡牌游戏。有批判性思维,不从众,但是对自己的观点有强烈的自信,不拿出证据证明他是错的的话他绝对不会善罢甘休(但是在学校里证... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\346\225\231\347\250\213/index.html" "b/tags/\346\225\231\347\250\213/index.html" new file mode 100644 index 0000000000..d0f6d21767 --- /dev/null +++ "b/tags/\346\225\231\347\250\213/index.html" @@ -0,0 +1,4393 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:教程 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + + + +
    +
    + + + + + + +
    + + 线性代数 简明教程 二 + +
    + + + +

    + +

    + +
    + + + pandoc测试自动部署 + + + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 线性代数 简明教程 一 + +
    + + + +

    + +

    + +
    + + + +线性代数 简明教程 +前言 + + + 前言正文 + + + + 我个人认为我自己与线性代数的渊源是极深的。差不多整一年之前,初三上册的寒假,我在启动某二字二次元风格开放世界游戏时偶然做到了一个世界解谜。与平常无脑过的难度不同,这次的解谜可谓是充满血和汗水的教训——看攻略前千万要搞清楚站位和朝向……于是一步错步步错,耗费了整整半个小时才碰巧还原到原始的... + + +
    + +
    +
    + + + + + + + + + 自学的数学 + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\346\225\260\345\255\246/index.html" "b/tags/\346\225\260\345\255\246/index.html" new file mode 100644 index 0000000000..dc75805d8b --- /dev/null +++ "b/tags/\346\225\260\345\255\246/index.html" @@ -0,0 +1,4548 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:数学 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + +诗曰: +“高数第一杀手,考试一考就寄。复数知识一用,算成正一。朴素演算善后,死磕公式何必?考场信心十足,全错当场暴毙。” + +前置知识:复数、位运算 +Part1. 快速傅里叶变换 +Div1. 世界上最优雅的算法 +FFT起源 +FFT的前身是DFT,可以简单看作是一堆OIer争先恐后对DFT算法进行优化的结果。美苏冷战期间,双方都对自己的核实力有所隐瞒,就等着某一天用自己的核导弹打对方个措手不及... + + +
    + +
    +
    + + + + + + + + + oi算法 + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 线性代数 简明教程 二 + +
    + + + +

    + +

    + +
    + + + pandoc测试自动部署 + + + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 约瑟夫环——春晚魔术表演原理解析 + +
    + + + +

    + +

    + +
    + + + +(操作没成功の尴尬,图片来自知乎) +前言 +这篇文章从数学方面推导刘谦2024年央视春晚上表演的第二个魔术的秘密、分析尼格买提错误之处,并在已知信息的加持下尝试推测尼格买提手上所剩的两张半面扑克牌的牌型。有一说一撒贝宁是真的会测假 +对应魔术节目:《守岁共此时》的回看请戳这里,在一小时十分整处。 +魔术步骤 + +四张牌面向下,并打乱。 +对折四张牌,并沿折痕撕开,得到两批半牌,每批四个共八个半牌 +(... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 线性代数 简明教程 一 + +
    + + + +

    + +

    + +
    + + + +线性代数 简明教程 +前言 + + + 前言正文 + + + + 我个人认为我自己与线性代数的渊源是极深的。差不多整一年之前,初三上册的寒假,我在启动某二字二次元风格开放世界游戏时偶然做到了一个世界解谜。与平常无脑过的难度不同,这次的解谜可谓是充满血和汗水的教训——看攻略前千万要搞清楚站位和朝向……于是一步错步步错,耗费了整整半个小时才碰巧还原到原始的... + + +
    + +
    +
    + + + + + + + + + 自学的数学 + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\346\225\260\350\256\272/index.html" "b/tags/\346\225\260\350\256\272/index.html" new file mode 100644 index 0000000000..5186bde01a --- /dev/null +++ "b/tags/\346\225\260\350\256\272/index.html" @@ -0,0 +1,4316 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:数论 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + +引入 +如果说数论是数学体系中专门用来研究数字性质的一个分支,那么初等数论则是对整数的性质进行系统性的探讨与研究。千万不要因为其中的“初等”二字小瞧这初等数论尽管名称和学习难度上都没有高等数论那么有逼格,就像初等数学之于高数,数论的所有内容均筑基于此。其中欧几里得证明的算数基本定理(一切合数都可被分解为有限个质数的乘积)在质数筛、GCD(以及LCA)计算、无理数证明等问题上均有用武之地。可以... + + +
    + +
    +
    + + + + + + + + + oi算法 + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\346\225\264\346\264\273/index.html" "b/tags/\346\225\264\346\264\273/index.html" new file mode 100644 index 0000000000..416184a5f0 --- /dev/null +++ "b/tags/\346\225\264\346\264\273/index.html" @@ -0,0 +1,4603 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:整活 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + 开发初衷 +Phigros玩得太烂了(确信) +啊作为一名中学生最重要的还得是学习!学习为重是吧。想着开发一个C#窗口程序练练手,顺便涉足一下OpenGL图像渲染的领域。挺重要的一点是感觉自己还是太闲了,再加上PC端音游实在太少喽。就萌生了这个想法。 +图形环境 +整体基于C#的.NET窗体程序,搭配OpenGL进行图形渲染和绘制。OpenGL本身调用起来比较麻烦,涉及很多底层操作(类似于C/C++... + + +
    + +
    +
    + + + + + + + + + 开发记录 + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 约瑟夫环——春晚魔术表演原理解析 + +
    + + + +

    + +

    + +
    + + + +(操作没成功の尴尬,图片来自知乎) +前言 +这篇文章从数学方面推导刘谦2024年央视春晚上表演的第二个魔术的秘密、分析尼格买提错误之处,并在已知信息的加持下尝试推测尼格买提手上所剩的两张半面扑克牌的牌型。有一说一撒贝宁是真的会测假 +对应魔术节目:《守岁共此时》的回看请戳这里,在一小时十分整处。 +魔术步骤 + +四张牌面向下,并打乱。 +对折四张牌,并沿折痕撕开,得到两批半牌,每批四个共八个半牌 +(... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 2023年度总结——机房管理软件的破解经验 + +
    + + + +

    + +

    + +
    + + + +文中提到的核心程序代码及食用方法在文章末尾处,或者访问我的云剪贴板来复制代码 +更新条目的链接 +极域——世界上最弱小最单纯的机房软件 +注意,极域由C/C++语言开发。对于极域的反编译工作可以基本认定为徒劳且耗费大量时间的。 +开始的开始,我的脱控方式还仅限于最原始的taskkill和ntsd。这种做法不仅有时会失效,而且一旦老师发现你的机子的监控屏幕是纯黑一片、且无法控制,他就会气急败坏地冲向... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 国祯文集 + +
    + + + +

    + +

    + +
    + + + 曾茂华到底有多六 +——By 国祯 +曾茂华是中国当代著名的科学家和教育家,他以“慈父”、“良师”、“学者”等称号闻名于世。 +1:曾茂华的蠢行为 +曾茂华的蠢行为: +他在大学期间参加了一个乐队,并担任主唱。然而,不幸的是,由于自己的疏忽,他犯下了一件愚蠢的事情——用刀砍掉了对方的手指头。这件事让他成了学校里的头号人物之一。从那以后,他再也不敢做任何愚蠢的事情了。这是因为他害怕自己会被开除出乐队或者... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + 本文转载自:【F444 +の 光荣历史•其二】人物传记·FRC +作者:Lucas2011 +一、简介 +曾就读于东辰「教学8班·行政11班」与我同班(两个都是哦),是我初中阶段最好的朋友。现就读于七林9班,在高中数学竞赛的道路上越走越远。喜好有Minecraft、原和一些神奇的卡牌游戏。有批判性思维,不从众,但是对自己的观点有强烈的自信,不拿出证据证明他是错的的话他绝对不会善罢甘休(但是在学校里证... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\346\226\207\347\253\240/index.html" "b/tags/\346\226\207\347\253\240/index.html" new file mode 100644 index 0000000000..6eab9ac2cc --- /dev/null +++ "b/tags/\346\226\207\347\253\240/index.html" @@ -0,0 +1,4313 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:文章 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + +
    + + 国祯文集 + +
    + + + +

    + +

    + +
    + + + 曾茂华到底有多六 +——By 国祯 +曾茂华是中国当代著名的科学家和教育家,他以“慈父”、“良师”、“学者”等称号闻名于世。 +1:曾茂华的蠢行为 +曾茂华的蠢行为: +他在大学期间参加了一个乐队,并担任主唱。然而,不幸的是,由于自己的疏忽,他犯下了一件愚蠢的事情——用刀砍掉了对方的手指头。这件事让他成了学校里的头号人物之一。从那以后,他再也不敢做任何愚蠢的事情了。这是因为他害怕自己会被开除出乐队或者... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\346\226\260\351\227\273/index.html" "b/tags/\346\226\260\351\227\273/index.html" new file mode 100644 index 0000000000..808cce466c --- /dev/null +++ "b/tags/\346\226\260\351\227\273/index.html" @@ -0,0 +1,4382 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:新闻 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + + + +
    +
    + + + + + + +
    + + DC Doujin 2023 EP1 一触即发正式发布 + +
    + + + +

    + +

    + +
    + + + + + + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + DC Doujin 2023 EP1 先行预告 + +
    + + + +

    + +

    + +
    + + + DC Doujin +2023,点击访问。 +DC Doujin将在11月带来他的第一部视频作品“一触即发 A Cusp Before It +Rings”。这个视频,对日常学校干饭的情景进行真实再现。其中由木稿比你铁饰演的受伤学生受到热烈关注,其原型是初中部的一位学生,我们将其镜头化,力求最真实地表现出其强烈的反差感。 +禁止用于商业用途,转载请注明出处 DC +Doujin。 +Copyright ... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\346\236\253\344\270\271/index.html" "b/tags/\346\236\253\344\270\271/index.html" new file mode 100644 index 0000000000..a2f3bcafe0 --- /dev/null +++ "b/tags/\346\236\253\344\270\271/index.html" @@ -0,0 +1,4309 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:枫丹 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + +
    + + 《原神》枫丹语言考究 + +
    + + + +

    + +

    + +
    + + + 起因 +这天月假,当我正为即将到来的水神池子疯狂做任务屯原石时,在列表里看到了一个悬赏整整30原石的世界任务。本着不放过任何一个给原石的任务的宗旨,我来到了秋分山西侧,白淞镇东北方向的海边房屋处。只见一位男子全身掩埋在海沙之下、动弹不得,面前摆放着一只散发香味的甜甜花酿鸡。我看他精神失常,满嘴都是“新型美容方式”的胡话又哭又闹,呜呜呜呜,好可怜呀。于是我决定帮他一把……找出了幕后黑手,此时他举... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\347\224\237\346\264\273/index.html" "b/tags/\347\224\237\346\264\273/index.html" new file mode 100644 index 0000000000..4155b0fdf2 --- /dev/null +++ "b/tags/\347\224\237\346\264\273/index.html" @@ -0,0 +1,4310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:生活 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + 本文转载自:【F444 +の 光荣历史•其二】人物传记·FRC +作者:Lucas2011 +一、简介 +曾就读于东辰「教学8班·行政11班」与我同班(两个都是哦),是我初中阶段最好的朋友。现就读于七林9班,在高中数学竞赛的道路上越走越远。喜好有Minecraft、原和一些神奇的卡牌游戏。有批判性思维,不从众,但是对自己的观点有强烈的自信,不拿出证据证明他是错的的话他绝对不会善罢甘休(但是在学校里证... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\347\240\264\350\247\243/index.html" "b/tags/\347\240\264\350\247\243/index.html" new file mode 100644 index 0000000000..489421bca6 --- /dev/null +++ "b/tags/\347\240\264\350\247\243/index.html" @@ -0,0 +1,4313 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:破解 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + +
    + + 2023年度总结——机房管理软件的破解经验 + +
    + + + +

    + +

    + +
    + + + +文中提到的核心程序代码及食用方法在文章末尾处,或者访问我的云剪贴板来复制代码 +更新条目的链接 +极域——世界上最弱小最单纯的机房软件 +注意,极域由C/C++语言开发。对于极域的反编译工作可以基本认定为徒劳且耗费大量时间的。 +开始的开始,我的脱控方式还仅限于最原始的taskkill和ntsd。这种做法不仅有时会失效,而且一旦老师发现你的机子的监控屏幕是纯黑一片、且无法控制,他就会气急败坏地冲向... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\347\256\227\346\263\225/index.html" "b/tags/\347\256\227\346\263\225/index.html" new file mode 100644 index 0000000000..4e6e52bb5a --- /dev/null +++ "b/tags/\347\256\227\346\263\225/index.html" @@ -0,0 +1,4764 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:算法 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + +
    + + 闫氏DP 学习笔记 + +
    + + + +

    + +

    + +
    + + + 说在前面 +本博客中“闫氏DP”指的是2011年NOI金牌保送北京大学计算机系的算法选手闫学灿(yxc/y总)在教授动态规划时提出的“从集合角度分析DP问题的思维方式”。并非指代某类动态规划题型、也不是某种求解动态规划的固定算法。该文章仅作“闫氏DP”的学习笔记,一并附上例题的个人理解。为了使文章生动有趣,后文使用“yxc”或“y总”指代闫学灿本人。 +代码均经过本人实际测试AC后才给出,代码总... + + +
    + +
    +
    + + + + + + + + + oi算法 + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + 何为分块 +分块,正如其名,将一个整区间分为若干小区间进行操作。分块拥有比线段树更强的泛用性,但是时间复杂度略输一筹;分块代码更加直观、减少理解难度,但是时间复杂度稍逊风骚;分块的代码比线段树更短,但是时间复杂度惜败后者……线段树所上下传递的操作计算必须满足结合律,区间平均数、方差还行,像计算区间众数、中位数这样的问题,线段树就只能被薄纱了…… +考虑到树状数组理解难度较大、较难调试,一般都选用... + + +
    + +
    +
    + + + + + + + + + oi算法 + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + +诗曰: +“高数第一杀手,考试一考就寄。复数知识一用,算成正一。朴素演算善后,死磕公式何必?考场信心十足,全错当场暴毙。” + +前置知识:复数、位运算 +Part1. 快速傅里叶变换 +Div1. 世界上最优雅的算法 +FFT起源 +FFT的前身是DFT,可以简单看作是一堆OIer争先恐后对DFT算法进行优化的结果。美苏冷战期间,双方都对自己的核实力有所隐瞒,就等着某一天用自己的核导弹打对方个措手不及... + + +
    + +
    +
    + + + + + + + + + oi算法 + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 线性代数 简明教程 二 + +
    + + + +

    + +

    + +
    + + + pandoc测试自动部署 + + + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 线性代数 简明教程 一 + +
    + + + +

    + +

    + +
    + + + +线性代数 简明教程 +前言 + + + 前言正文 + + + + 我个人认为我自己与线性代数的渊源是极深的。差不多整一年之前,初三上册的寒假,我在启动某二字二次元风格开放世界游戏时偶然做到了一个世界解谜。与平常无脑过的难度不同,这次的解谜可谓是充满血和汗水的教训——看攻略前千万要搞清楚站位和朝向……于是一步错步步错,耗费了整整半个小时才碰巧还原到原始的... + + +
    + +
    +
    + + + + + + + + + 自学的数学 + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + +引入 +如果说数论是数学体系中专门用来研究数字性质的一个分支,那么初等数论则是对整数的性质进行系统性的探讨与研究。千万不要因为其中的“初等”二字小瞧这初等数论尽管名称和学习难度上都没有高等数论那么有逼格,就像初等数学之于高数,数论的所有内容均筑基于此。其中欧几里得证明的算数基本定理(一切合数都可被分解为有限个质数的乘积)在质数筛、GCD(以及LCA)计算、无理数证明等问题上均有用武之地。可以... + + +
    + +
    +
    + + + + + + + + + oi算法 + + + + +
    + + + +
    + +
    + +
    + + + +
    +
    + + + + + + +
    + + 常用算法模板 + +
    + + + +

    + +

    + +
    + + + 1. Trie树(字典树) +123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051#include <bits/stdc++.h>#define N 10010using namespace std;int son[N][70], idx = 0, ... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\350\265\233\345\220\216\346\200\273\347\273\223/index.html" "b/tags/\350\265\233\345\220\216\346\200\273\347\273\223/index.html" new file mode 100644 index 0000000000..4f1e6c8fe7 --- /dev/null +++ "b/tags/\350\265\233\345\220\216\346\200\273\347\273\223/index.html" @@ -0,0 +1,4314 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:赛后总结 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + +
    + + CSP-J 2023 游记 + +
    + + + +

    + +

    + +
    + + + 又名:《第一次考就被小学生薄纱的一集》 +本次考场:绵阳东辰国际学校 +第一节    赛前准备 +       插一句:CSP-J +2023没有设置赛前试机环节(包括CSP-S,成都绵阳都这样),个人推测可能是由于开放自选Windows和Linux系统带来的结果。如果你听见诸如:不要操作电脑,违者将作作弊处理 +的话时,请将你按捺不住的双手安稳的放在双腿上,避免出现意料之外的事来。 +       然... + + +
    + +
    +
    + + + + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git "a/tags/\351\242\230\350\247\243/index.html" "b/tags/\351\242\230\350\247\243/index.html" new file mode 100644 index 0000000000..05debe8860 --- /dev/null +++ "b/tags/\351\242\230\350\247\243/index.html" @@ -0,0 +1,4322 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签:题解 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + + + +
    + + + + + + + + + + +
    +
    + + + + + + + + + + +

    + +

    + +
    + + + 题目传送门:P10178 +受到了题面的启发,我才想起那个早已死去的算法——SPFA +题面总结成一句话就是:最短路只能有一条。 +那么我们用最短路算法:如果有最短路,先选择最短路。如果在更新最短值时出现了冲突——即某两种方案路径长度相等时,让后来者考虑加上一个 + +范围内的值,使它变长、不再是最短路(退出奖牌争夺)就好了。 +对于加上的正整数值,不妨从 +开始加。不够就加上 ,还不够就加上 +,以... + + +
    + +
    +
    + + + + + + + + + 题解 + + + + +
    + + + +
    + +
    + +
    + + + +
    + + + + + + + +
    + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/talks.html b/talks.html new file mode 100644 index 0000000000..9625df924b --- /dev/null +++ b/talks.html @@ -0,0 +1,4252 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 随笔 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    + + + + + + + + + + + +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/thanks/index.html b/thanks/index.html new file mode 100644 index 0000000000..eb9b3e8381 --- /dev/null +++ b/thanks/index.html @@ -0,0 +1,4312 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 一命已出,前来还愿 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + +
    + + + +
    + + + + +
    +
    +
    +2023.11.11 21:10 + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +
    + + +
    +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + diff --git a/yans-dp-learning-notes/index.html b/yans-dp-learning-notes/index.html new file mode 100644 index 0000000000..9675cd59ee --- /dev/null +++ b/yans-dp-learning-notes/index.html @@ -0,0 +1,4613 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 闫氏DP 学习笔记 - JustPureH2O的博客 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    + +
    +
    + + + + + + + +
    + + + +
    + + + + +
    +
    +

    说在前面

    +

    本博客中“闫氏DP”指的是2011年NOI金牌保送北京大学计算机系的算法选手闫学灿(yxc/y总)在教授动态规划时提出的“从集合角度分析DP问题的思维方式”。并非指代某类动态规划题型、也不是某种求解动态规划的固定算法。该文章仅作“闫氏DP”的学习笔记,一并附上例题的个人理解。为了使文章生动有趣,后文使用“yxc”或“y总”指代闫学灿本人。

    +

    代码均经过本人实际测试AC后才给出,代码总耗时也会给出,以AC记录的时间为准。代码由CLion格式化。

    +

    了解动态规划

    +

    了解DP的大佬可以直接看到下一节~

    + +

    传统DP分析法

    +

    DP自诞生之初就用来解决多决策过程问题,解决多决策问题就需要考虑如下性质,这些也是传统动态规划所考虑的角度:

    +
      +
    1. 状态:相当于 +dp[i][j]所表示的意义,各个状态之间有内在的联系
    2. +
    3. 无后效性:第个状态仅由第个状态决定,而不是其他的任何状态
    4. +
    5. 最优子结构:把最优解拆开成一个个小部分,每个组成最优解的部分也一定是最优的
    6. +
    +

    这样的传统方法看起来比较抽象,但这种方法的确是DP问题的标准解法,因为上述几种性质组成一个完整的动态规划问题。自然针对其组成部分提出的解决方案是最为标准的。

    +

    闫氏DP分析法

    +

    +

    这张图(讲课板书)很清晰的阐明了闫氏DP分析法的内核,其中动态规划问题的求解依赖于状态的表示和计算,而搞清楚状态表示又需要读题分析需要规划的总集合、以及问题的属性。这个基本框架在求解DP问题中发挥了极其重要的作用。

    +

    状态计算里有一个非常重要的地方——搞清楚“前驱状态的转移”。就是需要解释清楚当前的状态是怎么由前面一个状态得到的。虽然说起来用不了几个字,但是这也是DP问题的难点,毕竟转移方程是DP问题的灵魂,得到了方程整个问题也就解决了。

    +

    线性DP

    +

    迷宫型 线性DP

    +
    P1216 数字三角形
    +

    题目传送门

    +

    难度:普及-

    +
    +

    观察下面的数字金字塔。

    +

    写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。

    +

    +

    在上面的样例中,从的路径产生了最大权值。

    +
    +

    这个题似乎连读入都要好好想一想

    +

    定义一个二维 map数组,map[i][j]表示第层从左数第个数,所以实际读入的数组输出出来会与上图有一些差别,为了与读入保持一致,使用下面给出的数组进行思考:

    +
    1
    2
    3
    4
    5
    7
    3 8
    8 1 0
    2 7 4 4
    4 5 2 6 5
    +

    我们需要解决的问题的总集合就是从第一层走到第五层的可能路径,而属性就是 +max(最大值)。这些都是读题能找出来的东西。

    +

    接着思考状态表示:摸清楚前驱状态。如果按照正向思维,从上往下遍历(第一次在第一层、第二次在第二层),会有一个问题——不知道前驱状态。那我们就反着来,由最下层向最上层遍历!

    +

    既然向上遍历,我们就脑补一下——把题图里面所有的箭头反向。这样一来上层的总和就可以用下边的点之和来转移了。例如倒数第二层的,表示出来就是 +dp[4][2];它可以用下层的得来,分别对应 dp[5][2]和 +dp[5][3]。推广一下就是 dp[i][j]可以由 +dp[i + 1][j]和 +dp[i + 1][j + 1]得来,结合先前所述的状态表示,得出状态转移方程:dp[i][j] = max(dp[i + 1][j], dp[i + 1][j + 1]) + map[i][j]。那么这个最大和从下边一路推到最上边,到达点(顶点)时显然就是整个问题的解,因此最后输出 +dp[1][1]即可。

    +

    最后是初始化:明显地,dp数组的最后一层应该全部赋值为 +map数组的最后一层,这样才能让整个算法基于金字塔的最底端进行递推,得到正确答案(或者可以直接用 +map数组计算)。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #include <bits/stdc++.h>
    #define N 1010
    using namespace std;

    int dp[N][N], mp[N][N];
    int main() {
    int r;
    cin >> r;
    for (int i = 1; i <= r; i ++) {
    for (int j = 1; j <= i; j ++) {
    cin >> mp[i][j];
    }
    }
    for (int i = 1; i <= r; i ++) dp[r][i] = mp[r][i]; // 初始化最后一层
    for (int i = r - 1; i >= 1; i --) {
    // 反着扫每一层
    for (int j = 1; j <= r - 1; j ++) {
    // 每一列
    dp[i][j] = max(dp[i + 1][j], dp[i + 1][j + 1]) + mp[i][j];
    }
    }
    cout << dp[1][1] << endl;
    return 0;
    }
    +

    由于命名冲突,原文中 map数组实为 +mp数组。

    +

    总用时: 记录

    +
    AcWing1015 摘花生
    +

    原题地址:AcWing1015(原AcWing1017)

    +

    难度:简单

    +

    不知道为什么听课的时候y总说是1017现在变成1015了(但网址还是1017)……可能是题库变动,前面少了两道题吧……

    +
    +

    Hello Kitty想摘点花生送给她喜欢的米老鼠。

    +

    她来到一片有列的网格状道路的矩形花生地(如下图),从西北角进去,东南角出来。

    +

    地里每个道路的交叉点上都有种着一株花生苗,上面有若干颗花生,经过一株花生苗就能摘走该它上面所有的花生。

    +

    Hello Kitty只能向东或向南走,不能向西或向北走。

    +

    问Hello Kitty最多能够摘到多少颗花生。

    +
    +1.gif + +
    +
    +

    这道题属于经典的“走方格最值型线性DP”(自己瞎起的名字),很多DP题目里都有它的影子。例如洛谷 P1176 +路径计数2洛谷 +P1958 上学路线AcWing 1018 +最低通行费

    +

    首先读入整个地图,用数组w存储每个点的花生数(点权)。

    +

    接下来解题:状态表示,读题——总集合是从点(左上角)走到点(右下角)的所有路径,属性则是max

    +

    接下来是状态计算,既然全集是所有合法路径,那我们如何划分这个“合法路径集”呢?

    +

    再读题,它说:“只能向东或向南走”。对应到方向标(上北下南左西右东),那就是只能向右或向下走(不走回头路)一直到右下角。假如她某次移动到了点),那么她可能是从点或者是过来的。既然如此,将两条支路的数据汇集起来,取一个最大值max,不就是整道题的答案吗?因而,状态转移方程就是dp[i][j] = max(dp[i - 1][j] + w[i][j], dp[i][j - 1] + w[i][j]),等价于dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + w[i][j]。由于递推是正向的,到点结束,因此最终输出dp[r][c]

    +

    当我们高高兴兴写代码的时候就会发现一些问题:如果我在第一列(最左边那一列),按照转移方程,左侧的点将会汇入计算,但第一列左侧的点并不存在;同理,第一行(最上边那一行)的上侧的点也不存在。那么该怎么样处理这样的特殊情况呢?

    +

    一般来说,OIer在开数组存值时,会从下标开始——但是在计算机中,一个数组真正的下标从开始。因此可以考虑在第一列和第一行的左侧和上侧点在w数组中设为-INF和负数均可),总之让它们成为“虚点”,对整体结果无实际影响就行。或者在循环中写入特判第一列和第一行的情况,两种方案均可。我选择了比较方便的填充特殊值法,代码在下边给出:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    // 给地图外部的行/列赋特殊值

    #include <bits/stdc++.h>

    #define INF 0x3f3f3f3f
    #define N 110
    using namespace std;

    int dp[N][N], w[N][N];

    int main() {
    int T, r, c;
    cin >> T;
    while (T--) {
    cin >> r >> c;
    for (int i = 1; i <= r; i++) {
    for (int j = 1; j <= c; j++) {
    cin >> w[i][j];
    }
    }
    // 初始化特殊行/列
    for (int i = 0; i <= r; i++) w[0][i] = -INF;
    for (int i = 0; i <= c; i++) w[i][0] = -INF;
    for (int i = 1; i <= r; i++) {
    for (int j = 1; j <= c; j++) {
    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + w[i][j];
    }
    }
    cout << dp[r][c] << endl;
    }
    return 0;
    }
    +

    当然,这道题也可以不填充特殊值,因为全局定义的数组在内存中的默认值就是0,但为了保险这里还是加上了负无穷的填充。

    +

    总用时: 记录

    +
    P1004 方格取数
    +

    题目传送门

    +

    难度:普及+/提高

    +

    来源:NOIp 提高组  2000

    +

    2008年NOIP官方送来的双倍经验,请注意查收P1006 传纸条

    +
    +

    设有 的方格图 ,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 +。如下图所示(见样例):

    +

    +

    某人从图的左上角的 +点出发,可以向下行走,也可以向右走,直到到达右下角的 +点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字 )。 此人从 点到 点共走两次,试找出 +条这样的路径,使得取得的数之和为最大。

    +

    输入的第一行为一个整数 (表示 + +的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的 + 表示输入结束。

    +

    数据范围:

    +
    +

    好家伙,两次DP???我们就选择用一个DP数组记录两条路径,同时遍历寻找最优解,最后输出即可。

    +

    状态表示就很明朗了,全集是两条从点走到点的路径可能性,属性是max。在状态计算方面,我们选用dp[i1][j1][i2][j2]表示第一条路线从走到了当前的;第二条路线从走到了当前的。这样来看,我们就只需要判断路径重合的情况:当时两条路径有可能重合。既然是「有可能」,那也就是说存在误判的情况失手了口牙。这里,y总引入了一个新变量,并使上式中的,如此操作,就可以删去dp数组的,转而用dp[k][i1][i2]表示,移项可得。因为DP操作仅限于这个的方阵中,所以取值范围,最大值就是到达右下角的,因此(严格来说,)。关于的循环应该是从开始一直到才对。

    +

    然后考虑状态之间的转移,就需要找到当前状态和上一个状态之间的联系。dp数组存储了两条路径,第一条路径可能从左侧过来、同时第二条路径也可能从左边过来;第一条从左边来、第二条从上边来;第一条从上边来、第二条从左边来;最后是两条都从上边来的情况。我们显然需要计算出这四种情况的状态后对所有状态联合取最大值,以第一种情况为例:两条都从左边来,那么就是从来的;如果是第二种情况,那么过来、来,该情况写成转移方程就是dp[k][i1][i2] = max(dp[k][i1][i2], dp[k - 1][i1][i2] + w[i1][j1] + w[i2][j2])

    +

    最后是重合路径的问题,当唯一确定,时,,所以,两点重合。所以当循环内出现的情况时直接抛除就好。状态转移方程里面也不能按w[i1][j1] + w[i2][j2]加和而是需要按w[i1][j1]进行累加。注意判断是否都在地图范围内。

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    #include <bits/stdc++.h>

    #define N 15
    using namespace std;

    int dp[2 * N][N][N], w[N][N];

    int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    int n;
    cin >> n;
    int x = 1, y = 1, d = 1;
    while (x || y || d) {
    // 谨防毒瘤数据权值出成0!!!
    // 我也不知道权值会不会是0……保险保险
    cin >> x >> y >> d;
    w[x][y] = d;
    }
    for (int k = 2; k <= 2 * n; k++) { // 注意k的取值范围
    for (int i1 = 1; i1 <= n; i1++) {
    for (int i2 = 1; i2 <= n; i2++) {
    int j1 = k - i1, j2 = k - i2;
    if (1 <= i1 <= n && 1 <= i2 <= n && 1 <= j1 <= n && 1 <= j2 <= n) {
    int val = (i1 == i2) ? w[i1][j1] : w[i1][j1] + w[i2][j2]; // 判断是否重合
    int &current = dp[k][i1][i2]; // 设置引用缩减码量
    current = max(current, dp[k - 1][i1][i2] + val); // 两条都从上边来
    current = max(current, dp[k - 1][i1][i2 - 1] + val); // 第一条从上边来,第二条从左边来
    current = max(current, dp[k - 1][i1 - 1][i2] + val); // 第一条从左边来,第二条从上边来
    current = max(current, dp[k - 1][i1 - 1][i2 - 1] + val); // 两条都从左边来
    }
    }
    }
    }
    cout << dp[2 * n][n][n] << endl;
    return 0;
    }
    +

    总用时: 记录

    +

    来都来了,顺便放一下传纸条的代码,两道题思路是相同的(状态转移方程都不需要改!),但是读入有点恶心,一定注意读入问题!

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    #include <bits/stdc++.h>

    #define N 110
    using namespace std;

    int dp[2 * N][N][N], w[N][N];

    int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    int n, m;
    cin >> n >> m;
    // 注意读入问题
    for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
    int d;
    cin >> d;
    w[i][j] = d;
    }
    }
    for (int k = 2; k <= m + n; k++) { // 注意k的取值范围
    for (int i1 = 1; i1 <= n; i1++) {
    for (int i2 = 1; i2 <= n; i2++) {
    int j1 = k - i1, j2 = k - i2;
    if (1 <= i1 <= n && 1 <= i2 <= n && 1 <= j1 <= m && 1 <= j2 <= m) {
    int val = (i1 == i2) ? w[i1][j1] : w[i1][j1] + w[i2][j2]; // 判断是否重合
    int &current = dp[k][i1][i2]; // 设置引用缩减码量
    current = max(current, dp[k - 1][i1][i2] + val); // 两条都从上边来
    current = max(current, dp[k - 1][i1][i2 - 1] + val); // 第一条从上边来,第二条从左边来
    current = max(current, dp[k - 1][i1 - 1][i2] + val); // 第一条从左边来,第二条从上边来
    current = max(current, dp[k - 1][i1 - 1][i2 - 1] + val); // 两条都从左边来
    }
    }
    }
    }
    cout << dp[m + n][n][n] << endl;
    return 0;
    }
    +

    总用时: 记录

    +

    子序列型 线性DP

    + +
    洛谷 B3637 最长上升子序列 +LIS
    +

    题目传送门:B3637 +最长上升子序列

    +

    难度:普及-

    +

    来源:NOIp 提高组  2004

    +
    +

    这是一个简单的动规板子题。

    +

    给出一个由 个不超过 + +的正整数组成的序列。请输出这个序列的最长上升子序列的长度。

    +

    最长上升子序列是指,从原序列中按顺序取出一些数字排在一起,这些数字是逐渐增大的。

    +
    +

    甚至你有可能都没见过B开头的洛谷题……在题库上端的“入门与面试”选项卡里,你可以找到B开头的题

    +

    在子序列DP的思考中,通常对DP的全集有一个比较跳脱常理的思维,通常让dp[i]作为以a[i]结尾的某类型子序列的最长长度。而子序列问题的状态集合属性也自然而然就是max了。

    +

    那么假设此时DP进行到了第项(),为了得出状态转移方程,我们聚焦到dp[i]的前一项,也就是dp[i - 1]。搞明白在什么情况下dp[i - 1]才能转化为dp[i]。不难发现,解决LIS问题,核心就是保证后一项的数严格大于前一项的数。于是当时,我们就可以将纳入最长子序列的计数中,也就是dp[i] = dp[i - 1] + 1

    +

    对于dp数组初始化,因为每个元素本身就是原序列的一个长度为1的上升子序列,所以必须让dp数组的每个位置都初始化成。在最后,因为我们也不知道以第几个元素为结尾的上升子序列可以取到最大长度,因此我们还需要从头到尾扫一遍取最大值。代码给出:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    #include <bits/stdc++.h>

    #define N 5010
    using namespace std;

    int dp[N], a[N];

    int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= n; i++) dp[i] = 1;
    for (int i = 1; i <= n; i++) {
    for (int j = 1; j < i; j++) {
    if (a[j] < a[i]) dp[i] = max(dp[i], dp[j] + 1);
    }
    }
    int ans = -1;
    for (int i = 1; i <= n; i++) ans = max(ans, dp[i]);
    cout << ans << endl;
    return 0;
    }
    +

    总用时: 记录

    +
    洛谷 P1091 合唱队形
    +

    题目传送门:这里

    +

    难度:普及/提高-

    +
    +

    +位同学站成一排,音乐老师要请其中的 位同学出列,使得剩下的 位同学排成合唱队形。

    +

    合唱队形是指这样的一种队形:设 +位同学从左到右依次编号为 … +,他们的身高分别为 ,则他们的身高满足 … +

    +

    你的任务是,已知所有 +位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

    +

    输入共二行。

    +

    第一行是一个整数 ),表示同学的总数。

    +

    第二行有 +个整数,用空格分隔,第 个整数 +)是第 位同学的身高(厘米)。

    +

    对于全部的数据,保证有

    +

    样例输入

    +
    1
    2
    8
    186 186 150 200 160 130 197 200
    +

    样例输出

    +

    4

    +
    +

    要想出列的人最少,留下的人必须最多!废话

    +

    那么如何保证留下的人最多呢?读题,要求是让整个队形变成先升后降的形式。我们不妨将样例输入进行一次可视化:

    +

    +

    题目想让我们把这张图变成左边上升右边下降的样子,形状酷似山峰,因此我称之为山峰模型。联系到刚才所说,需要让留下的人最多。我们在选择C位同学时就需要注意一下,让他左侧留下的人最多、而不是一定要让最高的站中间。这下就很明朗了,我们先正向(从左至右)做一遍LIS问题,就知道让哪个人站C位可以使得Ta左边的人出列最少。那么还差右边的人,怎么办呢?我们会发现如果将整个序列倒序一下(水平翻转),那么原先的右侧就变为现在的左侧,原先让右侧单调下降,现在就变成了左侧单调上升,也就是和处理左侧同样的思路。于是我们就对原序列跑一遍LIS,再对反向的序列跑一遍LIS。最后统计一下每个点跑两次LIS后结果的总和(对应留下的人的人数),找出总和最大的那个就好了。至此我们已经成功将这个问题转化为两次异向LIS问题了!

    +

    最后有一点小细节,是关于最终结果的。样例输入的原理是将中间那个身高两米(176cm小矮个瑟瑟发抖)的设为C位,让左侧150cm和任意一个186cm、右侧197cm和200cm的人出列(注意是保证严格上升,因此若连续二者身高相等则不计入LIS计数)。答案就是。可以发现中间200cm的同学,正向LIS的结果是、反向LIS的结果是。但是,少了一个人去哪了——这是因为正反向LIS都算入了一次那个两米的同学,根据容斥原理,多算一次,就要减去一次,实际留下的人数是人,答案就是人。

    +

    代码如下:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    #include <bits/stdc++.h>
    #define rev(x) n - x + 1
    #define N 5010
    using namespace std;

    int dp[N], rev_dp[N];
    int a[N];

    int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= n; i++) {
    dp[i] = 1;
    for (int j = 1; j < i; j++) {
    if (a[j] < a[i]) dp[i] = max(dp[i], dp[j] + 1);
    }
    }
    reverse(a + 1, a + n + 1);
    for (int i = 1; i <= n; i++) {
    rev_dp[i] = 1;
    for (int j = 1; j < i; j++) {
    if (a[j] < a[i]) rev_dp[i] = max(rev_dp[i], rev_dp[j] + 1);
    }
    }
    int ans = -1;
    for (int i = 1; i <= n; i++)
    ans = max(ans, dp[i] + rev_dp[rev(i)]);
    cout << n - (ans - 1) << endl;
    return 0;
    }
    +

    总用时: 记录

    +
    洛谷 P2782 友好城市
    +

    题目传送门:这里

    +

    难度:普及/提高-

    +
    +

    有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置各不相同的 + +个城市。北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同。每对友好城市都向政府申请在河上开辟一条直线航道连接两个城市,但是由于河上雾太大,政府决定避免任意两条航道交叉,以避免事故。编程帮助政府做出一些批准和拒绝申请的决定,使得在保证任意两条航道不相交的情况下,被批准的申请尽量多。

    +

    输入第一行,一个整数 ,表示城市数。

    +

    输入第二行到第 +行,每行两个整数,中间用一个空格隔开,分别表示南岸和北岸的一对友好城市的坐标。

    +

    输出仅一行,一个整数,表示政府所能批准的最多申请数。

    +

    样例输入

    +
    1
    2
    3
    4
    5
    6
    7
    8
    7
    22 4
    2 6
    10 3
    15 12
    9 8
    17 17
    4 2
    +

    样例输出

    +
    1
    4
    +

    数据范围

    +
      +
    • 对于 的数据,
    • +
    • 对于 的数据,
    • +
    +
    +

    样例看起来不是那么直观,考试时可以考虑用画图软件增强样例可读性,样例画成图就是下边这样:

    +

    +

    样例输出为,意味着我们需要删去条边,分别是边。为了探寻普遍规律,我们分离部分相交的航道来看一看,寻找相交线与河岸两头编号的规律。

    +

    +

    我将北岸城市所连接的南岸城市的编号以深蓝色字体标在了对应北岸城市的下方,这下就可以看出端倪了:北岸城市从左至右,当底部蓝色数字单调上升时,航线不会交叉;反之若出现破坏单调性的蓝色数字,就代表航线交叉。但这个不完全归纳出来的结论还是欠缺证据支撑,对于北岸城市,编号单调递增,也就是说若航线以北岸城市为起点,那么起点处航线是绝对不会相交的;但是对于整条航线,它在整条河上是连续不断的——比如上图中蓝色数字,表明北四号城市连接了一个很远的南二十二号城市;下一个是北十二号城市,连接南十五号城市。整条航线在河上连续不断,意味着航线总会在河上有一个正对南四~二十二号城市的点,此时当航线出现时,它们总会在某处相交。南岸证明同理。至此就证明了这个单调递增规律的问题,因此我们就想办法把南北岸城市的编号一一对应起来,接着跑一遍LIS,就可以解出答案了。

    +

    这里介绍一下C++的pairpair是一个二元组,在定义时传入第一参数和第二参数的数据类型,类似于vector的定义,它们也用一对尖括号包裹。特定类型的pair,例如pair<int, int>pair<double, double>pair<float, float>等,在sort函数中可以自动按第一参数排序。这里我们选择双intpair来存储南北城市的对应关系。代码如下:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    #include <bits/stdc++.h>

    #define N 200010
    using namespace std;

    typedef pair<int, int> coord;

    int dp[N];
    coord a[N];

    int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i].first >> a[i].second;
    sort(a + 1, a + n + 1);
    for (int i = 1; i <= n; i++) {
    dp[i] = 1;
    for (int j = 1; j < i; j++) {
    if (a[j].second < a[i].second) dp[i] = max(dp[i], dp[j] + 1);
    }
    }
    int res = -1;
    for (int i = 1; i <= n; i++) res = max(res, dp[i]);
    cout << res << endl;
    return 0;
    }
    +

    总用时:TLE 记录

    +

    注意到这里的数据范围:前50%没有问题,重点是后50%,它们的。LIS的时间复杂度是,早T飞了。不过AcWing对应的例题的数据没有洛谷上这么强,在AcWing 1012 +友好城市里可以用LIS代码AC,后者的数据范围是。要想通过洛谷的友好城市,就必须用贪心等其他优化方式将时间复杂度降到对数级别才行……画大饼画大饼

    +
    AcWing 1016 最大上升子序列和
    +

    题目传送门:这里

    +

    难度:简单

    +

    最大上升子序列和,又称MASS(Maxiumum Ascending +Subsequence +Sum)问题。是LIS问题的一种变式,它不再是只局限于上升子序列的最长长度、而是开始关注选定子序列的元素之和。MASS问题其实可以拆分为两个子问题求解,其一是上升子序列问题、其二是最大和问题。上升子序列无需多言,其本质是在循环内加上判断a[j] < a[i]来累加合法解个数。因此,如果想要再融合进最大值问题,我们就需要在状态转移那里改一下代码:考虑到LIS问题的dp数组记录的是合法解的个数,而每次找到一组合法解,答案只会累加;对于MASS问题,每次找到一组合法解,需要累加的是元素本身的权值,特殊情况,单元素组成子序列时,答案就是它本身的权值,因而初始化时需要把dp[i]设置成a[i]才对。

    +

    代码:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    #include <bits/stdc++.h>

    #define N 1010
    using namespace std;

    int dp[N], a[N];

    int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= n; i++) {
    dp[i] = a[i];
    for (int j = 1; j < i; j++) {
    if (a[j] < a[i]) dp[i] = max(dp[i], dp[j] + a[i]);
    }
    }
    int res = -1;
    for (int i = 1; i <= n; i++) res = max(res, dp[i]);
    cout << res << endl;
    return 0;
    }
    +

    总用时: 记录

    +
    AcWing 1010 拦截导弹
    +

    题目传送门:这里

    +

    难度:简单

    +

    来源:NOIp 提高组  1999

    +
    +

    某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

    +

    输入导弹依次飞来的高度,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

    +

    输入仅一行,若干个整数,中间由空格隔开。

    +

    输出包含两行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

    +

    样例输入

    +
    1
    389 207 155 300 299 170 158 65
    +

    样例输出

    +
    1
    2
    6
    2
    +

    保证导弹数量不超过

    +
    +

    同样画图理解样例抽象派画师又要登场喽!

    +

    +

    那么怎么做才是样例输出的解呢?很明显,把207155单独提出来作为一个新系统;剩下的作为一个系统。也就是说最多能拦截除开207155的其他六枚导弹,而新开了一个系统,所以总共是两个系统。

    +

    乍一看这很像一个求解最长单调不上升子序列的问题,但是它居然让我们求出系统的数量,这就很棘手了……所以我们需要一个两头兼顾的方法来解题:

    +

    当我们拿到这个序列,之后只会进行两种操作:第一种是将某个数接到已有的子序列之后、第二种是新开一个子序列。考虑到我们的目标之一是让新开的子序列尽量小,那我们就需要尽可能缩减第二种操作的执行次数——让尽可能多的数被归入子序列中,这样的话我们就需要让插入的数和插入前队尾的数尽可能接近才是,如此会让系统的利用率最大化(如果你是舰长总司令,拿到这种系统,你肯定不会轻易地让它拦截很低的导弹,这样只会降低系统利用率)。当然,我们也希望打头的元素尽量大一些,这样才会容纳进更多的元素。诶?这不就是贪心的思路吗?为了方便阅读,做归纳如下:

    +

    贪心过程:从前到后扫描每个数,并且:

    +
      +
    • 如果现有的所有子序列的结尾都小于这个数,显然不能插入,就开新序列(创建新系统)
    • +
    • 如果存在合法(符合题意且当前元素可插入队尾)的子序列,遍历队尾元素,找到和当前元素最相近的那个队尾对应的子序列插入
    • +
    +

    代码:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    #include <bits/stdc++.h>

    #define N 1010
    using namespace std;

    int dp[N], a[N], b[N];

    int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    int n = 1;
    while (cin >> a[n]) n++;
    n--;
    int lis = -1;
    for (int i = 1; i <= n; i++) {
    dp[i] = 1;
    for (int j = 1; j < i; j++) {
    if (a[j] >= a[i]) dp[i] = max(dp[i], dp[j] + 1);
    }
    lis = max(lis, dp[i]);
    }
    int cnt = 0;
    for (int i = 1; i <= n; i++) {
    int tmp = 0;
    while (tmp < cnt && b[tmp] < a[i]) tmp++;
    b[tmp] = a[i];
    if (tmp >= cnt) cnt++;
    }
    cout << lis << endl << cnt << endl;
    return 0;
    }
    +

    总用时: 记录

    +

    补 贪心优化子序列问题

    +

    正常做子序列问题的时候,由于要枚举每一个可能的状态,因此需要循环级别次,时间复杂度也就来到了惊人的(大多数题目的暴力算法都是这个复杂度),当时就TLE了,更别说更加毒瘤的数据了……好在对于最值子序列问题,人们提出了贪心法,可以将复杂度降落到对数级别,一般是(某些题用特定的数据结构还可以降到复杂度)。是一种极其高效的优化方式。

    +

    补 DFS暴搜求解最值问题

    +

    有些时候,就算是贪心也不能解决某些DP的决策问题。转而寻找与普通DP时间复杂度相近的替代方案——DFS暴搜。我们都知道,宽搜BFS常用于求解这类最值问题(尤其是最小步数),是因为BFS的实现基于对图的按层遍历;但是DFS就不太一样了,它不撞南墙不回头、有时还会爆栈(递归过深)……但是面对DP问题这样的一个根节点连巨多子节点的情况,BFS在压入每层节点时也会爆空间,而且DFS剪枝会比较容易……接下来用一个例题详解DFS暴搜的基本原理。

    +
    AcWing 187 导弹防御系统
    +

    题目传送门:这里

    +

    难度:简单

    +
    +

    为了对抗附近恶意国家的威胁,国更新了他们的导弹防御系统。

    +

    一套防御系统的导弹拦截高度要么一直 严格单调 +上升要么一直 严格单调 下降。

    +

    例如,一套系统先后拦截了高度为和高度为的两发导弹,那么接下来该系统就只能拦截高度大于的导弹。

    +

    给定即将袭来的一系列导弹的高度,请你求出至少需要多少套防御系统,就可以将它们全部击落。

    +
    +

    输入包含多组测试用例。

    +

    对于每个测试用例,第一行包含整数,表示来袭导弹数量。

    +

    第二行包含不同的整数,表示每个导弹的高度。

    +

    当输入测试用例时,表示输入终止,且该用例无需处理。

    +
    +

    对于每个测试用例,输出一个占据一行的整数,表示所需的防御系统数量。

    +
    +

    样例输入

    +
    1
    2
    3
    5
    3 5 2 4 1
    0
    +

    样例输出

    +
    1
    2
    +

    样例解释

    +

    对于给出样例,最少需要两套防御系统。

    +

    一套击落高度为的导弹,另一套击落高度为的导弹。

    +

    数据范围

    +

    +
    +

    样例已经解释过了,就不画图了……您的抽象派画师先生已下线

    +

    要么上升要么下降……其实在导弹拦截这里已经介绍过贪心的思路。这道题只是在那道题的基础上,在贪心的外部再加入一个选择上升还是下降的贪心。哦豁,不太好搞了——开局要做一个单选,每个选项下又有选项脑袋抓破,此时试着用高雅的暴戾算法DFS搜索来解决这个DP问题。

    +

    我们的目标是让系统数尽可能少节约开支,在DFS的处理过程中也要贯彻最小值的思想,但正如开头所说,DFS毕竟是不撞南墙不回头的搜索方式,怎么做才能让DFS具备BFS的最小值处理能力呢?有两种方法:记录全局最小值和迭代加深。

    +
    实现方法一 全局记录最值
    +

    设计DFS函数时,引入三个参数:当前点的下标(DFS必备)、以该点结尾最长上升子序列的长度、以该点结尾最长下降子序列的长度。函数签名就像这样:void dfs(int idx, int lis, int lds)(LDSLongest Decreasing +Subsequence,最长下降子序列)。

    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +
    + + +
    +
    + + + + +
    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + +