![](https://img-blog.csdnimg.cn/20201014180756926.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
Acwing算法基础课笔记
文章平均质量分 75
Acwing算法基础课笔记
刘胖仔学后端
这个作者很懒,什么都没留下…
展开
-
第六章 贪心 区间问题
1、区间选点给定 N 个闭区间 [ai,bi],请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。输出选择的点的最小数量。位于区间端点上的点也算作区间内。输入格式第一行包含整数 N,表示区间数。接下来 N 行,每行包含两个整数 ai,bi,表示一个区间的两个端点。输出格式输出一个整数,表示所需的点的最小数量。数据范围1≤N≤10^5,−10^9≤ai≤bi≤10^9输入样例:3-1 12 43 5输出样例:22、最大不相交区间数量给定 N 个闭原创 2021-11-17 10:06:30 · 509 阅读 · 0 评论 -
第四章 数学知识 博弈论
1、Nim游戏原创 2021-11-11 22:48:59 · 3112 阅读 · 0 评论 -
第四章 数学知识 容斥原理
1、算法思路在组合数学里,集合A1、A2…An均为有限集,则这些集合的元素之和三个集合的情况如下图所示:⋃13Ai=∣A1∣+∣A2∣+∣A3∣−∣A1∩A2∣−∣A1∩A3∣−∣A2∩A3∣+∣A1∩A2∩A3∣\bigcup_1^3Ai=|A1| + |A2|+|A3|-|A1∩A2|-|A1∩A3|-|A2∩A3|+|A1∩A2∩A3|1⋃3Ai=∣A1∣+∣A2∣+∣A3∣−∣A1∩A2∣−∣A1∩A3∣−∣A2∩A3∣+∣A1∩A2∩A3∣2、例题能整除的数给定一个整数 n 和 m原创 2021-11-07 17:16:32 · 146 阅读 · 0 评论 -
第四章 数学知识 卡特兰数
卡特兰数本身是指一个Cn=C2nn1n+1C_n=C_{2n}^n\frac{1}{n+1}Cn=C2nnn+11的数列,但是他经常在组合数学中各种问题的结果出现,所以比较重要。卡特兰数的各种表现形式:1、表现形式12、表现形式23、表现形式31、各种应用dyck wordCn表示长度2n的dyck word的个数。Dyck词是一个有n个X和n个Y组成的字串,且所有的前缀字串皆满足X的个数大于等于Y的个数。以下为长度为6的dyck words:XXXYYY XYXXYY XYX原创 2021-11-04 10:01:10 · 514 阅读 · 0 评论 -
第四章 数学知识 排列组合
求组合数有很多方法,需要根据数据范围去选择不同的方法。Cab=a(a−1)(a−2)....(a−b+1)1∗2∗3∗...∗b=a!b!(a−b)!C_a^b=\frac{a(a-1)(a-2)....(a-b+1)}{1*2*3*...*b}=\frac{a!}{b!(a-b)!}Cab=1∗2∗3∗...∗ba(a−1)(a−2)....(a−b+1)=b!(a−b)!a!1、取模的组合数计算给定 n 组询问,每组询问给定两个整数 a,b,请你输出 Cba mod (1原创 2021-11-03 10:02:31 · 175 阅读 · 0 评论 -
第四章 数学知识 高斯消元法
1、算法思路高斯消元法可用来为线性方程组求解。具体是怎么做的和证明可以去搜索资料,我这里只整理代码的思路。首先定义初等行列变换把某一行的k倍加到另一行把某一行扩大k倍交换两行下面来介绍算法思路我们首先利用初等行列变换,矩阵进行变形(具体变化过程如下)枚举每一列c找到绝对值最大的一行将该行换到最上面将该行第一个数字变成1将下面的所有行的第c列清成0此时观察矩阵,如果是上三角矩阵,证明答案唯一如果出现0=非零的行,则证明答案不存在如果出现0=0的行,则证明答案不唯一.原创 2021-11-01 13:50:06 · 328 阅读 · 0 评论 -
第四章 数学知识 扩展欧几里得算法
1、扩展欧几里得算法已知整数a、b,扩展欧几里得算法可以在求得a、b的最大公约数的同时,能找到整数x、y(其中一个很可能是负数),使它们满足等式ax+by=gcd(a,b)ax+by=gcd(a,b)ax+by=gcd(a,b)ps:这个gcd(a,b)是a和b能凑出来的最小的正整数int exgcd(int a, int b, int &x, int &y){ if(b == 0) { x = 1,y = 0; return a; }原创 2021-10-30 21:20:00 · 221 阅读 · 0 评论 -
第四章 数学知识 快速幂
1、求快速幂首先补充下模运算的基本运算规则$(a + b) % p = (a % p + b % p) % p (1)(a - b) % p = (a % p - b % p ) % p (2)(a * b) % p = (a % p * b % p) % p (3)(a^b) % p = ((a % p)^b) % p (4)快速幂,是为了快速求出形如akmod pa^k mod \ pakmod p的值的问题。其解决思路如下:将k拆解为如下的形式k=20+21+原创 2021-10-29 09:58:15 · 186 阅读 · 0 评论 -
第四章 数学知识 欧拉函数
1、欧拉函数1∼N 中与 N 互质的数的个数被称为欧拉函数,记为 ϕ(N)\phi(N)ϕ(N)。若在算数基本定理中,N=p1k1p2k2p3k3...pnknp_1^{k1}p_2^{k2}p_3^{k3}...p_n^{kn}p1k1p2k2p3k3...pnkn,则有ϕ(N)=N(1−1p1)(1−1p2)...(1−1pn)\phi(N) = N(1-\frac{1}{p_1})(1-\frac{1}{p_2}) ...(1-\frac{1}{p_n})ϕ(N)=N(1−p11)(原创 2021-10-28 00:30:24 · 319 阅读 · 0 评论 -
第四章 数学知识 约数相关
1、求一个数的所有约数使用试除法,如果 n 能整除 d, 则 n 也能整除 n / d,所以只需要遍历1~n\sqrt{n}n即可获得所有约数vector<int> ans;for(int i = 1; i <= n / i; i ++){ if(n % i == 0) { ans.push_back(i); if(i != n / i) ans.push_back(n / i); }}2、求所有约数的个数...原创 2021-10-27 09:34:08 · 84 阅读 · 0 评论 -
第四章 数学知识 质数相关
1、质数判定1. 问题解释所谓质数判定,就是给定一个数,判断一下该数是否为质数。质数(Prime number),又称素数,指在大于1的自然数中,除了1和该数自身外,无法被其他自然数整除的数(也可定义为只有1与该数本身两个正因数的数)。大于1的自然数若不是素数,则称之为合数(也称为合成数)。例如,5是个素数,因为其正约数只有1与5。2.模板代码及注释bool prime(int n){ //如果要判断的数字小于2,根据定义可以直接返回结果。 if(n < 2) return fal原创 2021-10-26 09:47:46 · 557 阅读 · 0 评论 -
第三章 搜索与图论 二分图之二分图的最大匹配问题
1、算法思路1.什么是二分图的最大匹配问题这篇博客讲得非常清楚详细——资料来源匹配:在图论中,一个「匹配」(matching)是一个边的集合,其中任意两条边都没有公共顶点。例如,图 3、图 4 中红色的边就是图 2 的匹配。最大匹配:一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。图 4 是一个最大匹配,它包含 4 条匹配边。2. 使用方法匈牙利算法。我们直接结合例题和代码来看吧,这里我使用的是DFS的方式进行求解。3.小例子对于这样一个二分图,我们来看一下他的最大匹配是多原创 2021-10-21 13:42:48 · 881 阅读 · 0 评论 -
第三章 搜索与图论 二分图之二分图的判定
1、算法思路1. 二分图定义二分图的顶点可以分成两个互斥的独立集 U 和 V 的图,使得所有边都是连结一个 U 中的点和一个 V 中的点。举个例子就是下面的样子。2. 判定思路1.原理一个图是二分图,其充要条件是图中不含奇数环2.判定方法使用染色法。所谓染色法,就是用两种不同的颜色给图中的每个点进行染色,如果能保证同一条边的两个端点颜色不一样,则证明是二分图,否则就不是。下面举两个小例子,第一个例子中,从点1开始染色,与点1相连的两条边要分别染上不同的颜色,可以看到2,4颜色不同,所以不原创 2021-10-21 11:25:51 · 258 阅读 · 0 评论 -
第三章 搜索与图论 最小生成树算法之Kruskal算法
1、算法思路1.解决的问题解决了在图中寻找最小生成树的问题。2.算法流程新建图G,G中拥有原图中相同的节点,但没有边将原图中所有的边按权值从小到大排序从权值最小的边开始,如果这条边连接的两个节点于图G中不在同一个连通分量中,则添加这条边到图G中重复3,直至图G中所有的节点都在同一个连通分量中3.时间复杂度O(MlogM)O(MlogM)O(MlogM),M为边的数量4. 小样例2、例题1. Kruskal算法求最小生成树给定一个 n 个点 m 条边的无向图,图中可能存在重原创 2021-10-20 18:06:40 · 85 阅读 · 0 评论 -
第三章 搜索与图论最小生成树算法之Prim算法
1、算法思路1.用途Prim算法用于搜索图中的最小生成树。(一般都是无向图)2.算法思路从单一顶点开始,普里姆算法按照以下步骤逐步扩大树中所含顶点的数目,直到遍及连通图的所有顶点。输入:一个加权连通图,其中顶点集合为{\displaystyle V}V,边集合为{\displaystyle E}E;初始化:{\displaystyle V_{\text{new}}={x}}{\displaystyle V_{\text{new}}={x}},其中{\displaystyle x}x为集合{\di原创 2021-10-20 16:13:12 · 146 阅读 · 0 评论 -
第三章 搜索与图论 最短路算法之Floyd算法
1、算法思路1.解决的问题Floyd-Warshall算法是解决图中任意两点间的最短路径的一种算法,可以正确处理带负权但不存在负权回路的图的任意两点间最短路径问题。2. 复杂度分析Floyd算法的时间复杂度为O(N3)O(N^{3})O(N3),空间复杂度为O(N2)O(N^2)O(N2)3.2、例题1. Floyd算法求最短路给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,边权可能为负数。再给定 k 个询问,每个询问包含两个整数 x 和 y,表示查询从点 x 到点 y 的最原创 2021-10-19 21:18:05 · 76 阅读 · 0 评论 -
第三章 搜索与图论 最短路算法之SPFA算法
1、算法思路1. 算法适用范围这两个算法用于解决存在负权边的单源最短路问题。其中SPFA算法是Bellman-Ford算法的优化。尽管可以用于负权图中,但是对于存在负权环的图两个算法无法有效工作,但是可以利用这两个算法判断图中是否存在负权环。2.Bellman-Ford算法Bellman-Ford 算法采用动态规划(Dynamic Programming)进行设计,实现的时间复杂度为 O(V*E),其中 V 为顶点数量,E 为边的数量。1.算法流程创建源顶点 v 到图中所有顶点的距离的集合 d原创 2021-10-17 16:24:52 · 166 阅读 · 0 评论 -
第三章 搜索与图论 最短路算法之Bellman-Ford算法
1、算法思路这两个算法用于解决存在负权边的单源最短路问题。尽管可以用于负权图中,但是对于存在负权环的图两个算法无法有效工作,但是可以利用这两个算法判断图中是否存在负权环。Bellman-Ford 算法采用动态规划(Dynamic Programming)进行设计,实现的时间复杂度为 O(V*E),其中 V 为顶点数量,E 为边的数量。1.算法流程创建源顶点 v 到图中所有顶点的距离的集合 distSet,为图中的所有顶点指定一个距离值,初始均为 Infinite,源点距离为 0计算最短路径,执行原创 2021-10-17 11:12:04 · 291 阅读 · 0 评论 -
第三章 搜索与图论 最短路算法之Dijkstra算法
1、算法思路1. 解决的问题Dijkstra算法是基于贪心的一种算法, 其目的是解决正权值图的单源最短路问题。所谓正权值,就是指图中所有边的权值为正,所谓单源最短路就是从某一个起点出发到图中任一个位置的最短路。2. 具体的小例子空说其做法不太直观,不如先看个小例子。初始状态下,除了起点之外,其他所有点到起点的最短距离均设置为正无穷。从所有点中(包括起点)找到一个没有作为距离起点最近的点更新过其他节点的(被标记)并且距离起点最近的点,显然在当前的情况下是起点自己,本例中也就是4号点。利用选出的原创 2021-10-14 13:30:40 · 296 阅读 · 0 评论 -
第三章 搜索与图论 拓扑排序
1、算法思路拓扑排序是对有向无环图的顶点的一种排序,它使得如果存在一条从u到v的一条路径的话,那么在排序中,v一定出现在u的后面。最接近生活的一个例子就是我们修的课程。图片来源我们一定是先修完一门基础课,再去修进阶课程。显然如果图中含有圈,那么拓扑排序一定是不可能的。在实现上我们采用卡恩算法进行实现:卡恩于1962年提出了该算法。简单来说,假设L是存放结果的列表,先找到那些入度为零的节点,把这些节点放到L中,因为这些节点没有任何的父节点。然后把与这些节点相连的边从图中去掉,再寻找图中的入度为零原创 2021-10-12 11:10:26 · 94 阅读 · 0 评论 -
第三章 搜索与图论 DFS和BFS
在这里插入图片描述最短的话 需要边的权重是一样的两个概念 回溯和剪枝回溯一定要注意恢复现场不符合要求的直接回溯,这就叫剪枝树和图的存储无向图可以变成两条有向图add操作vector 稍微差点劲 慢了点有向无环图也被称为拓扑图如果有环的入度一定没有是0的...原创 2021-10-11 10:22:37 · 128 阅读 · 0 评论 -
第二章 数据结构 哈希表及字符串前缀哈希法
1、算法思路1、存储结构这里就不介绍哈希的含义了。按照解决哈希冲突的方法,存储方式分成了两种方法。1.开放寻址法开放寻址法是指,当哈希碰撞发生时,从发生碰撞的那个单元起,按照一定的次序,从哈希表中寻找一个空闲的单元,然后把发生冲突的元素存入到该单元。经验上讲,哈希表的范围要开到数组范围的两到三倍,并且是大于数组范围两到三倍的最小质数,可以比较好的避免冲突。若想将一个元素放进哈希表中,如果当前位置不为空,就去下一个位置看看,如果该位置为空,证明此位置可以存放。删除不是常用的操作,如果需要删除操作的话,原创 2021-10-03 19:48:55 · 245 阅读 · 0 评论 -
第二章 数据结构 堆
1、算法思路如何手写一个堆?需求:建堆可以插入一个数可以求堆中的最小(最大)值可以删除最小值删除任意一个元素修改任意一个元素下面以小根堆为例1.堆的基本性质堆是一个完全二叉树分为大根堆和小根堆。大根堆是指每个节点都大于其左右子节点,小根堆是指每个节点都小于其左右子节点。小根堆的根节点是最小值,大根堆的根节点存储最大值2. 堆的存储对于所有的完全二叉树,都可以使用一个一维数组进行存储。根据上图的关系,就可以把一个完全二叉树用一维数组进行存储。注意这里根节点从1开始计算原创 2021-10-02 13:49:07 · 120 阅读 · 0 评论 -
第二章 数据结构 并查集
1、算法思路并查集要解决的是快速进行下面两个操作将两个集合合并询问两个元素是否在同一个集合中(在近乎O(1)O(1)O(1))的时间复杂度内其基本原理是:每个集合使用一棵树进行表示,树根的编号就是整个集合的编号,每个节点存储的是父节点的编号,p[x]表示x的父节点。有以下三个问题需要处理如何判断树根:if(p[x] == x)如何求x的集合编号:while(p[x] != x) x = p[x];如何合并两个集合:px是x的集合编号,py是y的集合编号。p[x] = y为了提高寻找原创 2021-09-28 10:06:19 · 72 阅读 · 0 评论 -
第二章 数据结构 Tire树
1、算法思路Tire树是用来方便的存储和查找字符串(或者其他类型的数据)的数据结构。一般来说题目会限定好所要求的数据范围,例如小写字母、大写字母等,如果实在过多,可以使用二进制编码进行存储,例如对于所有整数,可以将其二进制表示视为一个字符串进行存储。举一个例子就可以明白Tire的含义,接下来我们展示用Tire存储以下字符串:abcbcabcafgrdood第一个字符串存储如下图:标记上星星代表他是一个完整的字符串。我们继续添加:这样就完成了Tire树的插入,查找也只需要从上到下进原创 2021-09-28 00:22:01 · 183 阅读 · 0 评论 -
第二章 数据结构 单调栈和单调队列
1、算法思路这两个算法的核心思想是:只有那些符合某种单调性的元素才有可能是答案。根据题目要求筛掉那些不符合单调性的元素,在栈中或者队列中存储那些符合某种单调性的元素,并根据题目获得这些元素中的极大值、极小值(位置通常在栈顶、队头、队尾),或者依据单调性,通过二分得到某些元素的值。这样说起来比较抽象,我们下面分别找两个例题进行分析。这两种算法所能处理的题目种类有限,多多积累即可。2、例题分析1、单调栈原题连接:单调栈给定一个长度为 N 的整数数列,输出每个数左边第一个比它小的数,如果不存在则输原创 2021-09-22 01:17:12 · 156 阅读 · 0 评论 -
第二章 数据结构 栈和队列
1、算法思路及模板代码栈是一种先进后出的数据结构队列是一种先进先出的数据结构我们这里使用数组来模拟栈和队列1. 栈下标起始从0或者-1均可,代码稍有变动,下面以0为例//stk表示栈,tt表示栈顶指针int stk[N],tt;//插入int stk[tt ++];//弹出tt --;//判空if(tt > 0) 不空else 空// 栈顶skt[tt];2.队列int q[N],hh,tt = -1;//入队q[++ tt] = x;//出队hh ++;原创 2021-09-20 21:25:59 · 63 阅读 · 0 评论 -
第二章 数据结构 链表和邻接表
1、算法思路这里我们都是使用数组模拟链表,因为对于动态的链表来说,一个个去new太慢了,不利于我们做算法题。原创 2021-09-20 21:05:04 · 470 阅读 · 0 评论 -
第一章 基础算法 KMP算法
1. 算法思路KMP算法,很多同学一开始学起来会比较头疼,其实这个算法的想法还是很直观的,也是比较容易理解的。KMP算法主要是为了实现字符串匹配的功能,也是就给出一个短的字符串和一个长的字符串,使用KMP算法看看长的字符串中是否出现过短的字符串(或者出现过几次、在哪里出现的)。我们结合一个具体例子,首先从暴力做法开始思考。p = "ababc"s = "xababwababc"暴力的做法是这样的,我们首先将两个字符串对齐,从第一个字母开始比较xababwababcababc可以看到,第一原创 2021-09-26 10:31:03 · 127 阅读 · 0 评论 -
第一章 基础算法 区间合并
1、算法思路区间合并是这样一种情形,题目给出了很多区间,部分区间是有交集的,要把有交集的区间进行合并。操作思路是:首先对所有的区间按照左端点进行排序然后维护一个当前区间,左右端点分别是st,ed,不断地对各个区间进行处理其中,当前区间和待处理区间之间有上图中的三种关系,对于情况1,st和ed均无需变化,对于情况2,ed需要变成情况2区间的右端点,而对于情况3,则当前区间变为情况3区间。2、例题 区间合并给定 n 个区间 [li,ri],要求合并所有有交集的区间。注意如果在端点处相交,也原创 2021-09-15 09:58:39 · 181 阅读 · 0 评论 -
第一章 算法基础 整数离散化
1、算法思路这里我们分析的是一种整数、保序的离散化。所谓离散化,是针对这样一种情形。当我们要处理的数组元素的数量极大(有些题目干脆声明为无限大),而我们用到的元素个数很少(例如10510^5105),我们就可以把这些用到的数映射成一个元素较少的数组。也就是将所有用到的数组序号转换成连续的自然数。所谓保序,就是这个元素较少的数组里面元素的先后顺序与原数组是相同的。例如:假设我们只用到 12312312312312312123123123 12312312312312312123123124 两位我们原创 2021-09-15 00:09:21 · 153 阅读 · 0 评论 -
第一章 基础算法 位运算
1、算法思路这里只简单介绍了两种常用的位运算技巧。1.计算一个数的二进制第k位的值先把第k位移到最后一位 n >> k看个位是几 n&1合起来就是这个算法的代码 对于一个数字n其二进制第k位的值为 n >> k & 12.lowbit(x):返回x的最后一位1所代表的值例如x = (10100)2(10100)_2(10100)2,lowbit(x)=(100)2(100)_2(100)2其代码为 lowbit(x) = x &(~x原创 2021-09-12 23:59:25 · 71 阅读 · 0 评论 -
第一章 算法基础 双指针
1、算法思路双指针算法是一种思想。主要可以用来原创 2021-09-12 19:07:30 · 95 阅读 · 0 评论 -
第一章 算法基础 差分
1、算法思路差分其实算是前缀和的一种逆运算,我们从一维差分开始去理解差分的含义。1. 一维差分对于数组A=[a1,a2,...,an]A = [a_1,a_2,...,a_n]A=[a1,a2,...,an]来说,我们可以构造数组B=[b1,b2,...,bn]B= [b_1,b_2,...,b_n]B=[b1,b2,...,bn],使得ai=b1+b2+...+bia_i = b_1 + b_2 + ... + biai=b1+b2+...+bi成立。我们称B数组是A的差分,A是B原创 2021-09-11 17:48:53 · 155 阅读 · 0 评论 -
第一章 算法基础 前缀和
1、算法思路1.一维前缀和对于一个包含元素a1,a2,...,ana_1,a_2,...,a_na1,a2,...,an的数组a,设Si=a1+a2+...+aiS_i = a_1 + a_2 + ... + a_iSi=a1+a2+...+ai,那么SiS_iSi就是[a1,a2,...,ai][a_1,a_2,...,a_i][a1,a2,...,ai]的前缀和。如何求前缀和Si=a1+a2+...+ai=Si−1+aiS_i = a_1 + a_2 + ... + a原创 2021-09-10 09:43:43 · 68 阅读 · 0 评论 -
第一章 基础算法 大整数计算
1、算法思路对于java(有大整数类)和python来说,没有大整数计算的问题,对于c++来说,当一个整数的位数过大就会无法计算。这里我们定义:一个大整数,其长度可以在10610^6106,用大写字母表示一个小整数,其数值小于10910^9109,用小写字母表示。我们讨论四种类型的大整数计算A + BA - BA* aA / a1. 数据存储使用数组存储大整数,将低位放在数组的开始,将高位放在后面,方便进位2. 运算其实就是模拟小学手算的过程。例如对于加法 119 + 11原创 2021-09-07 15:07:54 · 265 阅读 · 0 评论 -
第一章 基础算法 二分
1、算法思路二分算法不仅仅只适用于具有单调性的数组上, 其本质是对于一个数组,左边(右边)符合某条件A,右边(左边)符合某条件B,并且没有元素可以同时满足条件A和条件B,我们都可以通过二分,找到符合条件A的或者B的分界点。二分又可以分成整数二分和浮点数二。对于整数二分,我们可以找到两个分界点,如下图。为了寻找这两个分界点,我们在处理的时候会有不同。而对于浮点数二分,只需要在足够小的区间内任意选取一个点作为分界点。整数二分具体步骤定义check()函数,用来判断某元素是否符合某条件原创 2021-09-06 14:34:05 · 109 阅读 · 0 评论 -
第一章 基础算法 归并排序
1、算法思路归并排序是一种基于分治思想的一种排序方法(下面的讨论均是基于将数组从小到大排序)具体步骤直接从中间位置划分区间成左右两部分 (mid = (l + r) / 2)分别递归两部分区间归并处理左右两部分子区间(使用双指针)2、模板代码以下代码模板参考Acwing//归并所用临时数组int tmp[N];void merge_sort(int q[], int l, int r){ //递归的边界 if(l >= r)return; //1、选原创 2021-09-04 11:13:59 · 74 阅读 · 0 评论 -
第一章 基础算法 快速排序
文章目录1、算法思路2、模板代码1、代码解释2、具体示例3、边界问题分析1. 避免递归时区间无限划分问题2. do i++; while(q[i] < x)和do j--; while(q[j] > x)不能用q[i] <= x 和 q[j] >= x3、为什么要在递归处理的时候,使用(l,j) 和 (j + 1, r)进行递归呢3、 算法复杂度分析1、最坏时间复杂度2、最优时间复杂度3、平均时间复杂度参考资料1、算法思路快速排序是一种基于分治思想的一种排序方法(下面的讨论均是原创 2021-09-03 13:34:16 · 138 阅读 · 0 评论