
数据结构与算法
文章平均质量分 54
学习常见数据结构与算法,提升使用算法解题的能力
m0_51303687
取乎其上,得乎其中;取乎其中,得乎其下;取乎其下,则无所得矣。
展开
-
做题记录22.3.6洛谷P1134
数学问题。原创 2022-03-06 16:07:05 · 165 阅读 · 0 评论 -
牛客XBal月赛45做题记录
牛客月赛45原创 2022-03-05 15:23:27 · 357 阅读 · 0 评论 -
做题记录2022.3.3
洛谷原创 2022-03-03 18:29:46 · 330 阅读 · 0 评论 -
做题记录 2022.2.26
洛谷P2385&P1076原创 2022-02-26 15:38:13 · 173 阅读 · 0 评论 -
学习记录 状压DP(二)
例题3这题与上面的题目类似,不过限制了可选的总数。令dp[i][j][k]表示前i行,状态为j,共计k个。按照之前的思路,我们选定了状态j后,这一行的“国王”总数就确定为j中二进制1的个数(记为popcnt(j))了,因此前i-1行还要k-popcnt(j)个。代码如下:int tot=(n<2)?2:(1<<(n-1))+(1<<(n-2));for(int i=1; i<=n; i++) { for(int j=0; j<tot; j++) { i原创 2022-02-07 16:31:02 · 91 阅读 · 0 评论 -
做题记录 牛客寒假基础训练3-I
题目链接此题我原本的思路是:建立前缀和数组t[],表示前i个字符的种类总数。对于任意的i,在i+l-1之后找到第一个j使得j>=i+2即可。注意j之后剩下的字符数是否大于等于r。但这种做法是错误的。考虑IE$abQ这样的字符串,这种方法会少统计$abQ从而得到错误答案。 看起来比起从第一个字符开始有多少种类型,我们似乎更应关心从i开始有多少类型。因此将t数组的定义改为:从i开始,第一次遇到第j,(j∈[0,4))种类型的位置是哪儿。最后找到t[]中第三大的数对应的位置即可。这一过程可以用std:原创 2022-02-02 15:21:42 · 601 阅读 · 0 评论 -
做题记录 牛客寒假基础训练1-H
牛客寒假基础训练营 题解&补题原创 2022-01-25 14:37:42 · 372 阅读 · 0 评论 -
牛客XBal月赛43总结
假期前的最后一次比赛,写完这篇就收拾收拾准备回家~暂时都是做出来的题目,没做出来的等过两天再补题吧。A:由于可以包含自身,而最大因数必然是自身,故答案显然为n。B:看到数据范围,首先想到应该是有固定结论或单次不超过O(log(target))的解法。首先,由于每次操作都要乘2,所以除非一开始就有一个瓶子的体积与目标相等,否则若目标为奇数,即不可完成。否则,如果目标<max(a,b),假设a>b,那么只要从A瓶中倒掉2a−target2\frac {2a-target}{2.原创 2022-01-14 13:45:40 · 335 阅读 · 0 评论 -
做题记录 2022.1.12
题目链接这题乍看是贪心,好像每次取首尾两个的较小者就行。但这是错误的。考虑5 5 1 6这组数据,贪心得到的答案是42,正确答案是43。可以采用搜索,设计搜索函数为int dfs(int from,int to,int day); 返回[from,to]区间内第day天的最大值。但搜索速度太慢。而画出搜索树发现,当[from][to]确定时day也随之确定,故可以采取记忆化。int dfs(int from,int to,int day=1) { if(dp[from][to]!=0) r原创 2022-01-12 10:51:58 · 144 阅读 · 0 评论 -
大整数乘除法的实现(二)
第二部分:除法的试商及估商法原创 2022-01-10 17:11:01 · 951 阅读 · 0 评论 -
学习记录 单调队列
题目链接此题可以用RMQ在O(nlogn)的时间内解决。可以选用的的方法有线段树、ST表等。但线段树常数太大,经实测会T 2个点,而ST表空间复杂度太大,会MLE。分块就不说了。那么可以用什么办法呢?正解是单调队列。以求解最小值为例,先初始化队列为空,每遇到一个值就将它的下标与队尾比较,如果当前值比队尾还小或队列已空就入队,否则将队尾出队(没错是队尾)。若当前下标大于等于m,则取出队头。若队头是本“窗口”的第一个值对应的下标,就将其出队,以避免下一个“窗口”中仍有它。由上面的分析不难看出这个队列要在原创 2022-01-08 16:29:48 · 583 阅读 · 0 评论 -
树形DP学习笔记
介绍树形DP的应用,包含例题。原创 2021-12-09 18:48:56 · 261 阅读 · 0 评论 -
蓝桥杯模拟赛记录
1:大意就是给一个IP地址,里面有一个数不知道,问该数最大是多少答案:常识,显然2552:如果一个整数 g 能同时整除整数 A 和 B,则称 g 是 A 和 B 的公约数。例如:43 是 86 和 2021 的公约数。请问在 1(含) 到 2021(含) 中,有多少个数与 2021 存在大于 1 的公约数。请注意 2021 和 2021 有大于 1 的公约数,因此在计算的时候要算一个。只要计算出所有因数放到集合里,并把它们的倍数也放到集合里就可以了。做的时候出了点低级的错误:把每个因数都设原创 2021-11-28 12:16:48 · 1538 阅读 · 2 评论 -
做题记录 P1441砝码称重
题目链接原本以为这题就是简单一搜索,直接套DFS模板发现样例也能过,但后来发现只是凑巧正确。因为题目要求的是选出n-m个后,再在n-m个当中选若干个并计算能出现多少个和。选哪n-m个不确定,这部分不得不爆搜(至少我只会这样)。那在n-m个中选的过程难道也只能爆搜了吗?显然不是,我们可以用DP完成这一过程(01背包)。代码如下:#include <cstdio>#include <algorithm>const int M=22,MAXW=2001;using name原创 2021-11-26 15:29:54 · 179 阅读 · 0 评论 -
做题记录 洛谷P2671求和
题目链接思路1:三层循环暴力枚举,复杂度O(n3)O(n^3)O(n3),对应20分。没用这种方法,代码就不水了。思路2:不难发现与中间点y没什么关系,只需保证x,y,z成等差数列即可。因此枚举x,z,若(x+z)/2到x和z的距离相等,则可以判断是否满足条件。优化:容易发现公差必然为偶数,所以枚举x+2,x+4…z即可,复杂度仍为O(n2)O(n^2)O(n2)但常数降低一半,能得40分。for(int i=1; i<n-1; i++) { for(int j=i+2; j&l原创 2021-11-23 16:34:35 · 669 阅读 · 0 评论 -
做题记录2021.11.19 洛谷P1103书本整理
题目链接本题很明显的DP。但转移方程如何制定是关键。去掉k本,就是选择n-k本。(不知道这里的高度有什么用 )因此可定义dp[i][j]:前i本中选j本的最小代价。很明显,∀i∈[1,n]\forall i \in[1,n]∀i∈[1,n],dp[i][1]=0。在背包问题中,我们选第i个物品时,它的前一个物品是任意的i∈[1,i−1]i \in [1,i-1]i∈[1,i−1]。但此问题需要我们知道上一个物品的宽度,因此就比较棘手。其实可以枚举上一个物品,但应注意在选了j个的前提下,上一个物品至原创 2021-11-19 20:45:13 · 377 阅读 · 0 评论 -
学习记录 ST表
稀疏表(ST表)也是一种用于RMQ的数据结构,它利用了倍增与动态规划的思想。如果只存在区间查询,不存在区间查找,则ST表是一种不错的选择。为了能在O(1)的时间完成查询,可以这样预处理:如果记maxn[i][j]为[i,j]区间上的最大值,易得max[i][j]=maxn([i][j-1],a[i])。但此种方法预处理的复杂度为O(n2)O(n^2)O(n2),为了简化,我们可以用倍增思想。记st[i][j]为从i开始连续2j2^j2j个元素的最大值。则有st[i][j]=max(st[i][j−1],原创 2021-11-14 09:47:34 · 383 阅读 · 0 评论 -
做题记录 洛谷P2004领地选择
题目链接这几乎是二维前缀和的模板题。众所周知,一维前缀和sumisum_isumi的定义为:对有n个数的数列,sumi=∑k=1iaisum_i=\sum \limits_{k=1}^{i}a_isumi=k=1∑iai那么,二维前缀和sumi,jsum_{i,j}sumi,j 自然就是对有n行m列的矩阵,sumi,j=∑i=1n∑j=1mai,jsum_{i,j}=\sum \limits_{i=1}^{n}\sum \limits_{j=1}^{m}a_{i,j}sumi,j=i=1∑原创 2021-11-06 15:41:15 · 250 阅读 · 0 评论 -
做题记录2021.11.3 洛谷P1521逆序对
题目链接近两天都在写一个C++的Biginteger类,一直没刷题,今天补一下。解法1.纯暴力解法 枚举所有全排列并求其逆序对,即使采用树状数组等高效方式求逆序对仍要O(nlogn∗n!)O(nlogn*n!)O(nlogn∗n!),完全不可行。解法2.动态规划定义dp[i][j]为前i个数的全排列中逆序对为j的个数。我一开始是考虑最后一个数字,但压根没有思路。正确方法是:考虑有i-1个数的序列,将第i个数插入,由于它是序列中最大的,所以插入其中最后一个位置,可以新增0个逆序原创 2021-11-03 21:03:16 · 178 阅读 · 0 评论 -
做题记录 石子合并
题目链接这个题目,我一开始的思路是这样的:先计算出前缀和sum[],对于新加进去的第i个石头堆,存在两种合并方式:1.将它与第i-1堆合并2.将前i-2堆合并,再将它并入第i-1堆中。然而这种思路就是默认了必须从1,2两个开始合并,实际上我们第一次可以合并其他的堆。所以是错误的。因此正确方法是区间DP。即枚举起点i、终点j、中间点k,然后dp[i][j]=dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]。然而如果这样枚举,就会造成需要使用没更新过的结果的情况。因此枚举长度和原创 2021-10-31 15:50:36 · 94 阅读 · 0 评论 -
做题记录2021.10.27 洛谷P2672推销员
题目链接我的想法是:假设当前选第i个,那么在前i-1个的基础上有下面两种方法:向前选:距离不变,选价值最大的(假设是第j个),那么res+=a[j].val;向后选:此时距离变大,要选(距离*2+当前已选的元素的价值和)最大的元素。由于要反复查找最大值,我一开始是想用分块或线段树做,但这两种方法似乎很难获取最大元素的下标(第二种方法要获取下标以更新当前距离),所以直接写了个暴力,复杂度为O(n2)O(n^2)O(n2),结果当然是TLE了。然而,我们可以用优先队列优化第一种情况选最大值的过程。原创 2021-10-27 16:50:43 · 149 阅读 · 0 评论 -
牛客XBai月赛39 做题记录
本次比赛应该是我做的最好的一场ACM赛制的比赛了。其实一共就3场 ,8题AC了3个当然主要是因为题目比较水。下面是我做出来的A:看到数据范围,想到直接O(n2)O(n^2)O(n2)暴力。我想的是把所有向量都简化然后暴力求解任意两个加起来再简化后是否可以为目标向量。但实际上这会导致错误(比如(2,0)+(4,1)=(6,1),但简化(2,0)将导致错误结果),只简化最后一个向量即可。然而我居然没想到可以直接x1y2=x2y1,看来数学不好有时候很麻烦呢~#include <cstdio&原创 2021-10-23 10:17:30 · 129 阅读 · 0 评论 -
做题记录 2021.10.21 POJ2376CleaningShifts
题目链接原创 2021-10-21 18:23:22 · 86 阅读 · 0 评论 -
做题记录 2021.10.20 被3整除的子序列
给你一个长度为50的数字串,问你有多少个子序列构成的数字可以被3整除答案对1e9+7取模思路:由小学数学知识可以看出是DP,但如果直接定义dp数组表示能整除的个数,状态转移就很困难。因此定义dp[i][j]=前i个数中对3的模为j的个数。只要输出dp[n][0] (n为字符串的长度)即可。dp[i][j]可分为两种情况:1.不将第i个数加进序列;2.将第i个数加进序列;因此可以得到dp[i][j]=dp[i-1][j]+dp[i-1][?]其中?处我想了很久,最终还是没想出来一个通用的式子.原创 2021-10-20 19:57:41 · 184 阅读 · 0 评论 -
做题记录 洛谷P1230 智力大冲浪
题目描述小伟报名参加中央电视台的智力大冲浪节目。本次挑战赛吸引了众多参赛者,主持人为了表彰大家的勇气,先奖励每个参赛者m元。先不要太高兴!因为这些钱还不一定都是你的?!接下来主持人宣布了比赛规则:首先,比赛时间分为n个时段(n≤500),它又给出了很多小游戏,每个小游戏都必须在规定期限ti前完成(1≤ti≤n)。如果一个游戏没能在规定期限前完成,则要从奖励费m元中扣去一部分钱wi,wi为自然数,不同的游戏扣去的钱是不一样的。当然,每个游戏本身都很简单,保证每个参赛者都能在一个时段内完成,而且都必须从整.原创 2021-10-20 14:43:52 · 203 阅读 · 0 评论 -
做题记录2021.10.18 SequenceGame(历史问题)
来源:牛客网题目描述 由于你帮助 Alice 回答得非常好,Sept 又找到了 Bob,希望能难倒他。 他给了要求 Bob 组成一个长度为 nnn 的新的数列 aaa,其中数列 aaa 的每一个元素ai都有k个取值。求所有可能的数列a中的最长上升子序列的的最大长度。 由于 Sept 怕题目钛难,所以他答应 Bob,对于每个i,k个取值不降。输入描述: 第一行两个数 k,n,意义如题述。 接下来n行,每行k个数,即ai的k个取值。输出描述: 仅一行一个整数,即所有可能的数列 aaa 中的最长上升子序.原创 2021-10-18 16:48:41 · 413 阅读 · 0 评论 -
做题记录 2021.10.17 洛谷P2431
题目链接首先,看到 1,2,4,8…… 这样的序列一定要想到二进制。不难发现,此题就是要我们求[a,b]的所有数中,二进制1最多的那个数的二进制有多少个1。前置知识:__builtin_popcount:GCC中内置的函数,可用于快速计算二进制中1的个数。其对应的64位整数版本为__builtin_popcountll。当然也可以自行实现,但以我的水平只能实现一个O(logn)的。不难发现:如果⌊log2a⌋≠⌊log2b⌋\lfloor log_2a\rfloor\neq \lfloor lo原创 2021-10-17 09:44:25 · 123 阅读 · 0 评论 -
做题记录2021.10.15 洛谷P5662纪念品
题目链接首先看一下数据范围:首先我们可以通过最后一句话得到一个结论:本题不用开long long。下面开始分析各个数据:对于10%数据,T=1:不管有多少物品,也不管当天买入了多少,最后总是会全部卖出,而此时买入价=卖出价,所以结果为m。另有15%数据,T≤100,N=1:如果只有一件物品,那么我们可以贪心地考虑:如果某一天物品价格比前一天多,那么就在前一天尽可能多的买入,在当天全部卖出。如果物品自第x天起价格连续数日上涨,那么我们就在那一天尽可能多的买入,在达到极值的那一天卖出,以求最大效原创 2021-10-15 16:53:08 · 121 阅读 · 0 评论 -
做题记录 2021.10.11 洛谷P2426删数
题目描述有N个不同的正整数数x1, x2, … xN 排成一排,我们可以从左边或右边去掉连续的i(1≤i≤n)个数(只能从两边删除数),剩下N-i个数,再把剩下的数按以上操作处理,直到所有的数都被删除为止。每次操作都有一个操作价值,比如现在要删除从i位置到k位置上的所有的数。操作价值为|xi – xk|*(k-i+1),如果只去掉一个数,操作价值为这个数的值。 问如何操作可以得到最大值,求操作的最大价值。输入格式第一行为一个正整数N;第二行有N个用空格隔开的N个不同的正整数。输出格式一行,包.原创 2021-10-11 16:23:13 · 188 阅读 · 0 评论 -
做题记录 2021.10.10 洛谷P1439LCS
题目描述:给定n与1~n的两个全排列a,b,请计算a与b的最大公共子序列长度输入第一行:整数n第二行:序列a第三行:序列b输出一行,最大公共子序列长度样例输入51 2 3 4 53 2 1 4 5样例输出 3数据范围:1≤n≤100000由于数据范围巨大,传统的O(n2)O(n^2)O(n2)算法肯定不行。但LCS问题不像LIS那样有优化方法,所以不能按照LCS的方法做。由于给的是1~n的全排列,所以序列中所有元素都是相同的,不同的只是排列顺序罢了。而.原创 2021-10-10 16:19:39 · 103 阅读 · 0 评论 -
高精度模板 2021.10.9
之前用高精度都是返回std::string,但这种做法常数太大。因此采用新思路,将每一位保存在数组中,最后倒序输出即可。由于是模拟,细节处理较多,因此最好记住代码。1.高精度加:int add(short *num1,short *num2,int len1,int len2) { //存储两个数的各位与长度//注意两个数都是倒序存储,高位自动补0 bool f=0; //进位标记 int maxlen=max(len1,len2); for(int i=0; i<maxlen; i+原创 2021-10-09 10:57:17 · 88 阅读 · 0 评论 -
RMQ阶段总结(一)
进行RMQ或类似问题可以采用如下思路:一、暴力求解通常用于对拍或实在想不出更好的方法时。最坏情况下的复杂度一般达到O(n2)O(n^2)O(n2),只能通过较弱的的数据。二、分块通过将数据分为⌊n⌋\lfloor {\sqrt n}\rfloor⌊n⌋块,每块维护相应数据(和、最大值、最小值等),注意如果存在区间修改时要设置标记。时间复杂度降至O(n)O(\sqrt n)O(n),在想不到如何用更好的方法(线段树、树状数组等)实现、题目时间限制不紧或做题时间比较紧时,可以尝试。有关用分块处理的原创 2021-10-04 16:13:56 · 218 阅读 · 0 评论 -
学习记录 2021.10.2
如题,已知一个数列,你需要进行下面三种操作:将某区间每一个数乘上x将某区间每一个数加上x求出某区间每一个数的和对p取模的结果很明显这又是一个RMQ的题目,可以用线段树求解。(以下均假设区间长度为len,原来的和为x)前提:很明显,如果某一个区间同时加上一个数a,那么整个区间的和变为x+len*a;如果同时乘a,那么和就变为ax。然而本题有两种修改操作,使用1种懒标记显然是不够的。所以用2种,分别为加法标记addt,乘法标记mult。在有两种标记时,由于标记要下放,所以必须人为规定两种原创 2021-10-02 15:00:00 · 77 阅读 · 0 评论 -
做题记录 洛谷P1843奶牛晒衣服
题目描述一件衣服在自然条件下用一秒的时间可以晒干a点湿度。抠门的熊大妈只买了一台烘衣机 。使用用一秒烘衣机可以让一件衣服额外烘干b点湿度(一秒晒干 a+b湿度),但在同一时间内只能烘一件衣服。现在有n件衣服,第 i件衣服的湿度为wiw_iwi(保证互不相同),要你求出弄干所有衣服的最少时间(湿度为 000 为干 )。输入格式第一行三个整数,分别为 n,a,b。接下来2到n+1 行,第i行输入wiw_iwi。输出格式一行,弄干所有衣服的最少时间。输入样例3 2 1123输出样例 .原创 2021-09-29 10:02:54 · 341 阅读 · 0 评论 -
学习记录 树状数组
如果需要对序列进行以下两种操作:将某一个数加上 x求出某区间每一个数的和朴素方法肯定不行,使用分块可以降低复杂度,但仍然有O(n)O(\sqrt n)O(n),数据非常大的话就不能过。使用线段树是一种不错的方法,但浪费空间且常数大。分析发现可以去掉线段树中不需要的结点。具体地说,去掉每一个结点的右儿子,这时线段树就被简化为这个样子:这种数据结构叫树状数组(BIT),下面讨论如何解决上面的两个问题。例如:要求[1,5]的和,我们可以求上图中4与5两块的和同样,要求[1,7]的和,我们可以原创 2021-09-28 15:02:46 · 80 阅读 · 0 评论 -
学习记录 线段树懒标记
对线段树进行区间更新时,采用一般方法需要访问区间每一个元素对应的所有叶节点 并逐级向上更新,这一操作的复杂度可以达到O(nlogn)O(nlogn)O(nlogn),比朴素方法还要慢。因此引入懒标记,更新时更新到能包含整个区间的结点时就给那个点打上标记,需要查询时再下传到左右儿子,这样可以显著提升效率。懒标记讲解对某个节点的懒标记进行下放时,左右儿子的标记也要更新,并且该节点的标记值要清零,以防重复下放。用懒标记解决洛谷P3372:#include <cstdio>#include &原创 2021-09-26 14:40:21 · 920 阅读 · 0 评论 -
做题记录 2021.9.23 洛谷P2574XOR的艺术
inline bool check(int i,int m) {return (b.vis[m])?a[i]=='0':a[i]=='1';} //应该加一inline void change(int i,int m) { if(a[i]=='0') { a[i]='1'; b.num0[m]--; b.num1[m]++; } else { a[i]='0'; b.num1[m]--; b.num0[m]++; }}inline void原创 2021-09-24 09:17:14 · 120 阅读 · 0 评论 -
学习记录 线段树(一)
处理RMQ问题的一个实用的数据结构是线段树,它是一种在每个节点上维护区间信息的二叉搜索树,并且由于不删除结点,平衡性较好,因而能实现高效查找、修改的目的。线段树的根节点维护整个区间的信息,每个结点的左右儿子分别维护父节点左半部分与右半部分的区间信息。下面以单点增加值与区间查询最大值为例说明如何利用线段树完成RMQ操作:为了方便起见,修改与查询均传入每个结点对应的区间。1.建立:为保险起见,将线段树大小设为四倍的区间大小。int seg_tree[M*4],num_nodes;//计算有效结点个原创 2021-09-21 16:29:01 · 67 阅读 · 0 评论 -
学习记录 分块思想
有时对于一些区间操作,比如求区间的最大(小)值、和、乘积等,如果朴素地求解,每次操作需要O(n)O(n)O(n)的时间(n为区间长度)。如果需要多次求解,那么时间复杂度会很不理想。这时就需要一些特殊方法。其中一种比较好理解的方法就是分块。就是把数据分成若干块,对于区间[l,r]上的操作,对其在完整的块内的部分直接求解,不完整的块单独求解。一般地,我们把每块长度设为b=[n][\sqrt n][n] ,这样就有n/b块。在最坏情况下(l为所在区间的第二个,r为所在区间的倒数第二个。比如100个元素,1原创 2021-09-19 15:01:11 · 93 阅读 · 0 评论 -
做题记录 离散化
如果一个序列(或坐标)的值域很大,但我们不关心它的值,只关心相对大小的话,为了降低时空复杂度,可以对其离散化。举个例子,在一个很长的坐标轴上,给定大量坐标,询问某一个点,坐标比它小(或大)的点有多少。很容易知道,对于大量的点,我们不必把他们在坐标轴上的位置都表示出来,因为我们比较有多少比它小的话,只需要知道他们之间的相对大小就可以,而不是绝对大小,这就要离散化。简单点说,就是把每个元素替换为它是整个序列中第几小。对于一个序列,可以把数存进结构体中,标记它的位置直接模拟完成离散化。int res[M]原创 2021-09-17 17:42:23 · 97 阅读 · 0 评论