2025年7月学习总结

七月学习总结

7.8

下午 VP 了 CF1023 得到如下教训:

  • max和min的两个参数的类型 一定一模一样 。(绝对不可以 long long 和 int 混着用)

  • 思考构造方案时考虑极端情况,比如取极值,分组时将一个点单独分为一个组......

晚上学到了 势能分析法,详见 《势能分析法》

7.9

上午模拟赛,看到两道比较有价值的题目:

下午 VP 了 CF960 得到如下教训:

  • 提交前一定要再测一次题目样例。

晚上重要收获是 广义矩阵乘法

7.10

上午模拟赛,都是好题:

专业网络 贪心,模拟最优决策。

Interval Collection 线段树神题,问题转化后用线段树和STL容器维护信息。

7.11

下午VP CF941 1h无错切掉4题,感觉良好,启示:

  • 认真读题,不要漏掉关键信息而审错题意;

  • 正式思考前必须看样例解释,确保自己get到的和题目想说的一致

晚上VP CF1004 总结:

  • 面对难题乏力,有思路无法但落到算法。
  • 对中档题解决速度较慢,如 __CF2067D__花了 \(20min\)CF2067E花了 \(30min\)

7.12

P3168 可持久化线段树要开够空间( \(100\) 倍以上的空间是正常的)

P3810 做题时要看题目是否保证数据不重,写代码前要考虑如果有重复是否会对做题有影响。

7.13

CF2097C 神奇转化,将二选一的限制条件转化为图上给边定向

7.15

CF1572 吉司机线段套线段树求和

CF1983 将四点加取模转化为行/列和一定

7.16

P4849 四维偏序+DP,犯了一大堆错误,包括但不限于:

  • 没有存储原来的点编号,直接用排序后的点编号访问dp数组;
  • 树套树内外层询问的询问区间混用;
  • 方案数做加法运算时漏取模;
  • 没有把所有可以取到最大值的点的方案数加起来;
  • 树套树撤销时没有清除外层树上的 \(rt\) 数组;
  • dp数组没有初始化
  • CDQ分治时没有加入起点
  • 归并排序时没有用新数组存储

P4688 sort在自定义排序规则时,如果自定义规则不具有传递性,那么sort会有奇怪的问题(生成奇怪的元素)

​ 莫队可以将单次询问涉及多区间的问题一个区间一个区间地做,前提是可以将每个区间统计的信息合并。

​ 莫队可以做多次来减小因统计答案而需要的空间。

P7424 一切和分块有关的题目,都要在读入后马上把块长算出来。

7.17

P5443 操作分块+可撤销并查集,面对需要重构的问题可以使用操作分块。

归并排序前一定要确保两个数组在同种排序规则下有序

AT_tenka1_2014_final_d 神奇数学、序列操作题。

P3674 解题报告待补

7.21

构造专题

Cf538G Trick1:看到 UDLR 就把坐标轴逆时针旋转 \(45\) 度,再延长 \(\sqrt 2\) 倍,这样就把这四个移动的坐标变化分别为 \((+1,+1)\)\((-1,-1)\)\((-1,+1)\)\((-1,+1)\)

​ 这样就可以把 \(x\) 轴和 \(y\) 轴独立开来,分别处理。

​ Trick2:当每次操作形如 \(+1\)\(-1\) 时,可以把坐标 \(x_i\) 变成 \((x_i+t_i) \div 2\)\(t_i\) 是操作数),然后把操作变成 \(0\)\(+1\)。(理解:相当于加入时间上的距离,每次操作就变成 \(-1(\text{In position})+1(\text{In time})\)\(+1(\text{In position})+1(\text{In time})\),位置同理,最后把坐标整体缩小一半即可。)

​ 当题目所求具有周期性时,可以先考虑假设已知单个周期的影响,然后尝试列式,最后需要化简出若干关于单个周期影响的不等式,取交即为取值范围。

P7320 图上构造一般转化为二分图或树( \(dfs\) 生成树)上构造

​ 一棵树上的最大独立集大小不小于叶子个数,一棵树可以被 \(k\) 条路径覆盖的充要条件是这棵树有不超过 \(2k\) 个叶子。

ARC103F 树上构造一般可以考虑从叶子入手,处理完叶子后更新父亲子树大小后就可以把叶子删去。

CF1508D ”交换原排列使得新排列上每个位置上的值与位置相等“类问题优先考虑置换环。

​ ”平面上线段无交“可以考虑菊花图。

ARC131E 当题目只给出 \(n\) 时,考虑使用归纳法。

CF1270E 当题目条件不好刻画时考虑从题目特征入手。

​ ”集合不交”想到给集合内元素取模,取模就想到黑白染色。

​ 当网格上黑白染色所有点颜色相同时,可以考虑旋转网格,这样即使行列奇偶性一样的点对也可以变成奇偶性不同的点对。

7.22

P5278 一个乱序的等差数列具有以下性质:(令项数为 \(L\),公差为 \(k\)

  • 最大值和最小值的差为 \((L-1) \times k\)

  • 相邻元素的差的最大公因数为 \(k\)

  • 元素互不相同

CF1149C 树上问题转化为序列问题时,优先考虑欧拉序或 \(\text{dfn}\) 序。

​ 线段树维护区间信息并且有区间修改操作时,需要计算标记对一个信息的系数,不一定总是 \(1\)

ARC069D 2-SAT问题,但是边数过多,用线段树优化建图减少边数。

7.23

模拟赛的题目很妙啊。

异或序列 很容易想到 \(O(n^2)\) 的暴力dp,发现瓶颈在于枚举需要被容斥掉的数,通过打表发现被 \(i\) 容斥掉的数的 \(\text{highbit}\) 都出现在 \(i\) 中,因此开数组维护即可。

数圈圈 神奇分治题。在矩形上分治,只统计跨越分治中心的答案贡献。因为本题性质极佳,可以维护一个点往四个方向最远可以扩展到的位置,在分治中心上暴力枚举长度/宽度,用桶或树状数组进行统计即可。

​ 在 \(n*m\) 的矩形上分治时,如果复杂度中出现了 \(n^2\)\(m^2\) 时,可以考虑在分治时向下分割较长的边,这样复杂度就可以优化为 \(O(nm)\)

题目描述

CF932F 想到dp是简单的,由于转移方程式形如一次函数,因此考虑使用李超线段树进行优化。又因为一次转移只和一个点的子树相关,考虑树上启发式合并。

7.24

AGC061C

直接统计不好统,考虑容斥。对于一个人 \(i\),它可以有三种转移方式:

  • \(a_i\),系数为 \(1\)

  • \(b_i\),系数为 \(1\)

  • \(b_i\) 但是 \([a_i,b_i]\) 没有任何数,系数为 \(-1\)

容易发现前两种情况转移时简单的,直接 f[i+1]+=f[i] 就好。

对于第三种情况,我们维护一个区间 \([L_i,R_i]\),表示这个编号在这区间内的区间和 \(i\) 号区间有交。因为这个几个都不能选。所以转移为f[R[i]+1]-=f[L[i]]

Take away:容斥类dp的做题方法

P11427

注意到放入一个物品后,其左右形成的极大空位是独立的,而且 \(n\le14\),考虑状压dp。直接枚举每一种可能的被放入的物品集。在dp时,从小到大枚举每一个子集。对于当前枚举到的子集 \(S\),它分开左右两侧的物品一定是集合中编号最小的。然后直接枚举子树的放入物品情况。因为题目要求能放必须放,因此有 \(f_S \le a_i (a_j= \min_{k \in S} a_k, i \le j)\)

Take away:序列分段类的dp的思考方法

P5972

想到设 \(f_{i,S}\) 为长度为 \(i\) 且选择情况为S的最小逆序对个数,这样的 \(O(n2^n)\) 的朴素dp是简单的。但是这太不优秀了。

注意到转移时我们不是关注“谁大于 \(i\)”而是“有多少个被选的数大于 \(i\)”。因此我们考虑在 \(i\) 时,记 \(a_{i+1},a_{i+2},...,a_n\) 升序排序后剩下的数列为 \(x_{i+1},x_{i+2},...,x_n\),那么本质上我们只需要知道区间\((x_{i+1},x_{i+2}),(x_{i+2},x_{i+3})...(x_n,n]\)内分别有多少数。

所以设 \(f_{i,S}\) 为长度为 \(i\)\(S\) 表示上述区间内的数的个数情况(怎么存之后说)时的逆序对个数,转移是简单的:

如果不选,就有 f[i+1][S]=min(f[i+1][S],f[i][S])

如果选,就有 f[i+(统计S中大于a[i]的个数)][S+(i对S的贡献)]=min(f[i+(统计S中大于a[i]的个数)][S+(i对S的贡献)],f[i][S])

但是 \(S\) 的数量看起来非常多啊。注意在 \(i\) 时到 \(S\) 的总量为个区间长度 \(+1\) 的乘积。由柯西不等式可以得知,当且仅当区间长度全部相同时,\(S\) 取到最大值,那么我们可以粗略地估计 \(S\) 的总量不超过 \(n*x^{\frac{n}{x}}\),其中 \(x\) 为区间长度。

考虑计算这东西的上限:因为 \(n\) 是常数,所以我们只需要求 \(x^{\frac{1}{x}}\) 就可以了。因为 \(x\) 非负,所以可以取ln,即求 \(\ln x^{\frac{1}{x}} = \frac{\ln x}{x}\) 。再简单的求导,有:

\[(\frac{\ln x}{x})'=\frac{1-\ln x}{x^2} \]

容易发现当 \(x=e\) 时,总量最大。因为 \(x\) 是离散的,所以当 \(x=3\) 时,总量最大(这里取 \(3\) 还是取 \(2\) 可以考虑做积分,但是我不会)。

因此复杂度上限为 \(O(n3^{\frac{n}{3}})\),当然,如果你比较严谨,那你也可以表示为 \(\Large O(\sum \limits_{i=1}^n(\frac{n}{n-i+1}+1)^{n-i+1})\)。总之就是 \(O(\text{能过})\)

但是新的问题随之而来,怎么存储 \(S\) 呢?这就需要科技——变进制状态存储

当我们需要存储一个 \(n\) 维向量,且第 \(i\) 维的值域为 \([0,a_i]\)。那么对于向量 \((c_1,c_2,...,c_n)\) 可以被表示为 \(\large \sum \limits_{i=1}^n (c_i \times \prod \limits_{j=1}^{i-1} a_i-1)\)

实现看代码

Take away:变进制状态存储和状压dp的优化(状态数角度)

ABC310Ex

背包问题pro max version

首先,一个套路,在被消耗的数值(我们叫做“该值”)随着操作有增有减,且操作的顺序可以随意改变时,对于任何操作序列,一定可以通过重排,使得任意时刻该值不超过 \(2 \times \max |c_i|\) ,其中 \(c_i\) 是操作对该值的影响。

其次,对于经过上面处理的操作序列,一定可以被分解成若干长度不超过 \(2 \times max |c_i|\) 的小序列,使得每一个小序列均满足上述条件。这是很好理解的,小于 \(2 \times \max |c_i|\) 的序列显然;大于这个值的序列,由鸽巢原理可以得知,一定可以在序列中找到两个位置,使得处理操作到这两个位置时,该值一样,那么我们可以将这个序列取出来,然后重复。

最后,我们可以将一个长 \(i\) 的满足条件的序列视为一个体积为 \(i\) 且价值为 \(\text{这种序列可以造成的最大伤害}\)。跑多重背包即可。

最后一个Trick:对于一个容量极大的背包,它至多不选性价比最高的物品 \(2*max w_i\) 次,其中 \(w_i\) 是体积。

Take away:在问题不好处理时,先分析性质。(然并卵)

7.25

UOJ84

首先考虑简化问题:钦定第一个人(称为“本体”)负责一直向下走并被传送,第二个人(称为“分身”)负责遍历其余叶子并在到叶子后传送回第一个人。感性理解一下,这么做一定是对的。因为在两个人重叠时,我们总是可以认为传送回去的人是分身。

那么我们观察一下这个过程:在一个节点 \(u\) ,如果 \(u\) 只有一个儿子,那么直接一起向下走;如果 \(u\) 有不少于两个儿子,那么我们钦定一个儿子 \(v\) 表示本体接下来要往 \(v\) 走,本体在 \(u\) 点等待,分身去遍历除了 \(v\) 之外的儿子子树内的叶子;当只剩最后一个叶子未被遍历到时,本体也可以向下走了,因为 \(u\) 点除了 \(v\) 的子树内的也子没有再需要被遍历的了,因此不需要再在 \(u\) 点停留。

但是直接算耗时有点难受,不如我们来算节省的时间吧。设 \(f_u\) 表示从 \(u\) 到其子树内的一个叶子能节省的最长时间,再记 \(d_u\) 表示 \(u\) 的深度,\(e_u\)\(u\) 子树内的叶子个数,\(D(u,v)\) 表示在 \(u\) 子树内,\(v\) 子树外的最大叶子深度。那么存在转移:

\[f_u=min(f_v+(d_v-d_u)*e_v+min(0,d_v-D(u,v))) \]

但是直接转移是 \(O(n^2)\),不太行。我们注意到对于一个 \(v\),它转移到一个不满足 \(D(u,v) \ge d_u\)\(u\) 一定是不优的。同时我们想:如果一个 \(u\) 只有一个儿子,那么直接转移就好了;如果 \(u\) 的儿子不止一个,那么最优的方案一定不是从叶子深度最大的儿子传递上来的,因为它的 \(D(u,v)\) 一定比别人小;同时,我们发现:对于点 \(v\),它只需要转移给满足 \(D(u,v)\ge d_u\)\(d_u\) 最大的点 \(u\) 就好了,因为如果需要转移到一个深度更小的点 \(w\),那么也一定可以通过 \(v\)\(u\),再到 \(w\)

因为注意到dp和深度关系密切,考虑长链剖分。

本题 \(n\) 很大,不能递归建树,只能使用非递归版本。

具体实现见代码

Take away:长链剖分优化dp的经验

P5298

看到 \(D_i^2\) 就知道这是dp不可做的,只能老老实实把 \(D_i\) 算出来。

\(f_{i,j}\) 表示在点 \(i\),权值为 \(j\) 的概率,那么存在转移:

\[f_{i,j}= f_{ls,j}*(p_i* \sum \limits_{i=1}^{j-1} f_{rs,j} + (1-p_i)*\sum \limits_{i=k+1}^{n}f_{rs,j})+f_{rs,j}*(p_i* \sum \limits_{i=1}^{j-1} f_{ls,j} + (1-p_i)*\sum \limits_{i=k+1}^{n}f_{ls,j}) \]

应该还算比较显然。

注意到这玩意和左右儿子的 \(f\) 数组的前后缀和有关,在加上这 \(n\) 最大才 \(3\times 10^5\),一看就是给常数较大的 \(O(nlogn)\) 或者常数较小的 \(O(nlog^2n)\) 算法。

因此考虑线段树合并。在合并向下递归时,维护当前区间的前后缀和即可。

实现见代码

Take away:树上dp可以使用线段树合并进行优化。

qoj7597

首先,需要知道:最大匹配等于最小点覆盖。因此可以钦定一组大小为 \(k\) 的匹配和点覆盖。

然后我们发现,对于 \(k\) 条匹配边,它们一定恰好有一个端点在点覆盖中;而没有与匹配边相连的点,一定不在点覆盖中。

因此我们分别考虑两边的点:

  • 一共有 \(x_1\) 条匹配边,其中有 \(x_2\) 条的左端点在点覆盖中;

  • 一共有 \(x_3\) 条非匹配边,其中有 \(x_4\) 条的左端点在点覆盖中;

  • 一共有 \(y_1\) 条匹配边,其中有 \(y_2\) 条的左端点在点覆盖中;

  • 一共有 \(y_3\) 条非匹配边,其中有 \(y_4\) 条的左端点在点覆盖中;

那么对一个合法情况,一定存在 \(x1=y1=k\)\(x2+y2=k\)。因为所有非匹配边都需有一个端点被覆盖,所以有 \(x3+y3 \le min(x4+y4,m-x1)\)

那么我们可以对两边分别dp,状态记录下到当前点时 \(x1,x2,x3,x4\) 的情况。

统计时枚举两边所有合法情况并取最小值,并选取任意一对取得最小值的合法情况进行方案构造。

构造细节看代码

7.26

P7589 容易发现后退总是可以被前进抵消掉,因此是Nim板题

P2575

阶梯Nim:有 \(n\) 堆石子,第 \(i\) 堆石子有 \(a_i\) 个,每次操作可以将第 \(i\) 堆的若干(非零)石子移到第 \(i-1\) 堆,第 \(1\) 堆的石子不能移动。两人轮流行动,判断先手/后手必胜。

考虑对于编号是偶数的第 \(i\) 堆石子,每一次有石子从 \(i+1\) 移过来,下一个人一定可以移动等量石子到 \(i-1\) 堆。因此只需要用编号为奇数的石子堆判断就行了。

CF725F

分类讨论两个人分别什么时候会取第一张照片。

最后权值变为第一个人取为 \(a_i\),第二个人取为 \(-b_i\),要求总权值最大。那么可以全局答案加 \(\large \frac{a_i-b_i}{2}\),物品权值为 \(\large \frac{a_i+b_i}{2}\) ,第一个人取就加上权值,第二个人取就减掉权值,容易发现这样总是满足要求的。

ABC416E

图论练少了。

本题的难点在于怎么支持加边后维护最短路和刻画”飞机“这类道路。

对于第一个难点,我们发现加入一条边 \((u,v)\) 后,两点间最短路会发生变化,当且仅当新的最短路通过新加的边,因此只需要枚举两点,新的最短路距离就是两点分别到 \(u,v\) 的距离加上新边的边长。

对于第二个难点,这有一个经典Trick:当满足某些条件的两点可以通过某种方式任意互达时,可以新开一个点,满足条件的点向其连边权为代价的边,其向满足条件的点连边权为 \(0\) 的边

7.27

更新了数学相关学习笔记

7.28

P1397

矩阵乘法模板题,以下是运用到的卡常技巧:

  • 因为加减快于乘除,因此有 #define bmod(x) ((x)>=mod?(x)-mod:(x))

  • 因为矩阵很小,因此可以循环展开

  • 十进制快速幂……

P2044

矩阵乘法模板题,但是计算中会爆 long long,因此需要用龟速乘(即像快速幂一样处理乘法)

P4301

利用Nim游戏中先手必胜当且仅当石子数异或和不为零的结论,可以证明先手只需要取走出了构成线性基之外的石子堆,就可以必胜。因为线性基里的数都线性无关,因此异或和一定不为零。

CF895C

显然,一个平方数的唯一分解中各个质数的指数一定为偶数(好绕),那么我们只关心质数指数的奇偶性即可。因为最大的数不超过 \(70\),因此只有 \(19\) 个有效质数。因为原数组中若干的数的异或和一定可以被线性基中的元素的异或和表示,因此构造线性基后,答案就是 \(2^{n-\text{线性基大小}}-1\)

CF1163E

结论:存在一个长 \(2^x\) 的排列使得排列相邻两项的异或和都在集合 \(S\) 中,当且仅当 \(S\) 中的元素通过异或运算可以表示 \([0,2^x)\) 中的所有整数。

构造看题解吧……

CF348D

LGV 引理模板题,因为起点和终点一一对应,因此可以直接构造并求行列式。

P6657

很早之前写过了。因为起点和终点一一对应,因此可以直接构造矩阵,高斯消元后求行列式。

CF1100F

时间戳线性基模板题。

具体地,在插入 \(x\) 并枚举位数时,若 \(x\) 的第 \(i\) 位上为 \(1\)\(d_i\) 存在,那么就比较 \(x\)\(d_i\) 被插入的时间,如果 \(x\) 被插入得更晚,那么就交换 \(x\)\(d_i\) ,异或后继续向下枚举。这样可以保证每一个 \(d_i\) 都是当前时间戳最大的。

P9041

神仙题。

首先看到 DAG 和不相交路径数就应该想到 LGV 引理。因为求的是不交路径的存在性,那么可以给边随机赋权,最后如果矩阵的行列式不为零,那么存在不相交路径;如果为零,那么矩阵的秩表示最多有多少起点和终点可以通过不相交的路径相连。本题就属于后者。

那么我们可以先维护每一个点的向量(也就是那些起点到该点的距离构成的向量),一个区间就构成了一个矩阵,因为要维护矩阵的秩,也就是最大线性无关的向量集合,因此考虑线性基。值得一提的是,本题的线性基是向量线性基。

统计时维护时间戳线性基,并对 \(r\) 做扫描线,对时间戳排序就可以了。

P10698

神仙题 plus 版。

边不交转换为对边建点,共点就连边。DAG 和 不交路径看起来很 LGV 引理。因为答案最大值为 \(k\),因此可以建 \(k\) 个虚点连向 \(1\) 号点;同时因为答案不超过 \(k\) ,在处理一个点的入边和出边的转移时,显然入边大于 \(k\) 条的部分是无效的,因此只需要用线性基维护 \(k\)线性无关向量即可。

7.29

P3391

板子题,为此学了 FHQ Treap。

详见 FHQ Treap 学习笔记

P7739

神奇矩阵乘法题。

首先来看 \(f\) 展开会是什么样子:

\[ \frac{1}{x_0+\frac{1}{x_1+\cdots}} \]

这是一个连分数的形式,这里有一个(非常不)显然的Trick:

考虑令 \(a_i\) 处理后,得到的分数为 \(\large \frac{A_i}{B_i}\) ,那么有:

\[\frac{A_i}{B_i}=\frac{1}{a_i+\frac{A_{i-1}}{B_{i-1}}}=\frac{B_{i-1}}{a_i*B_{i-1}+A_{i-1}} \]

那么存在转移:\(A_i=B_{i-1},B_i=a_i*B_{i-1}+A_{i-1}\)

注意到这是一个线性递推式,可以用矩阵表示:

\[\begin{bmatrix} A_i \\ B_i \end{bmatrix}=\begin{bmatrix} 0 & 1\\ 1 & a_i\end{bmatrix}\begin{bmatrix} A_{i-1} \\ B_{i-1}\end{bmatrix} \]

那么整个式子的值可以表示为:

\[\begin{bmatrix} 0 & 1 \\ 1 & a_1 \end{bmatrix} \begin{bmatrix} 0 & 1 \\ 1 & a_2\end{bmatrix} \cdots\begin{bmatrix} 0 & 1 \\ 1 & a_k\end{bmatrix} \begin{bmatrix} 0 \\ 1\end{bmatrix} \]

那么我们接下来分别描述 WE 对式子的值的影响:

经过一番分析,我们发现 W 可以用 \(\begin{bmatrix} 1 & 1 \\ 0 & 1\end{bmatrix}\) 表示,E 可以用 \(\begin{bmatrix} 0 & -1 \\ 1 & 2\end{bmatrix}\) 表示。

接下来是数据结构部分:支持加入节点、区间翻转的数据结构,想到平衡树。

每一个节点维护:

  • 正向连乘的值

  • 逆向连乘的值

  • 正向反转连乘的值

  • 逆向反转连乘的值

就做完了。

P13356

首先考虑 \(k\) 的含义:把边分成 \(k\) 组,每一组最多 \(n-1\) 条边。

看到 \(n-1\) 想到生成树,于是就维护 \(k\) 棵生成树,每一次加边时二分找到第一棵两个端点不连通的图即可。

AGC016E

正难则反,由易到难。

考虑一只火鸡 \(i\) 要活到最后,那么在一次为 \((x,i)\) 的操作中,\(x\) 一定会被吃掉,反过来,在此之前,\(x\) 一定不能被吃。

那么就对于每一只火鸡,维护一个集合 \(S_i\) 表示为了使 \(i\) 活下来,当前不能被吃的鸡的集合;倒序枚举每一次操作,如果当前操作中有一只鸡不能被吃,那么另一只鸡在当前被吃,在之前不能被吃,因此把另一只鸡加入集合中;如果两只鸡都不能被吃,那说明 \(i\) 被吃定了。

现在考虑两只鸡 \((i,j)\) 活到最后的情况,如果 \(S_i\)\(S_j\) 无交,那么一定可以;如果有交,对交集大力讨论一下,发现怎么样都不行。于是就转换为求 \(S_i \cap S_j = \emptyset\) 的二元组 \((i,j)\) 个数。

P9731

由易到难。

考虑 \(S=2\) 怎么做。因为对于同一行只有换和不换两种状态,因此可以转化为在同一行的两个题目之间连边,给边定向(这个Trick疑似太典了)。

同时我们注意到提交总数为奇数的题目一定只有奇数个,那么我们可以开一个新点,度数为奇数的题目向该点连边,那么此时所有点的出入度相等且都为偶数,那么就可以跑欧拉回路

尝试推广,看到 \(S=2^k\) 就应该想到分治。对左右两边进行同样的操作,只不过是变为同一行左右相同位置连边罢了。

CF1956E2

如果可以一直暴力模拟就好了……

考虑一直模拟直到最后的情况:序列由若干个长度为 \(1\) 的非零极长子段和一堆 \(0\) 构成,答案显然。

再往前一点:序列由若干个长度为 \(2\)\(1\) 的非零极长子段和一堆 \(0\) 构成,因为长度为 \(2\) 的极长子段中,前者一定可以打败后者,因此答案显然。

那么此时至少需要枚举 \(O(\sqrt{V})\) 次,不可以接受;

再往前一点:序列由若干个长度为 \(3\)\(2\)\(1\) 的非零极长子段和一堆 \(0\) 构成,在长度为 \(3\) 的极长子段中,最后一个人受到第二个人的伤害一个等差数列,可以\(O(1)\) 计算出来并判断。

次数至少需要枚举 \(O(\sqrt[3] V)\) 次,可以接受。

P10360

我想枚举操作,分类讨论(当前两位是否已知,如果已知那它是什么)地搜索并暴力统计答案,但这样是 \(O((n+m)2^n)\) 的,不太行。

注意到答案要求对 \(2\) 取模,这意味着如果存在两种情况的贡献相同,那么可以忽略这两种情况,那么我们发现在一次操作 \((a_i,b_i)\) 中,\(x_{a_i}=1,x_{b_i}=0\)\(x_{a_1}=0,x_{b_i}=1\) 的结果一样,那么它们的贡献一样,就可以忽略掉,单次扩展的状态数由 \(4\) 降低到 \(2\),新的时间复杂度为 \(O((n+m)\sqrt {2^n})\)

P9521

如果可以一直走直线就好了……

考虑最优路径需要拐弯需要满足什么。

对于 \(l<k<r\) , \(i<j\)\((l,i)\)\((r,j)\) 有三种走法。

  1. \((l,i) \rightarrow (l,j) \rightarrow (r,j)\) 花费为 \(b_l*(j-i)+a_j*(r-l)\)

  2. \((l,i) \rightarrow (r,i) \rightarrow (r,j)\) 花费为 \(b_r*(j-i)+a_i*(r-l)\)

  3. \((l,i) \rightarrow (k,i) \rightarrow (k,j) \rightarrow (r,j)\) 花费为 \(a_i*(k-l)+b_k*(j-i)+a_j*(j-k)\)

如果拐弯更优,那么有第三种的花费小于前两者,那么解不等式后有:

\[\frac{a_k-a_l}{k-l} \le \frac{b_j-b_i}{j-i} \le \frac{a_r-a_k}{r-k} \]

典型斜率优化形式,对于行列分别维护一个下凸壳,每一次贪心地往斜率小的方向走。

AGC057D

考虑对于每一个二元组 \((i,S-i)\),集合 \(A\) 中一定恰好包含其中一个。那么集合 \(A\) 的最大大小为 \(\lfloor\frac{n-1}{2}\rfloor\),并且我们只需要考虑 \(\lfloor\frac{n-1}{2}\rfloor\) 的部分(设这部分集合为 \(B\) )即可。

考虑 \(B\) 中最小的元素,一定是满足 $ p \nmid S$ 的最小的 \(p\) ,易证 \(p \le 43\) 。那么考虑 \(x,y \in B\),那么 \(x+y \in B\) 一定成立,因此我们可以将整个集合 \(B\) 分为 \(p\) 个剩余类。贪心地,我们令 \(f_i\) 表示模 \(p\) 后余数为 \(i\) 的最小值。那么对于一个新加进来的数 \(v\) ,有转移 \(f_i \leftarrow f_{i-vk \bmod p}+vk (k \in R)\),同时因为构造合法,存在 \(f_{n \bmod p} > n\),因此对于每一个新加入的数,存在 \(v \ge \lfloor \Large\frac{n-f_{n-vk}}{k} \rfloor \normalsize+1\)

(一下内容可以结合 同余最短路的转圈技巧 ——Alex_Wei 食用)注意到 \(f\) 的转移形式很像一个完全背包,那么可以考虑转圈圈。具体地,这是一个模 \(p\) 意义下的完全背包,那么对于一个体积为 \(v\) 的物品,它在长度为 \(p\) 的序列上存在 \(\gcd(v,p)\) 个子环,从一个点出发不会再回到该点,因为如果存在这类情况总可以把该物品换成若干基准物品(也就是 \(p\))。因此加入一个物品 \(v\) 时只需要在子环上转两圈即可遍历到所有转移。

P6240

猫树分治维护dp,可以看一下代码,里面定位节点应该是详细的了。

P3804

参考资料:ZTer的文章

SAM 模板,有时间再补学习笔记吧。

7.30

qoj6308

发现常规贪心和dp不能做,于是开始找神奇性质。

发现对于两个区间 \([l_1,r_1]\)\([l_2,r_2]\) ,如果存在 \(l_1 < l_2 <r_1 <r_2\) 那么 \(r_1\)\(l_2\) 一定只可以留一个。注意到这样的二元限制都是一个左端点和一个右端点,因此我们考虑到二分图,如上述的情况就右端点向左端点连边。想要留下来的最大,那么就是要求该二分图中的最大独立集,跑匈牙利算法就行。

但是空间只有 \(16 \text{MB}\),因此要 bitset 优化,详见代码

P6219

构造题,注意到 \(n\) 很大,考虑二进制拆分。

手玩几组数据后发现,我们可以实现 $ \times (-2)$ 的操作,那进行 \(-2\) 进制拆分即可。

7.31

今天写的题有亿点多……

P3966 ACAM 板子题,跑一边匹配后子树求和即可。

P2414 ACAM 板子题,读入Trie后构造 ACAM,在结束节点上用链式向前星挂询问即可。

P5840 ACAM 不那么板的板子题。因为一次匹配对一个模式串只做一次贡献,因此对所有匹配到的点按 dfn 序排序,相邻点求 LCA 消除重复贡献即可。

P4052 ACAM 上 dp,因为合法不好求,因此求非法串数量。dp 是朴素的,只是不转移到结束节点即可。

P3311 ACAM 上 dp,因为有不大于 \(n\) 的限制,因此把是否受到 \(n\) 的限制加进状态里。

P4112 广搜模板题,看到子串,想到后缀自动机;看到子序列,想到子序列自动机。因为 \(O(n^2)\) 可以接受,因此直接在对应自动机上暴力广搜。

P4555 Manacher 的初步应用。先跑一遍 Manacher,然后对于一个点 \(i\) 维护当前点可以向左/向右扩展的最长回文串长度(不一定是一个极长回文串)。

P3649 PAM 板子题。一个回文串的出现次数等于其在 fail 树上的子树内的出现总次数。

P4762 PAM 上dp。对每一个状态维护长度小于等于自己长度的一半的回文后缀中长度最长的状态。dp不太朴素。

P5685 广义 PAM 板子题。

P3975 SAM 求第 \(k\) 大(本质不同)子串。

P4070 SAM 维护本质不同子串数。

P4248 SAM 求 LCP 长度和。倒序建 SAM,LCP 就是两个状态在 Parent 树上的LCA,考虑每一个点做 LCA 贡献的长度。注意:只有实点有大小

P2178

上一题的加强版。

考虑一个点的贡献的区间:\([len_{link_i}+1,len_i]\)

对第二个问的贡献:即以自己为 LCA 的点对数,可以通过儿子的 \(size\) 求出来。

对第一个问的贡献:考虑到点权有正有负,因此维护每一个点当前子树内的最大值和最小值。在点 \(p\),对第二问的贡献是 \(max(mx_u*mx_v,mn_i*mn_j)\) 其中,\(u,v,i,j\)\(p\) 的儿子。

可以线段树维护。

P4094

参考资料:Forwarcl的题解

首先,答案具有可二分性。

问题转化为 \(s[ l : r ]\) 中是否有子串和 \(s[c : c+mid-1]\) 相同。

那么我们可以通过倍增跳 link 找到表示 \(s[c : c+mid-1]\) 的节点,然后用线段树判断其在 \([l+mid-1,r]\) 是否存在 \(endpos\) ,这可以通过线段树合并预处理实现

P4770

参考资料:shadowice1984 的题解

题目转化一下就是问 \(T\) 中有多少本质不同的子串在 \(S[l:r]\) 中出现过。

如果没有区间的限制,那么考虑 \(T\)\(S\) 的 SAM 跑匹配,这样可以得出 \(T\) 的每一个前缀可以匹配出的最大长度。

那么答案就是 \(T\)\(\sum \limits_{u \in SAM_T} max(ans_{len_u}-len_u,0)\) ,其中 \(ans_i\) 表示 \(i\) 点表示前缀的最大匹配长度,这么求是因为对于一个 \(endpos\) 等价类,只有长度小于等于对应匹配长度的串,才可能在 \(S\) 中出现过。

现在来考虑区间限制。如果可以把 \(S[l:r]\) 的 SAM 单独挑出来就行了……

但其实没必要,因为对于一条转移边 \((p,q0\),如果 \(p\) 在区间 \([l+len_p,r]\) 内有 \(endpos\),那么这条转移边就可以走。

\(endpos\) 集合区间查询可以通过线段树合并实现。

End

七月应该是全身心投入信息学的一个月,本月在主要三个平台的刷题总数为 \(66 (\text{In Luogu})+14(\text{In Atcoder}+49(\text{In Coderforces}))=132\),如果算上模拟赛和其他 OJ 的提交之类的应该有 \(160+\) 题。

这么一看自己好像有点疯狂……

希望 \(8\) 月能做到 \(7\) 月的一半吧。

posted @ 2025-07-23 21:30  XiaoZi_qwq  阅读(8)  评论(0)    收藏  举报