06 2022 档案

摘要:本题就是从c到a/b再到b/a距离的最大值,显然,a和b分别是树的直径的两个端点,先用两次dfs求出树的直径,再用一次dfs求出每个点到a的距离,最后再用一次dfs求出每个点到距离它较近的a/b的距离,最后以每个节点为c枚举求最大距离即可。 1 #include<bits/stdc++.h> 2 u 阅读全文
posted @ 2022-06-25 16:14 YHXo 阅读(25) 评论(0) 推荐(0) 编辑
摘要:有负边权,所以用树形DP来找树的直径。 1 //树形DP求树的直径 2 #include<bits/stdc++.h> 3 using namespace std; 4 const int N=500005,M=500005; 5 int n,m,tot,ans; 6 int f1[N],f2[N] 阅读全文
posted @ 2022-06-25 15:42 YHXo 阅读(193) 评论(0) 推荐(0) 编辑
摘要:用两次dfs求出树的直径,这两次dfs可以写在一起,当然为了方便理解,这里是分开写的。 1 //两次dfs求树的重心 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 7 con 阅读全文
posted @ 2022-06-25 15:14 YHXo 阅读(32) 评论(0) 推荐(0) 编辑
摘要:这道题考察了树的重心的性质,所有点到中心的距离之和是最小的,所以我们一遍dfs求出树的重心,在跑一次dfs统计距离之和。 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int INF=0x7f7f7f7f; 4 const int 阅读全文
posted @ 2022-06-25 14:44 YHXo 阅读(56) 评论(0) 推荐(0) 编辑
摘要:又是一道模板题...... 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 const int INF=0x7f7f7f7f; 6 const int N=50005; 7 in 阅读全文
posted @ 2022-06-25 14:34 YHXo 阅读(19) 评论(0) 推荐(0) 编辑
摘要:求树的重心的模板题,size[u]维护以u为根的子树大小,f[u]表示去掉u后的最大子树。 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 const int INF=0x7f7 阅读全文
posted @ 2022-06-25 14:18 YHXo 阅读(21) 评论(0) 推荐(0) 编辑
摘要:白嫖的一道省选题...... 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 typedef long long LL; 6 int dig[15],pos; 7 LL dp[ 阅读全文
posted @ 2022-06-25 11:54 YHXo 阅读(20) 评论(0) 推荐(0) 编辑
摘要:dp[i][j]表示以a[i]结尾的长度为j的上升子序列个数。 方程:dp[i][j]=sum(dp[k][j-1]),a[k]<a[i],1<=k<i。 求解目标:sum(dp[k][m]),1<=k<=n。 三层循环枚举的话要超时,观察式子,相当于是统计前缀和,这启示我们可以用到树状数组来优化, 阅读全文
posted @ 2022-06-25 11:41 YHXo 阅读(16) 评论(0) 推荐(0) 编辑
摘要:LIS和LCS的结合。 容易写出方程,复杂度是nm2,但我们可以去掉一层没有必要的枚举,用一个变量val记录前一阶段的最优解,这样优化成nm。 1<=k<j,j增加1,k的上界也增加1,就可以考虑用变量优化去掉一层循环。 1 #include<cstdio> 2 #include<cstring> 阅读全文
posted @ 2022-06-25 11:26 YHXo 阅读(14) 评论(0) 推荐(0) 编辑
摘要:将车票的使用情况用二进制表示状态,对其进行转移即可。 但是我一开始写的代码是错误的(注释部分),看似思路是正确的,但是暗藏很大的问题。 枚举S,我们要求解的是dp[S][v],这个是从u转移过来的,不可以写成dp[S|(1<<i)][v]。这也是一次惨痛的教训...... 1 #include<cs 阅读全文
posted @ 2022-06-25 11:12 YHXo 阅读(20) 评论(0) 推荐(0) 编辑
摘要:又是一道有合法性检测的状压题。 dp[i][j][k]表示第i行状态为j,i-1行状态为k时前i行放置的最大数量。 注意22行统计二进制数中1的个数时的巧妙方法。 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using 阅读全文
posted @ 2022-06-25 09:57 YHXo 阅读(19) 评论(0) 推荐(0) 编辑
摘要:dp[i][j]表示第i行第j个状态时,前i行得到的方案数,该状态可由前一行的状态转移过来。 本题重点在于合法性检测:每一行都用一个二进制数表示,1.二进制数不能有相邻的1;2.要和原地图匹配;3.上下两行不能有冲突。 预处理地图时将0换成1,方便进行2号检测,用位运算&可以实现。 1 #inclu 阅读全文
posted @ 2022-06-25 09:28 YHXo 阅读(21) 评论(0) 推荐(0) 编辑
摘要:题目没有起点限制,且每个节点至少访问1次,最多访问2次,所以用三进制数表示节点的状态(选取情况)。 因为三进制数的每一位是0或1或2,所以预处理z状态S的第j位的数是有必要的。 边界条件:dp[tri[i]][i]=0,表示只访问了i节点时,从i出发最小费用是0。 最后的答案就在所有满足条件的状态中 阅读全文
posted @ 2022-06-25 08:55 YHXo 阅读(22) 评论(0) 推荐(0) 编辑
摘要:本题是经典的Tsp问题的变形,Tsp问题就是要求从起点出发经过每个节点一次再回到起点的距离最小值,本题的区别就是可以经过一个节点不止一次,那么先预处理出任意两点之间的最短距离就行了,因为再多走只会浪费更多的距离。 dp[S][u]表示当前已访问的节点集合为S,从u出发走完剩余节点回到起点的最短距离。 阅读全文
posted @ 2022-06-25 08:24 YHXo 阅读(25) 评论(0) 推荐(0) 编辑
摘要:(如此简短的题目给人一种莫名的压迫感......) 题目中定义一个数的权值求解函数:F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1. 观察可知:权值的表达式与数的位数相关,再加上要分离每个位上的数字,那么就不难想到数位DP了。 dp[po 阅读全文
posted @ 2022-06-24 21:50 YHXo 阅读(15) 评论(0) 推荐(0) 编辑
摘要:用dp[pos][val][cnt]表示状态,pos是数位,val是当前统计的数字,cnt是目前统计的目标数字的出现次数 注意状态的转移过程,统计数字0时前导0的影响。 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 us 阅读全文
posted @ 2022-06-24 21:25 YHXo 阅读(31) 评论(0) 推荐(0) 编辑
摘要:在二进制数上进行数位DP,在dp数组中就记录num0和num1,方便递归到边界时判断该数是否为round number,是则加1。 套用记忆化递归模板: 1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 int dp[40 阅读全文
posted @ 2022-06-24 19:48 YHXo 阅读(14) 评论(0) 推荐(0) 编辑
摘要:和HDU2089差不多,但是本题是求包含某个数的个数,采用代码第15行的方式实现,当然,也可以求不包含的个数,最后用总数减去也可以得到答案。 1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 typedef long lo 阅读全文
posted @ 2022-06-24 19:22 YHXo 阅读(23) 评论(0) 推荐(0) 编辑
摘要:本题是数位DP的入门题,可以用来浅浅了解一下这种强大的计数类工具。 以下代码是采用记忆化递归的写法,效率很高。 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 int a[20] 阅读全文
posted @ 2022-06-24 18:58 YHXo 阅读(13) 评论(0) 推荐(0) 编辑
摘要:dp[u][0]表示u向下走的最大距离; dp[u][1]表示u向下走的次大距离; dp[u][2]表示u向上走的最大距离; 最后的答案就是每个点的max(dp[u][0],dp[u][2]); 求解次大距离并记录idx在求解向上最大距离中是有必要的,可以画图分析。 1 #include<cstdi 阅读全文
posted @ 2022-06-24 18:28 YHXo 阅读(22) 评论(0) 推荐(0) 编辑
摘要:本题属于不定根的树形DP,若以每个节点为根求解一次,复杂度太高,所以可以用换根的技巧。 d[u]表示以u为根向下可以流的最大流量,这个是比较好求的,直接遍历到叶子节点,由子节点信息更新父节点。然后进行第二次遍历,从上往下,子节点的信息由父节点更新。 这就是换根法的基本思路。 本题转移方程还是比较好想 阅读全文
posted @ 2022-06-24 18:07 YHXo 阅读(26) 评论(0) 推荐(0) 编辑
摘要:通过这道题对树形背包理解更深一步...... 有几个地方需要注意: 1.本题数据结构为森林,需增加一个超根作为根节点,M+=1(后面解释)。 2.本题有拓扑序的限制,通过vector建成的一棵树中,必须父节点选择了之后才可以往下选择孩子节点。 3.在以v为根的子树中选择k个节点,k必然小等于v的子树 阅读全文
posted @ 2022-06-18 16:38 YHXo 阅读(24) 评论(0) 推荐(0) 编辑
摘要:一道好题...... 首先要将环形转化为线形结构,接着就是标准的区间DP,但这样的话复杂度为O(n3),n<=1000,要超时,所以要考虑优化。 dp[i][j]=min( dp[i][k]+dp[k+1][j]+sum(i,j) ),我们通过证明sum(i,j)满足四边不等式和区间包含单调性,从而 阅读全文
posted @ 2022-06-18 15:50 YHXo 阅读(24) 评论(0) 推荐(0) 编辑
摘要:fn[i]表示走上第i级台阶的所有走法。 方程:fn[i]=fn[i-1]+fn[i-2]; 1 #include<cstdio> 2 #define MAXN 40 3 using namespace std; 4 typedef unsigned long long LL; 5 LL fn[MA 阅读全文
posted @ 2022-06-18 15:04 YHXo 阅读(27) 评论(0) 推荐(0) 编辑
摘要:每种课程学习不同天数可以获得不同价值,这可以看成一个组,那么题目就是分组背包的模板题了。 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define maxn 105 5 using namespace std; 6 阅读全文
posted @ 2022-06-18 14:56 YHXo 阅读(19) 评论(0) 推荐(0) 编辑
摘要:多重背包就是每种物品有数量限制时求解最大价值。 如果一种物品数量和重量之积超过背包容量,可视为完全背包;其余情况通过二进制拆分,将几个数量的物品看成一个,转化为01背包求解。 按照这种思路代码是这样的: 1 #include<cstdio>//多重背包,二进制拆分 2 #include<cstrin 阅读全文
posted @ 2022-06-18 14:43 YHXo 阅读(31) 评论(0) 推荐(0) 编辑
摘要:完全背包模板,和01背包相比不用倒推,因为一种可以选多个。 这道题求最小,dp数组初始化为无穷即可。 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int M 阅读全文
posted @ 2022-06-18 14:14 YHXo 阅读(55) 评论(0) 推荐(0) 编辑
摘要:01背包模板题。 1维数组倒推。 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define M 1005 6 int dp[M]; 7 int val[M],v[M] 阅读全文
posted @ 2022-06-18 11:59 YHXo 阅读(16) 评论(0) 推荐(0) 编辑
摘要:从每个节点u出发后有两种情况:回到u和不回到u。 dp数组设为三维,第一维是节点编号,第二维是从该节点开始走的步数,第三维1/0 表示是否回到该节点。 可以回到时:dp[u][j][1]=max(dp[u][j][1],dp[u][j-t][1]+dp[v][t-2][1]); 不能回到时,分为两种 阅读全文
posted @ 2022-06-18 11:51 YHXo 阅读(25) 评论(0) 推荐(0) 编辑
摘要:对于每个u要设置三维。 dp[u][0]表示u是服务器,以u为根的最小服务器数,其子节点既可以是,也可以不是,dp[u][0]+=min(d[v][0],d[v][1]); dp[u][1]表示u不是服务器,但他的父节点时,此时u的子节点都不可能是,dp[u][1]+=dp[v][2]; dp[u] 阅读全文
posted @ 2022-06-18 10:52 YHXo 阅读(23) 评论(0) 推荐(0) 编辑
摘要:节点u不放置,其所有子节点都需要放置:节点u放置,子节点既可以放置,又可以不放置,取min。 边界条件:dp[u][0]=0,dp[u][1]=1; 求解目标:min(dp[root][0],dp[root][1]),root是树根。 #include<cstdio> #include<cstrin 阅读全文
posted @ 2022-06-18 10:12 YHXo 阅读(23) 评论(0) 推荐(0) 编辑
摘要:dp[u][0]表示不选u时在以u为根的子树中最大人数,dp[u][1]则是选了u后的最大人数; f[u][0]表示不选u时的唯一性,f[u][1]是选了u后的唯一性,值为1代表唯一,0代表不唯一。 当不选u时,u的子节点v可选可不选,dp[u][0]+=max(dp[v][0],dp[v][1]) 阅读全文
posted @ 2022-06-18 09:44 YHXo 阅读(22) 评论(0) 推荐(0) 编辑
摘要:这道题的妙处在于把原问题看成矩阵连乘问题,求这些矩阵相乘的最小乘法次数,比如一个i*k矩阵乘一个k*j的矩阵,他们的乘法次数就是i*k*j (联想矩阵乘法的三层循环),题目说的取走一张牌,类似于矩阵相乘除去k,所以根据这个条件分析可以联想到矩阵。 题目要求首尾两端不可取,也就是求到最后只剩下一个矩阵 阅读全文
posted @ 2022-06-18 08:52 YHXo 阅读(32) 评论(0) 推荐(0) 编辑
摘要:dp[i]表示要让i向上级发请愿书,最少需要多少个工人递交请愿书,因为要取前T%最小的,所以还要将i的子节点排序(这里用vector实现),取前c个最小的作为dp[i]的值。 这里用dfs可以省去dp数组,用返回值的方式实现。 1 #include<cstdio> 2 #include<cstrin 阅读全文
posted @ 2022-06-18 08:30 YHXo 阅读(24) 评论(0) 推荐(0) 编辑
摘要:很好的区间DP题。 需要注意第一种情况不管是否匹配,都要枚举k来更新答案,比如: “()()()”:dp[0][5]=dp[1][4]+2=4,枚举k,k=1时,dp[0][1]+dp[2][5]=6,最后取最大值6. 第一层d相当于“长度”的含义,第二层枚举i,j就可以用i+d表示,通过这种方式枚 阅读全文
posted @ 2022-06-17 21:18 YHXo 阅读(23) 评论(0) 推荐(0) 编辑
摘要:禁止报的数的生成规则与埃式筛法类似,考虑用筛法预处理可以报出的数字列表和不可报出的数字,从而 O(1) 回答每一组询问。 用check函数判断数字中是否含有7,用nx[i]记录数字i的下一个合法数。 1 #include<bits/stdc++.h> 2 using namespace std; 3 阅读全文
posted @ 2022-06-17 20:58 YHXo 阅读(85) 评论(0) 推荐(0) 编辑
摘要:dp[i][j]表示将字符串子区间[i,j]转化为回文字符串的最小成本。 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<string> 6 #include<iost 阅读全文
posted @ 2022-06-17 19:40 YHXo 阅读(16) 评论(0) 推荐(0) 编辑
摘要:dp[i][j]表示s1[1...i]和s2[1...j]的最长公共子序列。 1 #include <map> 2 #include <set> 3 #include <cmath> 4 #include <queue> 5 #include <cstdio> 6 #include <vector> 阅读全文
posted @ 2022-06-17 18:56 YHXo 阅读(16) 评论(0) 推荐(0) 编辑
摘要:设dp[i]表示以i结尾的最长上升子序列的长度。 dp[i]=max(dp[i],dp[j]+1). 1 #include <map> 2 #include <set> 3 #include <cmath> 4 #include <queue> 5 #include <cstdio> 6 #incl 阅读全文
posted @ 2022-06-17 18:39 YHXo 阅读(16) 评论(0) 推荐(0) 编辑
摘要:支付对应的是多重背包问题,找零对应完全背包问题。 难点在于找上限T+maxv*maxv,可以用鸽笼原理证明,实在想不到就开一个尽量大的数组。 1 #include <map> 2 #include <set> 3 #include <cmath> 4 #include <queue> 5 #incl 阅读全文
posted @ 2022-06-17 18:27 YHXo 阅读(32) 评论(0) 推荐(0) 编辑
摘要:考虑逆推就行了。 1 #include<bits/stdc++.h> 2 using namespace std; 3 int n; 4 int a[1010][1010]; 5 int main(){ 6 scanf("%d",&n); 7 for(int i=1;i<=n;i++) 8 for( 阅读全文
posted @ 2022-06-11 16:51 YHXo 阅读(27) 评论(0) 推荐(0) 编辑
摘要:一道单调队列优化DP的入门题。 f[i]表示到第i头牛时获得的最大效率。 状态转移方程:f[i]=max(f[j-1]-sum[j])+sum[i] ,i-k<=j<=i。j的意义表示断点,因为不能连续安排超过k只牛,肯定要在中间断开一处。 max中f[j-1]-sum[j]只和j相关,我们可以对其 阅读全文
posted @ 2022-06-11 15:49 YHXo 阅读(42) 评论(0) 推荐(0) 编辑
摘要:数据加强了,原来nlogn的复杂度就不行了...... 首先对原来的n个数排序(注意不能用快排),因为值域是1e5,所以可以开桶排序,开两个队列,一个存原来的n个数(已经满足单增),另一队列存两两合并后的数(也是满足单调性的),每次合并从两个队列中选取最小的两个数,合并后放入第二个队列就行了。 更难 阅读全文
posted @ 2022-06-11 14:46 YHXo 阅读(86) 评论(0) 推荐(0) 编辑
摘要:状态表示:dp[i]表示打印前i个单词的最小成本;s[i]维护前缀和。 状态转移:dp[i]=min(dp[j]+(s[i]-s[j])2)+m , 0<=j<i。 换成y=kx+b的形式:dp[j]+s[j]2=2*s[i]*s[j]+dp[i]-s[i]2-m。 算法步骤:1.枚举i=1...n 阅读全文
posted @ 2022-06-11 14:21 YHXo 阅读(26) 评论(0) 推荐(0) 编辑
摘要:【问题描述】 最近,afy决定给TOJ印刷广告,广告牌是刷在城市的建筑物上的,城市里有紧靠着的N个建筑。afy决定在上面找一块尽可能大的矩形放置广告牌。我们假设每个建筑物都有一个高度,从左到右给出每个建筑物的高度H1,H2…HN,且0<Hi<=1,000,000,000,并且我们假设每个建筑物的宽度 阅读全文
posted @ 2022-06-11 09:25 YHXo 阅读(227) 评论(0) 推荐(0) 编辑
摘要:本题的大意就是加最少的边使得图成为边双。 多举例子,画图分析可得:最终答案就是叶子节点(度数为1的点)的个数加1在除以2。 那么我们的目的就转化为找叶子节点: 首先通过tarjan找到割边,再dfs将原图分为几个边双(通过割边划分),缩点,最后统计度数为1的节点个数即可。 1 #include <b 阅读全文
posted @ 2022-06-10 21:55 YHXo 阅读(39) 评论(0) 推荐(0) 编辑
摘要:在本题中很明显,给你一个有向图,要用tarjan缩点。 缩点后,一头牛要受到所有牛的欢迎,那么该点的出度要为0,这是容易证明的:如果该点还有出度,比如a连向b,那么a不受到b的欢迎。所以我们要找出度为0的点,找到后该点中点的个数就是答案。 注意:出度为0的点只能有一个,如果有多个出度为0的点,那么这 阅读全文
posted @ 2022-06-10 21:14 YHXo 阅读(46) 评论(0) 推荐(0) 编辑
摘要:题目简述:一个有向图,求出这个图点数>1的强连通分量的个数。 那么就是tarjan求强联通分量的模板了。 记得要用一个数组标记节点是否在栈中。 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e5+10; 4 int h 阅读全文
posted @ 2022-06-10 19:40 YHXo 阅读(22) 评论(0) 推荐(0) 编辑
摘要:圆方树大致理解:将每个点双看做一个新建的点(方点),该点双内的所有点(圆点)都向新建的点连边,最后形成一棵树,可以给点赋予点权,用以解决相关路径问题。 在本题中,方点点权赋值为该点双的大小,因为两个点双最多有一个交点,将圆点赋为-1来去重,先用tarjan()构建出圆方树,在跑一遍dfs,dfs枚举 阅读全文
posted @ 2022-06-10 19:09 YHXo 阅读(37) 评论(0) 推荐(0) 编辑
摘要:tarjan求割点的模板题。 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e5+10; 4 int head[N],to[N<<1],nxt[N<<1],tot; 5 int dfn[N],low[N],st[N], 阅读全文
posted @ 2022-06-03 14:37 YHXo 阅读(25) 评论(0) 推荐(0) 编辑
摘要:用tarjan变种求割边的模板题 其实还可以求出所有的边双(用栈),但本题不需要求。 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e5+10; 4 int head[N],nxt[N<<1],to[N<<1],tot 阅读全文
posted @ 2022-06-03 11:41 YHXo 阅读(65) 评论(0) 推荐(0) 编辑
摘要:树状数组加差分的应用。(线段树也可以这么用) 1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m; 4 long long t[500005]; 5 int lowbit(int x) {return x&(-x);} 6 7 voi 阅读全文
posted @ 2022-06-03 10:14 YHXo 阅读(18) 评论(0) 推荐(0) 编辑
摘要:这道题看起来像是线段树和最大子段和的结合,但这里求最大子段和不用dp,充分利用线段树递归的优势来处理。个人理解:线段树相当于把求整个区间的最大子段和的问题不断划分为很多个小问题,容易解决小问题,然后递归处理较大的问题(分治),所以这就可以用来解决。 在线段树中,除了左端点,右端点,新开4个域——an 阅读全文
posted @ 2022-06-03 09:56 YHXo 阅读(31) 评论(0) 推荐(0) 编辑
摘要:一道用来练习打标记的好题。 对于区间加和区间赋值两个操作分别用两个标记,分析如何打标记并下传标记(还是比较好分析的)。 坑点:查询操作时,我一开始把ans设为-0x3f3f3f3f(调试了好久才发现),这显然是不对的(看题目的数据设置),将其赋值为-1e18就行了。 代码中注释的内容是另一种打标记的 阅读全文
posted @ 2022-06-02 22:00 YHXo 阅读(120) 评论(0) 推荐(0) 编辑
摘要:变了个花样,在l~r区间加上一个等差数列,等差数列的显著特点就是公差d,我们容易想到用线段树维护差分数组,在l位置加上k,在l+1~r位置加上d,最后在r+1位置减去k+(l-r)*d,这样就是在差分数组上操作,利用线段树打标记容易实现。 最后对于每个查询的位置t,查询1~t的区间和就是t位置上的数 阅读全文
posted @ 2022-06-02 20:11 YHXo 阅读(32) 评论(0) 推荐(0) 编辑

点击右上角即可分享
微信分享提示