数据结构作业笔记
题目代码
大部分题目的代码已上传百度网盘。
链接:https://pan.baidu.com/s/1si1K3jh705oBNbNInC2T5w
提取码:dchi
Week1
A
Origin: POJ 1050
题目大意:
给定一个n*n的矩阵,求它的最大子矩阵。n<=100。
解法:
二维前缀和+DP(其实并不算)。
\(O(n^3)\)做法是二重循环枚举子矩阵的上下边界,然后一重循环枚举矩阵的右边界,同时维护之前的前缀和最小值,\(O(1)\)计算出左边界。
B
Origin: POJ 1208
题目大意:
一开始0~n-1个方块并排放在平面上,给出以下一些指令:
- move a onto b: 先将a和b上所有方块归位,然后将方块a放在b的上面。
- move a over b: 先将a上所有方块归位,然后将方块a放在包含方块b的方块堆上。
- pile a onto b: 先将b上所有方块归位,然后将包含方块a的方块堆放在方块b的上面。
- pile a over b: 将包含方块a的方块堆放在包含方块b的方块堆上面。
- quit: 停止所有操作。
保证指令中的a和b不同,且不在同一个方块堆中。n<=25。
解法:
哈希表+无脑模拟。
C
Origin: POJ3106
题目大意:
给定一个m*n(n,m<=300)的矩阵,对其进行q(q<=1e5)次下列操作:
- 沿主对角线转置
- 沿副对角线转置
- 沿垂直中轴线转置
- 顺时针旋转90、180、270度
- 逆时针旋转90、180、270度
求出矩阵的最后结果。
解法:
先开一个二阶方阵,元素赋值为1、2、3、4。然后模拟一遍之后,根据模拟结束之后的情况对m*n的矩阵操作即可。
另外一种做法是找规律,具体不明。
D
Origin: POJ3347
题目大意:
将n(n<=50)个边长不一的正方形以45度角的方式并排放在一个坐标系的左下角,要求输出所有从上往下看所有可见的正方形。
解法:
似乎是玄学模拟。
E
Origin: AtCoder 4243
题目大意:
对于一个金字塔,设塔顶坐标为\((C_x,C_y)\),塔高为\(H\),那么对于任意点\((x,y)\),高度为\(h(x,y)=max(H-|x-C_x|-|y-C_y|,0)\)。
给出n(n<=100)个不重合的点的坐标(0<=x,y<=100,0<=h<=1e9),求塔顶坐标。
限制:塔顶坐标在[0,100]*[0,100]中。
解法:
无脑模拟。枚举所有可能的塔顶坐标,然后对所有的给定坐标,验证是否符合假设。
F
Origin: AtCoder 4876
题目大意:
n(n<=1e5)个人站成一排,每个人要么面向左边,要么面向右边。如果一个人看到的是前面人的背,则定义“他是快乐的”;反之则定义“他是不快乐的”。特别地,如果一个人面前看不到其他人,则“他是不快乐的”。最多可以对这个序列进行k(k<=1e5)次操作,每次操作可以任意指定一个区间,然后将这个区间的所有人进行翻转(包括每个人的朝向)。试在k次操作内将快乐人数最大化。
解法:
结论题。只要有两个不快乐的人,则每次一定能够通过一次操作将其变成快乐的。因此设初始阶段快乐的人为num,则直接输出答案\(min(num+2k,n-1)\)。
Week2
A
Origin: CodeForces 990E
题目大意:
定义一款路灯的照明能力:如果一款路灯被放在坐标\(x\),它能照亮\([x,x+l]\)的区域(注意只能单向照明),那么称这款路灯的照明能力为\(l\)。现在有照明能力1~k共k种路灯,每种路灯的数量无限,且不能同时选取两种路灯。照明能力为\(l\)的单个路灯价格为\(a_l\)。
现在给定一个\([0,n]\)的区间,其中有\(m\)个点是不能放置路灯的。请问怎样放置路灯可以在照亮\([0,n]\)中所有点的同时总花费最小。
\(1\leq k\leq n\leq 10^6,0\leq m\leq n,1\leq a_i\leq 10^6\)
解法:
直接暴力。调和级数分析可知复杂度为\(O(nlogn)\)。
B
Origin: CodeForces 427B
题目大意:
给定一个长度为n(n<=2e5)的序列,求出长度为c的滑动窗口中区间最大值不高于t(t<=1e9)的数目。
解法:
单调队列裸题(当然优先队列也可做)
C
Origin: CodeForces 816B
题目大意:
给定n种配方,第\(i\)种配方要求咖啡的温度介于\([l_i,r_i]\)之间。定义一个温度值是“可接受的”当且仅当它落在至少k个配方的区间内。给出q个询问,第i次询问一个区间\([a_i,b_i]\),表示询问区间中有多少个温度值是可接受的。
\(1\leq k\leq n\leq 2\times 10^5,1\leq q\leq 2\times 10^5\)。
解法:
前缀和处理区间加操作。
先定义一个初始值均为0的数组,每次将\([l_i,r_i]\)的所有元素+1,操作结束之后将所有<k的元素置0,>=k的元素置1,然后求前缀和,询问时O(1)查询。
D
Origin: HDU 5585
题目大意:
给定一个最多30位的十进制数n,询问n是否能被2、3、5中任意一个整除。
解法:
利用小学奥数知识判断即可。
E
Origin: CodeForces 706E
题目大意:
给定一个n*m的矩阵,共有q个操作,每个操作包含6个参数:a,b,c,d,h,w。表示交换左上角坐标为(a,b)和(c,d)的两个h*w的子矩阵。最后输出q次交换之后的结果。
\(2\leq n,m\leq 1000,1\leq q\leq 10^4\)。
解法:
单向十字链表。每个节点创建一个指向它右边节点和下边节点的指针。这样单次交换的复杂度由\(O(nm)\)优化至\(O(n+m)\)。
Week3
A
Origin: CodeForces 898F
题目大意:
给定一个长度为n(n<=1e6)的字符串,用+和=将字符串划分为三块,组成一个等式a+b=c。要求:①a,b,c均没有前导0。②等式成立。
解法:
注意到\(0\leq c.size-max(a.size,b.size)\leq 1\)。因此对于每个字符串,等号位置确定时可能的加号位置最多只有四个。因此枚举等号位置,字符串哈希判断(最好写双哈希)。
B
Origin: CodeForces 961F
这道题我没做……
C
Origin: HDU 1004
题目大意:
多组数据。给出若干个字符串,输出出现个数最多的字符串。保证答案唯一。
解法:
无脑set或者哈希。
D
Origin: HDU 1088
题目大意:
将html语言转换为正常格式。包含以下规则:
- 每行字符个数不超过80。
- 如果读到<br>,换行。
- 如果读到<hr>且当前不在行开头,换行并且打印80个"-"。
解法:
无脑模拟。
E
Origin: HDU 3746
这道题我没做……
F
Origin: HDU 5057
题目大意:
T组数据,给定一个长度为n的序列a,进行m次操作。操作类型如下:
- S X Y:将a[X]的值设为Y。
- Q L R D P:询问在[L,R]中,第D位(个位为第一位)的数字为P的有多少个。
\(1\leq T\leq 50,1\leq n,m\leq 10^5,0\leq a_i\leq 2^{31}-1\)
\(1\leq X\leq N,0\leq Y\leq 2^{31}-1,1\leq L\leq R\leq N\)
\(1\leq D\leq 10,0\leq P\leq 9\)
解法:
分块。b[x][d][p]记录第x个块中第d位数字为p的个数。修改的时候暴力修改。
这道题也可以用线段树/树状数组做,问题在于32MB空间限制。
G
Origin: HDU 5918
题目大意:
给定长度为n的字符串a,长度为m的字符串b和p,求出q的个数,满足\(b_1b_2...b_m=a_qa_{q+p}a_{q+2p}...a_{q+(m-1)p}\)。
解法:
将a拆分为p个串,做p次KMP。
Week4
A
Origin: HDU 4193
题目大意:
给定一个长度为n(n<=1e6)的序列a,询问在a的n个循环移动中有多少个满足a的前缀和序列不小于0。
解法:
将a延长到2n-1,求前缀和,滑动窗口求最小值后和滑动窗口前一个值比较大小。
B
Origin: HDU 4886
题目大意:
给定一个长度为n(n<=1e6)的仅由{A,B,C,D,E,F,G,H}组成的字符串s,求出一个字符串t,满足以下条件:
- t不是s的子串
- t的长度最小
- t的字典序最小
解法:
发现长度为8(或者是9)的由{A,B,C,D,E,F,G,H}组成的字符串个数超过1e6,因此预处理时将s的所有长度小于等于9的字符串哈希,最后枚举子串判断即可。
C
Origin:CodeForces 821C
题目大意:
有一个栈,给定2n(n<=3e5)个进栈和出栈指令,你可以在任意时刻将栈内元素重排,要求使用最少的重排次数使最后出栈序列变为1,2,...,n。
解法:
用栈模拟。如果栈顶元素与出栈序列不符则清空栈(表示把栈内元素排序成符合出栈序列),因此如果退栈时栈为空则表示元素顺序经过重排,忽略即可。
D
Origin: CodeForces 704A
题目大意:
雷神有一个包含n个APP的手机。共有q次事件:
- 第x个APP生成一条未读消息
- 雷神阅读了第x个APP生成的所有消息(包含已读消息)
- 雷神阅读了前t个时间生成的所有消息(包含已读消息)
每次事件之后,要求输出未读消息的总数。
解法:
平衡树赛高!
建立n+1棵平衡树。对于第i次事件的操作1,将值为(i,x)的节点插入root[0]和root[x]中。对于操作2,将root[0]和root[x]中值为(j,x)的节点删除。对于操作3,将root[0]中rnk值小于rnk(t)的所有节点删除,同时删除root[x]中相应节点。
E
Origin: CodeForces 632D
题目大意:
给定一个长度为n(n<=1e6)的序列和一个数m(m<=1e6),要求求出最长子序列s,满足LCM(s)<=m。定义空序列的LCM=1。
解法:
类似线性筛。将num[a[i]*k]++,统计最大值。
Week5
A
Origin: HDU 1576
题目大意:
求\(A/B \pmod {9973}\)。
解法:
高级做法:扩展欧几里得。
中级做法:注意到9973是素数,结合费马小定理\(a^{p-1}\equiv 1\pmod p\),可得\(a^{p-2}\equiv a^{-1}\pmod p\)。转化为快速幂。
低级做法:枚举0~9972。
B
Origin: HDU 4911
题目大意:
给定一个长度为n的序列,支持k次操作,每次可以将任意相邻元素交换。求k次操作后序列的最小逆序对数。
\(1\leq n\leq 10^5,0\leq k\leq 10^9,0\leq a_i\leq 10^9\)。
解法:
大胆猜想,不需证明可以证明只要序列逆序对数不为0,每次总能找到一组相邻元素,交换之后逆序对数-1。因此只需要先求出原序列的逆序对数t,答案为\(max(0,t-k)\)。
求逆序对的方法可以是树状数组,也可以是归并排序。
C
Origin: HDU 5124
题目大意:
T组数据。
给定n条x轴上的线段,第i条线段的左端点横坐标为\(x_i\),右端点横坐标为\(y_i\),覆盖范围为\([x_i,y_i]\)。求x轴上所有点中被线段覆盖层数最多的点被覆盖的次数。
解法:
无脑线段树,可惜空间限制32MB……
正解是将所有端点按坐标排序,如果端点坐标相同则左端点排在前面。枚举所有坐标,如果遇到左端点坐标,计数器+1;右端点计数器-1,在此过程中计数器的最大值就是答案。
D
Origin: HDU 6375
题目大意:
很长很长的中文题面。懒得总结了。建议自行前往原链。
解法:
双端队列板子裸题。注意对deque的rbegin(),rend(),insert()等迭代器和函数的使用。
E
Origin: CodeForces 545D
题目大意:
给定一个n个人的队伍,其中第i个人需要\(t_i\)分钟接受服务。期间后面的人需要等待。如果一个人等待的时间大于他接受服务的时间,他会失望。你的任务是重排队伍,使失望的人尽量的少,输出不失望的人的数量最大值。
解法:
排序,记录等待总时间,如果当前人服务时间大于总时间就服务,否则将它放到最后。
F
Origin: CodeForces 559B
题目大意:
定义两字符串同余。字符串\(a\)和字符串\(b\)同余只需要满足下列条件中的一个:
- \(a=b\)。
- \(a,b\)都可以被分为两个长度相等的子串\(a_1,a_2,b_1,b_2\),且满足\(a_1\equiv b_1,a_2\equiv b_2\)。
- \(a,b\)都可以被分为两个长度相等的子串\(a_1,a_2,b_1,b_2\),且满足\(a_1\equiv b_2,a_2\equiv b_1\)。
给定两个长度不超过\(2\times 10^5\)的小写英文字母串\(a,b\),请问\(a,b\)是否同余。
解法:
将与字符串a同余的所有字符串集称为集合A,利用类似归并排序的思想可以在\(O(nlogn),n=|a|\)的时间里找到A中字典序最小的字符串\(a_m\)。同理找到\(b_m\)之后答案即为\(a_m==b_m\)。
G
Origin: CodeForces 768B
题目大意:
有一个序列,初始时只有一个数n,对于序列中每一个>1的数x,将其拆分成三个数x/2,x%2,x/2并替换原数,重复以上操作直到序列中没有>1的数。询问最后序列中[l,r]有多少个1。
\(0\leq n<2^{50},0\leq r-l\leq 10^5\)。
解法:
注意到序列长度为\(highbit(n+1)-1\)。此外,整个序列有非常良好的递归性质。可以分别计算出[1,l-1]和[1,r]的1的个数,然后相减。(具体看代码)
Week6
A
Origin: AtCoder 4864
题目大意:
给定n件商品,第i件商品的价格为\(a_i\)。Takahashi有m张优惠券,如果使用y张优惠券购买第i件商品,则需要付\(\lfloor \frac{a_i}{2^y}\rfloor\)元。Takahashi需要一件一件地将n件商品全部买下来。请问他该如何分配m张优惠券,使总花费最少?
\(1\leq n,m\leq 10^5,1\leq a_i\leq 10^9\)。
解法:
先将n件商品的价格插入大根堆中,进行m次操作。每次操作将堆顶元素取出,减半后重新插入大根堆中。操作结束后堆中元素之和为答案。
B
Origin: CodeForces 632C
题目大意:
给定n个字符串,第i个字符串为\(a_{i}\),求出一种连接n个字符串的顺序,使连接后的字符串字典序最小。
\(1\leq n\leq 5\times 10^4,1\leq |a_i|\leq 50\)。
解法:
将n个字符串排序。排序依据为:设两个字符串为a,b,如果a+b<b+a,那么a应该排在b的前面。排序完成后,从左到右将字符串连接起来即可。
C
Origin: CodeForces 873D
题目大意:
mergesort的步骤如下:
- 如果当前序列为升序,退出函数。
- 将序列划分为左右子序列。
- 递归对左右子序列分别调用mergesort。
- 对左右序列进行merge操作。
给定n,k,构造一个长度为n的排列,使得用上述mergesort对n进行排序时,调用mergesort的次数刚好为k。如果无法构造输出-1。
\(1\leq n\leq 10^5,1\leq k\leq 2\times 10^5\)。
解法:
显然,当k为偶数时无法构造。先初始化出一个1~n的排列,调用rmerge函数。如果当前k为0则退出函数,否则将a[mid-1]和a[mid]交换(保证交换之后左右子序列依然升序),k自减,递归调用左右子序列的rmerge。
D
Origin: CodeForces 987E
题目大意:
定义一种操作:每次随机挑选一个序列中的两个元素,将其交换。Alex喜欢把一个1n的排列进行7n+1次交换,而Petr喜欢把一个1n的排列进行3n次交换。你得到了一个交换后的排列,请你判断这个排列是谁操作过的。
\(10^3\leq n\leq 10^6\)。
解法:
注意到,每次对序列进行一次操作,必将改变该序列的逆序对数的奇偶性。求出交换后的序列的逆序对数k,结合n和k的奇偶性情况判断。
E
Origin: CodeForces 1017C
题目大意:
给定一个数字n,构造一个n的排列,满足该排列的LIS和LDS长度之和最小。
\(1\leq n\leq 10^5\)。
解法:
注意到在导弹拦截中提及的一个定理:一个序列的最长上升/下降子序列长度等于其反链的最多序列数。换言之,
因此可以构造若干个长度均为i的上升序列,构造方法如下:
\(\{n-i+1,n-i+2,...|n-2i+1,n-2i+2,...|...\}\)
因此块数为\(\lceil \frac ni\rceil\)。
所以有\(i+\lceil \frac ni\rceil\geq i+\frac ni\geq 2\sqrt n\)
所以i取\(\sqrt n\)进行构造即可。
F
Origin: CodeForces 1088B
题目大意:
给定一个长度为n的序列a,要求做m次操作。
一次操作定义为,从序列中找出最小的正整数,记为x,并令序列中所有不为0的数减去x,并输出x。如果序列中全部是0则输出0。
\(1\leq n,m\leq 10^5\)。
解法:
优先队列模拟。每次记录下上次取出的正整数pre,操作开始前先将小根堆中值等于pre的元素全部取出。如果堆空输出0,否则输出堆顶元素x减去pre的值,然后更新pre。
G
Origin: HDU 5696
题目大意:
多组数据。
定义“区间价值”为一段区间的最大值与最小值的积。
给定一个长度为n的序列a,求出对于长度为i的区间,最大价值的区间的区间价值分别是多少。
\(1\leq n\leq 10^5,1\leq a_i\leq 10^9\)。
注意:序列元素值随机
解法:
对于每个待处理区间[l,r],首先找到区间中最小元素的下标x,对于所有跨越x的区间,用two-pointer的方法,从x开始向两边扩展,每次选值更大的一边进行扩展,这样区间最小值是单调的,可以O(1)维护。对于未能跨越x的区间,分治处理。由于数据随机,复杂度为\(O(nlogn)\)。
Week7
A
Origin: AtCoder 2363
题目大意:
如果一个字符串能被等分为两个相同的子串,那么称该字符串为好串。构造一个字符串s,满足以下条件:
- \(1\leq |s|\leq 200\)
- s最多只能由100种字符组成。这100种字符用整数1~100代替。
- 在s的\(2^s\)个子串中,恰有n个好串。
\(1\leq n\leq 10^{12}\)。
解法:
考虑这种构造方法。
假设目前有序列\(x_1,x_2,x_3,x_4,1,2,3,4\),有\(cnt\)个好串。
那么\(x_1,x_2,x_3,x_4,5,1,2,3,4,5\),有\(2cnt+1\)个。
而\(5,x_1,x_2,x_3,x_4,1,2,3,4,5\),有\(cnt+1\)个。
那么考虑递归
B
Origin: CodeForces 598C
题目大意:
给定n个向量的坐标,求出两个向量最小的夹角,输出向量的序号。
\(2\leq n\leq 10^5\)。
解法:
利用atan2(y,x)函数求出向量与x轴的夹角(弧度值),随后排序取最小值。注意判断相等的精度值取1e-25,\(\pi\)的值利用acos(-1)生成。
C
Origin: CodeForces 764C
题目大意:
在一棵n个节点的无根树中,第i个节点被染上了颜色\(c_i\),你需要选择一个点作为根节点,使得这个根节点的所有子节点满足以该子节点为根的子树中所有点颜色均相同。如果能找到输出YES,否则输出NO。
解法:
注意到在所有边中,两端点颜色不同的边只可能是连接根和根的子节点的边。因此枚举所有边,同时统计每个点的异色邻接边数目。如果某个点的异色邻接边数目等于异色邻接边总数,它可以被选为根节点。
D
Origin: HDU 4607
题目大意:
T组数据。
给定一棵n个节点的无根树,共有m个询问,每次询问从任意一个节点出发访问k个节点的最短路径长度是多少。
\(1\leq T\leq 20,1\leq n,m\leq 10^5,1\leq k\leq n\)。
解法:
结论题。设n个节点的无根树的直径为d,则
第一种情况是k较小,足够在树上形成一条链;第二种情况是遍历k个节点的无根树,直径上的边经过了一次,其他边经过了两次。
E
Origin: HDU 4705
题目大意:
给定一棵n个节点的无根树,计算满足以下条件的三元组\((A,B,C)\)的个数:
- \(A,B,C\)是无根树上的节点。
- 不存在一条覆盖\(A,B,C\)三个节点的简单路径。
\(3\leq n\leq 10^5\)。
解法:
考虑问题的反面,即求存在一条覆盖三个节点的简单路径的三元组。这种情况下,必有两个节点是这条简单路径的端点,另外一个点在简单路径中间。因此只需要计算出树上任意两点之间距离之和。这个是可以树形DP的。
具体需要计算出来的量除了以s为根的子树内所有点两两距离之和外,还有一些辅助量:s的size值和以s为根的子树内所有点到根的距离之和。将这些量合理四则运算一下就好了(可以用高中数学推导一下状态转移方程)
F
Origin: POJ 3107
题目大意:
给定一棵n个节点的无根树,需要删除一个节点,让剩下的分支中节点数量最多的分支的节点数尽量少。
\(2\leq n\leq 50000\)。
解法:
按照字面意思树形DP即可。特别地,这样求出来的节点是树的重心。需要计算的辅助量有s的size值。
G
Origin: POJ 3264
题目大意:
给定一个长度为n的序列,支持q次询问,每次询问区间[l,r]上的最大值与最小值的差。
\(1\leq n\leq 50000,1\leq q\leq 2\times 10^5\)。
解法:
RMQ裸题。
Week8
A
Origin: CodeForces 734E
题目大意:
给定一棵n个节点的无根树,每个点为黑色或白色。这棵树支持一种操作,每次操作可以使一个相同颜色的连通块变成另一种颜色,求使整棵树变成一种颜色的最少操作数。
\(1\leq n\leq 2\times 10^5\)。
解法:
将相同颜色的连通块缩为一个点,设新树的直径为d,则答案为\(\lceil \frac d2\rceil\)。
B
Origin: CodeForces 902B
题目大意:
给定一棵n个节点的无根树,每个节点初始条件下颜色为0。这棵树支持一种操作,每次可以选择一棵子树,将其染成同一个颜色。求染成目标状态的最小操作次数。
\(2\leq n\leq 10^4,1\leq c_i\leq n(i=1,2,...,n)\)。
解法:
随便选一个节点为根,从根开始自顶向下染色。如果访问到的节点的颜色与目标颜色相同则不用染色,否则染一次色。
C
Origin: HDU 1130
题目大意:
多组数据。
给定一个数n,求所有不同形态的n个节点的二叉搜索树的个数。
\(1\leq n\leq 100\)。
解法:
卡特兰数。
推导过程:
设答案为\(f(n)\),讨论一下n个节点的二叉搜索树的根节点可能是1,2,..,n。
因此可以得出递推关系:
记忆化搜索即可。注意高精。
D
Origin: HDU 1710
题目大意:
给定一棵n个节点的二叉树的前序、中序遍历。求这颗二叉树的后序遍历。
\(1\leq n\leq 1000\)。
解法:
递归处理即可。先根据前序遍历找到二叉树的根结点编号,然后在中序遍历中找到根节点编号位置,其左边是二叉树的左子树,右边是二叉树的右子树。注意到前序遍历是根-左-右,中序遍历是左-根-右,前序遍历和中序遍历的左子树对应关系存在偏移。因此需要在递归函数中加入一个cur偏移参数,计算位置偏移值。
E
Origin: HDU 2586
题目大意:
T组数据。
给定一棵n个节点的无根边权树,共有m次查询,每次查询节点i与节点j之间的距离。
解法:
随便选一个节点作为根节点,DFS之后计算出每个节点到根节点的距离。随后对于每个查询\((u,v)\),计算出\(LCA(u,v)\),两点距离即为\(dis_u+dis_v-2dis_{LCA(u,v)}\)。
求LCA有很多种方法:
- 倍增LCA
- 将LCA转化为RMQ问题,用ST表解决
- 树链剖分
- Tarjan离线算法
Week9
A
Origin:POJ 3784
题目大意:
读入P(P<=1000)组数据,每组数据为一个长度为n(n<=9999)的序列,要求在读入奇数个数字的时候输出已读入的所有数字中的中位数。
解法:
双堆维护中位数。
具体做法就是定义一个大根堆和小根堆,维护大根堆中装升序序列中前一半的元素,小根堆中装升序序列后一半的元素。定义一个变量mid放中位数。如果两堆元素个数之差大于2(不平衡了),就将mid插入数量少的堆中,将数量多的堆的堆顶元素弹出作为mid。
B
Origin:CodeForces 191C
题目大意:
给定一棵n(n<=2e5)个点的无根树,有k(k<=1e5)个操作,每次操作选取树上两个点u,v,将u到v上所有边权值+1,最后询问n-1条边的权值。
解法:
树链剖分
树上差分。
对于树上修改,可以先开一个数组d[i]。
针对点权的(u,v)操作:
d[u]++;d[v]++;d[lca(u,v)]--;
针对边权的(u,v)操作:
d[u]++;d[v]++;d[lca(u,v)]-=2;
最后点u的真实值为以u为根的子树中所有节点的d值之和。
C
Origin:CodeForces 884D
题目大意:
有n种不同颜色的球,分别给出n种颜色的球的数量。初始情况下这些球按颜色分为n堆,每次可以选取两堆或三堆球,将它们合并为一堆。合并的代价为合并后的球总数。求将n堆球合并为一堆的最小代价。
解法:
和石子合并非常相似。只不过多了三堆合并的选项。容易想到三堆合并相较两堆合并总是更优(一次少掉两堆),然而需要注意,如果不得不进行一次两堆合并(n为偶数),早做比晚做好(小数据验证)。
D
Origin:CodeForces 991C
题目大意:
Vasya有n支蜡烛。他想玩一个游戏,游戏的流程是这样的:
- Vasya从剩下的蜡烛中拿走k支。
- Petya拿走剩下的蜡烛中的10%(下取整)。
- 循环往复直至蜡烛全部被拿走。
Vasya想知道,他每次至少需要拿走多少支蜡烛,才能让他在游戏结束时拥有至少一半(上取整)的蜡烛?
解法:
二分答案。由于每次至少拿走蜡烛的10%,check的计算次数最多不超过1e3次。
E
Origin:CodeForces 1006E
题目大意:
给定一棵以1为根的大小为n(n<=2e5)的有根树。规定在DFS时优先遍历编号较小的点。给出q(q<=2e5)个询问,每次询问(u,k)表示询问从节点u开始的第k个被DFS到的节点编号。特别地,如果该节点不是u的子孙,输出-1。
解法:
DFS预处理出DFS序、逆映射以及size。每次询问O(1)查询。
注意由于DFS顺序的规定,vector存图比邻接表方便。
Week10
A
Origin:HDU 1213
题目大意:
t组数据。Ignatius有n个朋友。这些朋友彼此有m个认识关系。如果A认识B,B认识C,那么就认为A,C彼此认识。n个朋友来参加Ignatius的生日聚会。彼此认识的人可以坐在一张桌子上。请问Ignatius至少需要准备几张桌子。
\(1\leq t\leq 25,1\leq n,m\leq 1000\)
解法:
将认识关系转化为图,答案变为判定图的连通分量个数。并查集裸题。
B
Origin:HDU 4585
题目大意:
多组数据。给定n个少林寺和尚的编号k及武力值g,第i个和尚需要和前i-1个和尚中武力值最接近他的和尚对决(第0个和尚的编号和武力值分别为1和1e9),如果有两个武力值与他同样相近的和尚,他会选择武力值较小的那个。求与第i个和尚进行对决的和尚编号。
\(1\leq n\leq 10^5,0\leq k,g\leq 5\times 10^6\)
解法:
动态求一个有序序列中x的前驱后继。用set解决。由于题目中没有提重复元素的处理方法,可以不用multiset。
C
Origin:HDU 5183
题目大意:
t组数据。定义函数
给定\(\{a_i\},k\),询问是否存在满足条件\(sum_{NP}(i,j)=k\)的有序二元组\((i,j)\)。
\(0<t\leq 25,1\leq n\leq 10^6,-10^9\leq a_i\leq 10^9\)
解法:
前缀和求出\(s_i=\sum_{j=0}^i(-1)^ja_j\),随后从n-1至0枚举\((i,j)\)的起点i,并将s[i]插入哈希表中,根据i的奇偶性在哈希表中查找是否存在\(s_{i-1}\pm k\)。倒序遍历保证枚举起点时潜在的终点已经被插入哈希表中。
其实根据奇偶性分别计算也是可以的,只是常数变为原来两倍,会被卡常。建议手写哈希。
D
Origin:CodeForces 527C
题目大意:
给定一个w*h的玻璃,要求对玻璃划n刀。每次在玻璃上横着或竖着在刻度为x的地方划一刀。每次划完询问玻璃碎片中最大一块的面积是多少。
\(2\leq w,h\leq 2\times 10^5,1\leq n\leq 2\times 10^5\)
解法:
以玻璃的宽为例。用两个multiset分别维护分割的所有刻度和被分割成的所有线段长度。设一次分割的刻度为x,将x插入刻度multiset中,且将x的前驱后继取出,算出原线段长度,将它从线段multiset中删除,用两条新线段代替插入。对玻璃的长也是相同操作。
每次答案就是长宽的线段multiset中最大值的乘积。
E
Origin:CodeForces 1213G
题目大意:
给定一棵大小为n的无根树,有m个询问,第i次询问树上满足瓶颈值(路径上所有边中边权最大值)不大于\(q_i\)的路径条数。
\(1\leq n,m\leq 2\times 10^5\)
解法:
Kruskal算法变形。将所有边按照权值升序排序,依次加入树中,一条有效边加入后,路径增加数量为\(size_u\times size_v\)。因此只需要预先读入所有查询并排序,依次处理即可。
Week11
A
Origin:CodeForces 76A
题目大意:
给定一张点数为n,边数为m的无向连通图和两个参数G,S。第i条边有两个参数\(g_i,s_i\)。求出这张图的一个生成树,最小化\(G\cdot max(g_i)+S\cdot max(s_i)\)。
\(2\leq n\leq 200,1\leq m\leq 50000,1\leq G,S,g_i,s_i\leq 10^9\)
解法:
先将所有边按照参数g第一关键字,参数s第二关键字排序。逐条边加入“待选序列”中(最初序列为空),并保持序列为按照参数s升序。随后将“待选序列”中的边逐条进行Kruskal算法,如果构造出生成树则更新答案。复杂度\(O(mn)\)。
B
Origin:CodeForces 437C
题目大意:
给定一张点数为n,边数为m的点权无向图。删除点u的代价为u所有剩下的邻点v的权值之和。求删除所有点的最小代价。
\(1\leq n\leq 1000,0\leq m\leq 2000,0\leq w_i\leq 10^5\)。
解法:
将删点转化为删边。容易发现如果只有两个点u,v和一条边,那么选点权较大的点删除最优。因此定义\(w(u,v)=min(w_u,w_v)\)。最后答案为所有边权之和。复杂度\(O(m)\)。
C
Origin:CodeForces 770C
题目大意:
一共有n门课,其中k门必修课。第i门课有\(t_i\)门前序课程,即只能在修读第i门课的所有前序课程的情况下才可以修读第i门课程。求出一个修读课程的顺序,使得最终修读的总课程数最少。
\(1\leq k\leq n\leq 10^5,0\leq t_i\leq n-1\)。
解法:
拓扑排序的DFS形式。用vector存储修读顺序,以k门必修课为起点按反向边搜索,如果碰到环输出-1,回溯时pushback。
D
Origin:CodeForces 1095F
题目大意:
给定一张点数为n,边数为m的点/边权无向图。此外可以添加任意条边。每次可以在点u和点v之间添加一条权值为\(w_u+w_v\)的边。求最小生成树权值。
\(1\leq n\leq 2\times 10^5,0\leq m\leq 2\times 10^5,1\leq w_i\leq 10^{12},1\leq w_e\leq 10^{12}\)。
解法:
不考虑原有的边,如果全部添加边的话,最优方案显然是将n个点中权值最小的和其他n-1个点连一条边(2n-2个度数,n个点都要有,剩下n-2个度数贪心)。所以往原有图中添加n-1条边之后做Kruskal算法即可。复杂度\(O((m+n)log(m+n))\)。
E
Origin:CodeForces 1245D
题目大意:
给定n个城市的坐标。需要在若干个城市中修建发电站,再用电缆将若干城市连接。在第i个城市修建发电站的代价是\(c_i\),将第i个城市和第j个城市相连的代价为\((k_i+k_j)\cdot dis(i,j)\),其中\(dis(i,j)\)指两座城市的曼哈顿距离。求使所有城市通电的最小代价。
\(1\leq n\leq 2000,1\leq x_i,y_i\leq 10^6,1\leq c_i,k_i\leq 10^9\)。
解法:
暴力构造完全图。随后新增一个虚拟节点0,从节点0向节点i连一条权值为\(c_i\)的边,然后做Kruskal算法即可。