2023.7 做题记录
CF1842F *2500 \(\color{green}\bigstar\)
看到这个两边取个 \(\max\) 加起来就可以想到树的带权中心,这样一条边的贡献就是 \(k\) 减去两倍的子树内个数。
然后发现求最大值,而选中心作为根就是最大值。
因此枚举一个根,然后直接考虑每个位置染色的贡献,排个序即可。
CF1842G *2800 \(\color{blue}\bigstar\)
高妙啊,首先显然需要乘法分配率去展开那个式子。
一开始的想法是对于选了多少个 \(v\),画一个竖着的柱状图,然后发现这个东西非常难做。
考虑画一个横着的柱状图,一个地方我要选 \(v\) 了,那么有两种情况,第一种是这一行前面已经选过了,否则就新开一行。
然后设计一个 dp,\(f_{i,j}\) 表示前 \(i\) 个里面,有 \(j\) 行已经有东西了的和,直接转移。
CF1842H *3000 \(\color{blue}\bigstar\)
一开始的想法是枚举一个集合 \(>\frac{1}{2}\),这样分成两个集合,集合内部的就不用考虑了,只需要考虑中间的限制条件,那么中间的限制条件可以把 \(<\frac{1}{2}\) 的元素变成 \(1-a_i\),然后全部一起排序,可以发现一条限制条件就对应在这个排序后的东西上的一个先后关系。
相当于后面有一个拓扑序计数。
不可做啊,两部分都是 \(O(2^n)\) 的。
两个一起 dp,考虑按照排序后的东西去一个一个选,那么如果钦定当前是 \(<\frac{1}{2}\),那么说明以及选的数里不能存在和 \(>1\) 的限制条件, \(>\frac{1}{2}\) 的同理。
这样就是 \(O(n2^n)\) 了。
uoj462 \(\color{green}\bigstar\)
读完题就会做了,但大家好像都做了很久?
首先一条重链肯定是一个点出发到一个叶子。
很容易搞出一个 \(O(n^2)\) 的 dp,就是 \(f_{i,j}\) 表示 \(i\) 子树内,重链一条是 \(i\) 到 \(j\) 的最小值。
注意到转移就是链旁边毛毛虫这样一条的和,因此考虑在 dfs 过程中维护每个叶子对应的 dp 值,只需要区间修改,因此线段树即可。
uoj164 \(\color{Gold}\bigstar\)
降智了啊,以为是维护加多少和减多少��标记,然后可以知道一个点的值,但是无法维护历史最值。
换成维护一个操作,把下传的标记换成加上一个数,再和一个数去 \(\max\),三个修改都可以表示,并且这个东西可以直接合并。
P6242 \(\color{blue}\bigstar\)
万 恶 之 源。
3.67k,写了半天。
学习了一下 beats,就是说区间取 \(\max\) 操作,这个东西可以维护区间最小值和次小值,然后找到修改的东西在这两个中间的时候,对于最小值进行区间修改,否则递归。
然后这题思路就比较简单,就是区间取 \(\max\) 的时候对区间最小值的区间修改操作,然后还需要维护历史最值,因此要开一堆标记,然后维护。
线段树卡空间方法:
#define mid ((l+r)/2)
#define ls mid*2
#define rs mid*2+1
这样只需要开两倍空间即可。
loj3495 \(\color{green}\bigstar\)
这个东西等价于带权重心。
瞎 jb 证明一下,发现满足条件的点一定是一条链。
直接点分值,然后没啥细节就写完了。
也可以 dsu on tree 啥的。
loj6892 \(\color{green}\bigstar\)
什么几把破题,赛时很快就会了,没时间写,赛后写了好久,然后卡常卡一年。
这个题和 回转寿司 比较像,但是修改是全局的,而且数据范围也没办法分块。
用类似的思路,因为观察到一个修改操作经过一个区间,对于区间和的影响就是把这个数放进来,然后把最小值扔掉,然后可以发现操作顺序无影响,因此可以把操作放到一个堆里,然后和区间里的数合并。
然后考虑一个询问是咋操作的,相当于是 \([1,l-1]\) 这个区间里的数和堆里的数去合并,去除前(询问个数)个元素,然后再和 \([l,r]\) 去合并,选出 \(r-l+1\) 个最大的数,这就是答案。
具体咋维护呢,就是直接主席树上二分得到最后答案的数的区间然后加起来即可,然后询问的堆用一个权值线段树去维护。
一开始写的是二分然后再询问,复杂度 \(O(n\log^2 n)\),结果一个点跑了 \(20\) 秒。
换成主席树上直接二分,复杂度 \(O(n\log n)\),然后跑了 \(7\) 秒,因为线段树询问次数较多,常数比较大。
卡常半天,当天在 loj 上过了,但是这个代码跑得非常惊险,而且不用快读过不去,洛谷上无法通过。
今天又来卡常,终于在洛谷上过了,code,甚至跑得比 loj 上快。
卡常小技巧:
void Ad(seg, int x, int z) {//AC
s[p] += z, sum[p] += 1ll * x * z;
if (l == r) return;
x <= mid ? Ad(lid, x, z) : Ad(rid, x, z);
}
void Ad(seg, int x, int z) {//TLE
if (l == r) {
s[p] += z, sum[p] += 1ll * l * z;
return;
}
x <= mid ? Ad(lid, x, z) : Ad(rid, x, z);
s[p] = s[ls[p]] + s[rs[p]], sum[p] = sum[ls[p]] + sum[rs[p]];
}
这就是个普通的线段树单点修改操作,上面的是在递归的过程中直接修改,下面的是修改叶子然后 up 上来。
loj 上,每个点快 0.1s,洛谷上,每个点快 0.5s+。
不懂了啊,反正过了。
uoj180 \(\color{gray}\bigstar\)
签到,不合法的东西就是 \(A\) 里一个小的东西在一个比他大的东西的前面,然后 \(B\) 里跑到后面去了。
树状数组瞎维护。
uoj181 \(\color{blue}\bigstar\)
不错的题。
这个东西开始想的是和这题一样去阴间容斥 dp,然后发现根本不需要啊,因为竞赛图缩点之后是一条链,问的又是强联通个数,因此直接枚举割集加起来即可,暴力枚举复杂度 \(O(m2^n)\)。
然后去考虑一下复杂度和 \(m\) 有关的算法。
去枚举那些边会对答案产生贡献,那么会发现这样划分成若干个连通块,每个连通块对应一个二分图,然后由于其他边全部都是 \(\frac{1}{2}\),因此可以背包合并起来算答案,复杂度 \(O(n^22^m)\),但还是过不去。
把上面两个东西结合一下,因为可以把连通块合并,我们找出原图每个连通块分开做,而一个连通块最多只有 \(m+1\) 个点,因此直接按照枚举割集即可,然后合并。
复杂度 \(O(n2^m+n^2)\)。
uoj182 \(\color{red}\bigstar\)
不会多项式。
uoj186 \(\color{green}\bigstar\)
一个需要被删掉的点,需要找左右比它小的不能被删掉的点,然后看这个区间里比它大的点的个数。
离线,并查集即可。
uoj187 \(\color{green}\bigstar\)
比较套路的斜率优化。
uoj188 \(\color{red}\bigstar\)
阿拉丁题,有时间再做。
uoj193 \(\color{blue}\bigstar\)
先考虑生成树计数咋做。
可以矩阵树,但是也可以直接状压。
具体来说,一个集合 \(S\),拿出最小的和第二小的两个点分别为 \(x,y\),然后以 \(x\) 为根,枚举 \(y\) 所在子树的集合,然后合并就可以 \(O(3^n)\)。
然后考虑基环树计数咋做。
基环树相当于每个点指定一个出边,那么就是度数之积,然后可能不连通,所以容斥一下,然后可能会把一条边重边看成是基环,因此直接减去生成数个数乘以边数,最后由于环有两个方向所以除以二。
这部分是 \(O(n2^n+3^n)\)。
最后是考虑贡献,这个去染色,相当于所有点可以染黑白,然后叶子不能染黑。
容斥,去枚举染黑了的叶子集合即可。
这部分用 dfs ,复杂度可以做到 \(O(3^n)\)。
loj3806 \(\color{Gold}\bigstar\)
抑郁症题。
首先先把不在 \(1\) 到 \(n\) 路径上的点扔掉,这个可以建圆方树做。
剩下的,看每条边,如果一条边不在任意一条最短路上,那么一定有远路。
否则,一条可以走远路的边 \((x,y)\) 满足存在 \(1\to x\to y\to n\) 和 \(1\to y\to x\to n\)。
可以发现不存在这样边的图就是一个“西瓜图”,也就是起点和终点有若干条链,然后每条链上有可能有类似的结构。
但是不会判断。
事实上有个重要性质,就是一个点度数为 \(2\) 就可以直接扬了。
不断缩点,如果最后只剩两个点说明没有远路。
CF1168D \(\color{blue}\bigstar\)
先可以考虑一个简单的 dp,就是从下向上跑,然后统计子树里一个字母的链最多是多少,然后合并即可。
答案就是把所有字母减去后就是问号个数,轻松求出答案。
唯一的问题是可能有一个点字母总数超过最长链,这样无解。
正解是考虑叶子深度相同,因此把没有分支的链合并,剩下的树高为 \(\sqrt{n}\),直接暴力即可。
模拟赛时没有观察到这个,直接大力维护,一个修改的贡献相当于修改一条向上的链,可以倍增然后 chk,修改直接树剖。
CF1845F \(\color{blue}\bigstar\)
观察一下,\(i,j\) 撞到一起的条件是 \(t(a_i+a_j)\bmod 2l=0\) 或者 \(t(a_i-a_j)\bmod 2l=0\)。
卷积一下求出 \(a_i+a_j,a_i-a_j\) 是那些数。
然后相当于有一堆 \(k\),然后需要满足 \(t=x\frac{2l}{k}\) 就是合法的,\(x\) 需要是正整数。
注意到 \(k\) 的合法集合包含了 \(k\) 因数的,因此把所有因数也加入集合,然后开始容斥,把可以被自己因数表示的减掉即可。
复杂度 \(O(n\log n)\)。
ABC309Ex \(\color{Gold}\bigstar\) *3029
妙啊。
一次询问都不会做。
这个东西一般是直接容斥,走到上下边界,但是这样复杂度爆炸。
还是要考虑多项式,要每次把 \(0\) 和 \(m+1\) 项去掉。
一个很牛的做法是考虑放到一个长度 \(2m+2\) 的环上,然后令一遍放一个对称的 \(-1\),这样就抵消掉了,然后直接卷积即可。
CF1835D \(\color{blue}\bigstar\)
\(k\) 很大,大概就是在提示你乱走都可以。
大概证明一下,如果有多条路径,长度分别为 \(a_1,a_2,a_3,...,a_n\),放同余最短路上,最大只会有 \(a_1a_n\),也就是 \(n^2\) 级别,远远到不了。
先强连通缩点,一个里面要找出所有路径长度的 \(\gcd\),这个不好求,但是 \(\gcd\) 可以做差,因此枚举一条边,这样就可以找到 \(1\to y\) 和 \(1\to x\to y\) 的差,枚举所有边就可以得到 \(\gcd\),然后答案乱做即可。
ABC308Ex \(\color{green}\bigstar\) *2861
逆天,看错题意然后过了,以为是数据水,然后发现可以证明和原问题一样。
看成边不能在环上,利用求最小环的套路,相当于找到那个连出去的点,那么就是把除了它之外的所有点都 floyd 加进去,然后算即可。
这个可以线段树分治或者分块达到 \(O(n^3\sqrt{n})\) 或者 \(O(n^3\log n)\)。
然后这个为什么和原问题等价呢,因为如果一条边连向了环上的一个点,就可以缩成一个更小的 “Q”。
\(O(n^3)\) 也不难,因为连出去的边只可能是最小的三条边之一,因此枚举这条边,然后删掉,跑单源的最小环,这个可以用 dij 做到 \(O(n^2)\)。
ABC307Ex \(\color{gray}\bigstar\) *2754
板子,卷积匹配通配符。
ABC306Ex \(\color{green}\bigstar\) *3335
场上过的人只有一个日本人,剩下都是中国人,看来 DAG 容斥套路被玩烂了。
最后图是个 DAG,容斥找入度为 \(0\) 的点,那么这些点之间一定都是 =
,那么找有多少个连通块,容斥系数就是 \((-1)^{c+1}\),直接 dp 即可。