自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(60)
  • 收藏
  • 关注

原创 新生讲课——图和并查集

其中e[idx]表示idx这个位置存储的点u,ne[idx]存储u指向的点的下标,也就是e[ne[idx]]表示的就是v并且u指向v,w[idx]表示的是u到v点的边权,h[u]表示的是以u为起点的最后一条边遍历的时候帮助我们开始遍历以u为起点的路径,遍历方法如下。其中g[u][i].first表示u可以到达的点v,g[u][i].second表示u到达v的这条边的权值。这里的p[i]表示的实际含义就是i现在所在团体的祖宗,这里的find函数则可以帮助我们找到u的祖宗。比赛中出现的并查集相关题型。

2025-02-04 17:41:58 616

原创 二分/双指针/单调栈队列专题

给定一个范围,求出一个数组中所有满足和在这个区间内的子数组,可以通过双指针来实现,实际上也可以理解成三指针,第一个指针是我们枚举的子数组的起点i,第二个指针l满足pre[l] - pre[i - 1] >= L,第三个指针r满足pre[r] - pre[i - 1] <= R,如此一来对于起点i而言所有位于[l , r]区间内的点都可以作为终点满足与i构成一个合法子数组。关键点在于对前缀和进行排序,如此一来此时的s[i] - s[j - 1]代表的是|a[j] + ....... + a[i]|

2025-02-03 23:37:37 282

原创 Codeforces Round 997 (Div. 2) D. Unique Median

我们反着考虑,什么情况下偶数数组的两个中位数不相等呢,发现我们可以钦定x为基准,所有小于x的为-1,大于的为1,这样对于一个区间而言,若该区间的和为0则说明最中间的两个数不相等,那么我们就统计对于每个x区间和为0的个数,并且为了防止重复统计(若直接统计区间和为0的数量那么对于一段中位数为x,y的区间它会被统计abs(y-x)次)我们可以在以x为基准的时候统计所有y为x的和为0的区间,这个可以通过开一个桶来进行快速计算,我们求出-1/1数组的前缀和p[i],那么对于j而言不合法的数组数量就是1-j-

2025-01-18 16:35:46 234

原创 思维 + 贪心 + 构造专题

1.Problem - C - Codeforces先根据样例得到结论,n % 2时最大值为n,n % 2 == 0时n最大值为2^x - 1(x为n二进制下的最高位),接下来就是如何构造,一般这种题需要我们想一个阻断器,就是不管之前的值如何只要经过这个阻断器都会变成一个固定的值,本题的阻断器可以找1在奇数位置的时候,这样只要经过这个位置不管之前如何都会变成1,因此n % 2时我们在最后三位填上1 , n - 1 , n即可之前可以随便填,n % 2 == 0的时候也是在奇数位置上填1,我们没办法通过一个数

2025-01-16 16:17:23 161

原创 基础dp专题

因为构造的b可以递增可以递减,因此我们升序降序都进行dp,dp[i][j]表示前i个数且第i个数是a中第j大的时候的最小值,那么dp[i][j] = min(dp[i - 1][k](1 <= k <= j),那么我们需要维护新的数组ndp[i][j]用来记录dp[i][1 ~ j]的最小值来帮助dp[i][j]进行转移。若被使用则说明a[i]是j组的开头部分,此时的a[i - 1]可以是第j组被使用的状态也可以是j - 1组时使用/不被使用的状态。dp[i]表示以i结尾的长度不超过m的最大子数组的和。

2025-01-14 17:34:38 521

原创 最小生成树专题

本题难点在于贪心,这里的n个卫星代表的意思其实就是可以免费合并n个点(n > 1),那么我们可以直接按照kruscal的流程在最后合并的时候当剩下需要合并的点为n的时候停下来,剩下需要合并的点其实就是点数m - 已经合并的次数,

2025-01-07 12:38:56 225

原创 并查集专题

好题,需要想到离线回答并且要会灵活运用带边权并查集,这题有两个难点,一个是不知道能否根据前i个信息得到答案,这一点可以通过离线回答来解决,第二点就是在确定u和v在同一并查集的时候怎么得到两点的曼哈顿距离,一开始一直想着将同一并查集中的一个点当作原点以此整合整个集合的其他点但是我们只需要知道每个点x和y上与根点的偏差,知道u和v与根点的x和y的偏差也可以得到u和v的曼哈顿距离,维护和根点的x和y的偏差只需要维护两个边权即可。题目给出的条件是l到r的和为w,那么就自然会想到前缀和,这句话说明。

2025-01-06 17:25:44 171

原创 12.2日志

线段树 + 差分,一开始的思路是直接将整个等差数列加到线段树中,但是pushdown不好维护于是改变思路,想到我们可以去维护a的差分数组,这样一来对[l , r]加上一个首项为看,公差为d的等差数列其实就是在l上加k,[l + 1 ~ r]上加d,之后我们求第p项也转变成求[1 ~ p]的区间和即可,一开始多尝试新思路,不要在困难的思路上折磨自己,多想少code。

2024-12-29 15:33:42 179

原创 最短路专题

xi - xj <= w这个不等式通过移项变成xi <= xj + w,我们发现再最短路算法中每次进行松弛操作的时候dist[u] > dist[v] + w的时候我们要令dist[u] = dist[v] + w从而达到dist[u] <= dist[v] + w的状态,而这个式子和上述不等式的形式是一样的,所以我们可以从j点向i点连一条边权为w的边,最后在整张图上跑最短路即可因为存在负边权所以得用spfa,若图中出现负环则说明无解。本体有一个坑点就是满足题意的有两种情况一种是从1到n的一条路径。

2024-12-29 15:32:57 419

原创 AtCoder Beginner Contest 386

1.D - Diagonal Separation赛时一直卡在这道题,知道思路但不知道怎么解决,就是说若存在给定的白色方块出现在某个B方块与源点构成的区域内就无法实现,如果数据是1000则可以通过离散化 + 二维差分来解决,赛时一直在试图通过树状数组,线段树来解决,但是都卡住了,其实这是一道贪心的问题,因为有两维所以我们可以通过排序来固定其中一维的顺序,假定我们固定x上的排序那么此时遇到的'W'在x这个维度上势必会被已经遍历到的'B'包含那么接下来就看当前的'w'y上是否也会被之前的'B'包含,那么我们只需

2024-12-28 23:19:20 266

原创 最大子数组和 最大子数组和(有长度限制) 最大m段子数组和

若第i个数被使用则dp[i][j][1] = max(dp[i - 1][j][1](前i - 1个数凑出j段) , max(dp[i - 1][j - 1][0] , dp[i - 1][j - 1][1])这里考虑i - 1在第j段的时候之所以不考虑i - 1不被使用的情况是因为若i - 1在第j段却不被使用那么i就只能在j + 1段。一个经典的状态机模型,我们开一个dp[i][j][k]表示第i个数在第j段子数组是否被使用。2.最大子数组和(有长度限制)3.最大m段子数组和。

2024-12-20 21:35:56 280

原创 12.1日志

f[x] = dp[0] * (1 + f[x]) + dp[1] * (1 + f[x - 1]) + ........ + dp[n] * (1 + f[x - n]) = dp[0] + dp[1] + ..... + dp[n] + f[i] * dp[0] + f[i - 1] * dp[1] + .... + f[i - x] * dp[x] + ...... + f[0] * dp[x]其中dp[0] + dp[1] + ..... + dp[n] = 1。

2024-12-02 00:41:23 1631

原创 11.28日志

该题一开始的想法是用tarjan求出图中的强连通分量然后缩点再建一个新图,可以发现此时从cnt到1的点是新图的拓扑序,然后我就从cnt遍历到1将自身的数量累加到邻点,最后检查所有的新点,若该点被累加的值等于n则加上该点的大小,但这是不对的,例如1 -> 2,2 -> 3,1 -> 3这一组数据答案是3但是对3所做的贡献中1会产生两次,所以这种方法不对,应该缩点之后看每个点的出度,若该点出度为0且只有一个点出度为0则答案就是该点的大小否则为0。

2024-11-29 15:31:16 272

原创 11.23 ~ 25日志

很假的一道题,一开始一直想着是不是要化简式子然后用线段树维护,但是发现一个数即使是1e12也不过操作6次之后就是1了,对于一段区间最大值为1的区间是没有操作的必要的,因此我们最多对每个数操作6次,那么我们就直接暴力修改每一个数就好了,modify的时候若区间最大值为1直接返回,否则就去修改其左右子树一直到叶子节点的时候进行修改,需要记住每次modify结束都要pushup。每次深搜返回u点的时候会带回其邻点信息,我们就通过其邻点的low来更新自己的low(自己的邻点能到达的点自己也一定能到达)

2024-11-26 00:27:28 277

原创 11.22日志

既然如此我们就可以根据每句话知道合并u和v的时候u和v之间的距离如何定义了,这里拿u吃v来举例,此时要求我们合并完之后d[v] == d[u] + 1,合并之前的表示就是d[v](v到pv的距离) + d[pv] == d[u] + 1,要将v这条路径合并到u就需要令d[pv] = d[u] - d[v] + 1,之后pv这条路径的节点都会在路径压缩的时候根据d[pv]重新赋值。A中的1与B中的2合并,B中的1与C中的2合并,C中的1与A中的2合并。d[a] - d[b] == 1 --> a吃b。

2024-11-23 00:43:25 398

原创 11.21日志

【代码】11.21日志。

2024-11-22 10:37:24 143

原创 11.20日志

很好的并查集的题目,自己写的时候没想怎么去使用并查集,后来看题解才知道。首先肯定是需要去排序的,当两个人祖先相同的时候则直接输出他们的矛盾值结束即可,若两人不在同一个监狱那么我们宁愿让i去j敌人的监狱也好于跟j在一个监狱,因为去j敌人的监狱只有两种情况。因此一定是最优的,若j有敌人就合并i和j的敌人,若j没有敌人记录i成为j的敌人,这意味着两人已经不在一个监狱了,不需要我们去确定i和j分别在那个监狱。2.j的敌人跟i有矛盾关系但是矛盾值不如i与j的(因为排在i与j的后面)

2024-11-21 01:01:20 206

原创 11.19

,后来想到这个答案一定是出现在我们某个点和某个点之间的边中,那么该如何找到那个边呢,肯定是由小到大去找,那么就会想到kruscal求最小生成树这个算法,发现可行,我们并不需要建完整个生成树,只需要在连边的中途保证所有点都能够相互到达即可,那么如何判断什么时候我们的防御线没有缺漏呢,我们可以将x = 0和x = m这两条线抽象成两个虚点,然后只要在中途出现find(0) == find(m + 1)就说明最两端的点都在一个连通块中了那么就说明防御线没有缺漏了。假设我们有矩阵A,那么能否使得矩阵。

2024-11-20 16:26:28 281

原创 11.15 ~ 18日志

正难则反,首先很容易能够想到并查集,但是对于删点的操作不太好想,因为我们每次删除一个点i我们并不能知道与i相连的j是否还与其他点有连结从而继续联通,但是我们反过来想,不是将k个点依次删除而是从头到尾将k个点依次连结,这样每次接点的时候只需要i和j的祖先是否相同,若不同则合并后一定会少一个连通块,复杂度实际上是k + m。2.(sum + k) / x * x >= sum,这是因为当k = 0的时候sum / x是向下取整的,此时有可能出现牌堆数 * x < sum的情况,这是不能存在的。

2024-11-19 00:04:06 253

原创 11.14日志

和上一题很像,这题我们需要一点逆向的思维,虽然他让我们求的是选择的数字的最大和,但是不好处理,所以我们要对不选的数字和进行dp,我们的dpi表示的是前i个数字中且第i个数字不选的不选的数字的最小和,对于i不选它转移的区间是什么呢,我们发现第i个不选那么上一个不选的区间其实是[i - k - 1 ~ i - 1],并且我们求的是minn因此我们维护的应该是一个单调递减的单调队列,每次由队头进行转移。

2024-11-15 11:28:16 320

原创 11.13日志

首先对式子进行化简,化简完之后发现当i和j满足ai - i

2024-11-14 00:49:44 243

原创 11.11 ~ 12日志

转换成图来做,将它的连个条件转换成图,pi = i就是一个点指向自己的自环,p[pi] = i其实就是两个互相指的点,接下来需要你将给你的图通过最小的操作数转换成数个环且每个环的大小<= 2,有一个引领就是想要将大小为n的环拆成n个自环最小需要n - 1次操作,因此我们优先选择拆成互相指的点对,我们发现对于一个大小为x的环每次都可以拆分出一对互相指的点对,那么当x为偶数的时候拆x / 2 - 1次即可,x为奇数的时候拆x / 2次即可(前提是该环大小大于2)2.先往右边走,走到一个临界值后左转拿完左边的。

2024-11-13 00:58:43 401

原创 11.8日志

p^2 / s = (2 * a + 2 * b) ^ 2 / (a * b)化简完之后可以得到8 + 4 * (a / b + b / a),很明显这里可以使用基本不等式,a + b >= 2 * sqrt(a * b) 我们其中要想取等号也就是令a + b最小当且仅当a == b的时候,那么也就是a和b的差值越小值越小,那么对于i我们只需要找到n个数中大小位于i两边的数进行枚举就行,这样时间复杂度就是O(n)了,我们将所有出现过两次的边放进vector中排序然后每个数字只与相邻的数枚举选最小即可。

2024-11-09 00:57:00 408

原创 11.7日志

【代码】11.7日志。

2024-11-08 01:02:10 439

原创 11.6日志

我们的状态表示为dp[i][j]即j个人凑i的方案数,为了防止x越界因此我们将x += 1000,也就是将我们凑得数整体加上1000,最内层循环就是枚举1 - 10的正负数以及1-5双重循环的组合进行转移,有一点需要注意的是内外层循环不能颠倒必须先枚举人作为最外层循环再枚举数字,因为若是先枚举数字的话那么我们之后的转移都是不准确的,例如对于i明明可以通过一个人就可以从i + 10转移但是因为我们还没有枚举到i + 10所以此时的i + 10是空的,这个时候就会产生遗漏。

2024-11-07 00:48:23 272

原创 11.5日志

该题的难点在于如何找到树的根,题目中也明确说明了k重刺猬图本质上是一棵树,那么我们就可以将其抽象成树来进行考虑,抽象成的树是一颗深度为k的满树并且每个非叶子节点都至少有三个节点,如果我们能知道根节点那么我们就可以通过遍历这棵树,当深度小于k的时候每个节点都应该有4个及以上的节点,根节点有>=3个节点,叶子节点无节点,这是很好判断的,那么我们如何找到根节点呢,一开始我尝试从叶子结点出发找到距离自己长度为k的点作为根节点,但这是错误的。第二种我们减去左/右的区间后进行合并再加上新的区间长度。

2024-11-05 23:52:34 262

原创 11.4日志

很明显的一道构造题,并且是要求我们凑出询问的数字,那么很自然的想到如何利用二进制构造,那么如何将二进制与数字三角形结合呢,那么我们可以令数字三角形的节点是二进制数,最顶层的是0,下面是0,右节点是2^(21)(为了防止节点的值超过1e6),以此类推从而构造一棵二进制树,每一层节点的权值要么是0要么是2^(21 - i),其中奇数位置是0偶数位置是2^(21 - i)(为了让每个节点向下走的时候都有机会选择有/无权值),接下来我们就从顶端向底层模拟即可在模拟的过程中记录路径即可。

2024-11-04 23:52:12 394

原创 11.1日志

看似是求期望,实际上是推式子,容易发现每天都会由一种可能分裂成两种相差为1的可能,那么在第k天所有的可能可以组成一个由x * 2^k为首项公差为1且一共有2^k项的等差数列,并且在最后一天只会翻倍不会减少因此我们的首项实际上是x*2^(k+1),公差为2,一共2^k项的等差数列,因为我们要求的是期望所以我们算出前n项和之后还要除去2^k,化简完之后答案的式子是x * 2^(k+1) - 2^k + 1,有几点细节问题需要注意。3.需要注意x == mod的情况,这种情况下先不要对x取mod。

2024-11-02 01:46:44 562

原创 10.31日志

容易发现只有当01连续交替的时候才会发生平滑移位,当0/1位于1或者n或者有两个及以上连续的时候那么无论如何都不会再改变了,因此我们可以利用双指针去看从i开始最长的连续01串,并且这一段01串经过数次操作之后会出现4种情况。需要注意的是这样会wa在精度上,因为分子即使不算这个2000也已经到了1e18的级别了,这种时候我们只需要调换一下顺序让2000先除分母再去乘分子就可以解决这个问题了。此时操作次数就是cnt1 - 1 || cnt0 - 1(将所有1移到最左边减去原来就在左边的1)

2024-11-01 00:58:54 429

原创 10.29日志

首先考虑是0的天数,这些i只能在后面出现1的时候被一起买走,那么免单肯定选择价值高的,所以对于0的i它们不可能获得免单的机会。然后考虑1的天数,要想免单必须至少再带一个之前某天未买过的i,那么就可能出现之前没有可以一起购买的导致只能买这一个,因此我们要把免单优先给i较大的时候,并且应该0中i较大的跟1中较大的匹配,那么我们可以用栈来实现,需要注意的是装0的栈最后若没有清空要再次处理,最后剩下的1则是放弃前一半用来跟后一半匹配,给后一半免单。

2024-10-30 07:11:35 744

原创 10.28日志

ans = max(min(xi , xj) * (yi , yj) , min(xi , yj) * min(xj , yi))这是一个必须通过双重循环才能进行求解的式子,显然这题没办法接受n^2的复杂度,那么我们尝试能否化简这个式子,首先我们可以令所有的x < y,并且按照x由大到小排序且i > j的时候,那么式子就会变成。

2024-10-29 15:00:20 347

原创 10.25日志

考虑用dp,若每次只是判断比较相邻两位的影响的话会有后效性,dp的状态表示就是前i位中第i位交换/不交换的最小值,状态表示列对了转移方程也会简单很多。

2024-10-26 11:37:49 336

原创 10.24日志

考察对fail树的运用,暴力做法是kmp处理出ne后遍历字符串,通过ne不停回跳一直到0为止,其中当ne[i]

2024-10-25 00:58:07 270

原创 10.23日志

贪心可做,首先有一个很显然的结论,这是一个树形结构,要想最短路沿途经过的旅游城市最多那么肯定优先选择最外层的城市然后慢慢向根节点逼近,既然有了这个结论那么我们就可以去考虑每一个节点会对答案做的贡献了,很容易发现每一个节点对答案做的贡献其实就是。用两个dfs分别处理出d和dist,这就是考验对树的基本操作了,求d是从根节点1开始遍历,深度从0开始每往下搜一次深度加1再通过回溯调整,求dist则是预先将每个节点的dist设置为1再从根节点1开始往下搜一直搜到叶子节点后开始逐层向上累加。

2024-10-24 08:48:53 376

原创 10.22日志

接下来给出一个kmp + 栈的解法,本质上就是处理出t的ne数组后在s上进行匹配每一次匹配到就将t从栈中弹出,但是这样有一个问题就是没有办法解决连续性例如t = moo,s = momooo,当我们把中间的moo弹出后j会归0,但是我们应该让它回到s[1]的时候的状态,那么我们就可以新开一个pos数组记录s[i]的时候的j值,并在栈中装入下标,当我们删除完毕后直接通过pos回到栈顶元素所在位置的j值即可。那么我们处理出ne和z数组后在遍历答案的时候即可o1判断了。

2024-10-23 00:14:17 466

原创 10.21日志

一道思维题,暴力算法是计算出a的前缀和后在双重循环中寻找j - (i - 1) == a[j] - a[i - 1]的个数,但我们将式子变形一下就变成了j - a[j] == i - 1 - a[i - 1]的时候ans++,那么不就是开桶计算了吗。以上是另一种求l,r的方法,简单很多。

2024-10-22 01:00:39 276

原创 10.20日志

其实本质是要寻找字典序最小的前缀,这么说不严谨,例如。

2024-10-21 11:04:38 209

原创 10.19日志

思维构造,看到后能发现f函数的达成条件比g要苛刻很多,那么构造01串的话我们就让0多1少,先极端一点1个1,n-1个0,我们发现f(n) = 2^(n - 1) - 1,g的话不就是每个f的序列加个1吗,此时f(n) = g(n)思维 + 博弈论,我们可以发现当有一段长度大于1的'1'子串的时候我们先手操作在左右某一段加个|,那么这一段就不会变成0,需要注意的是若出现靠在左边或者右边的1的时候只有一个也没关系因为其中一边没办法加&从而变为0。

2024-10-20 01:01:37 294

原创 10.18日志

和上题类似,但是有些需要注意的点,这题不再是字符串而是由数字组成的序列,不能被trie树的思想固定,认为我们要建一个tr[1e5][1e9]的树,这其中有很多空间是被浪费的,这里的tr并不是要建树而是边,那么我们就可以用map来表示,同时这题需要我们边动态的插入节点边进行不同子串的统计,那么我们每新插入一个节点,对答案的贡献其实就是len[np] - len[fa[np]],可以在插入的时候完成统计。

2024-10-19 00:39:21 279

原创 10.17日志

len[p] + 1那么q就不是合法的链接点了(此时q中虽然包含np集合中最短串的最长后缀,但不是q的最长串),此时我们就需要将q这个点分裂,分成以np最短串的最长后缀为最长串的集合也就是新的合法的新链接点nq,这个时候我们就需要将原来q上的一些性质转移到nq上,首先q的链接点转移到nq上,q的链接边和np的链接边都连向nq,然后我们将连向q的转移边都改连向nq,这一步操作我们需要用p指针通过fa回跳来完成,接下来我们再将q连出的转移边复制到nq上即可。父节点集合的最长串 = 子节点最短串的最长后缀。

2024-10-18 00:52:16 253

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除