Codeforces 2400+ 口胡
评分2400+,通过人数从大到小排序。
A:想出正解并且完成代码;
B:想出正解未完成代码;
C:未想出正解但完成代码;
D:未想出正解未完成代码。
开始刷的时候没有保存网页,刷着刷着,题目通过人数更新,就都乱了。
342E C
点分树板子
假如能维护 \(c_x\) 为 \(x\) 子树内离 \(x\) 最近的红色点距离。
一开始想的是树剖这个东西,询问拆成查询它到根的链中最低的红点,和以它到根的链中的点为 LCA 的红点。前者很容易树剖两个 \(\log\) 解决。如果维护的 \(c_x\) 都是加上它到重链底部的距离的值,这样查询就是查询一个最小值,而修改变成了公差为 \(2\) 的等差数列加。对于每一个重链开一个李超树支持区间插入线段查询区间最低点(修改 \(\log^2\),查询 \(\log\) )可以做到 \(\log^3\)。总复杂度就是 \(\mathcal{O}(n\log^3 n)\),没有实现是口胡的所以可能有误的一个想法(
如果把询问看成对端点为 \(x\) 的所有路径看哪个最短路径满足端点为红色,从而想到树分治。建出点分树之后,端点 \(x\) 的路径一定经过 \(x\) 在点分树内的祖先,那么维护每个点在点分树的子树内的红点,在原树里离它最近的距离是多少,查询的时候 \(x\) 加上到它点分树内祖先的距离加上这个最小值,取个 \(\min\) 就好。
修改的话直接暴力跳点分树里的父亲然后更新就可以。统计到的路径可能会产生折返,但其实比它优的一定能统计到所以无关紧要。
375D B
做个 dsu on tree,\(c_i\) 代表 \(i\) 颜色出现了几次,\(a_i\) 代表有多少颜色 \(\geq i\),每加进来一个颜色这两个都可以直接维护。时间复杂度是 \(\mathcal{O}(n\log n)\)。
321E D
决策单调性
449D C
F M T
实际上就是个位运算卷积的背包,只需要每个 \(F_i=x^{a_i}+x^{U}\) 位运算卷积卷起来即可(\(U\) 是全集),如果直接暴力把每个 \(F\) 都卷起来是 GG 的,注意到这个做 FMT 也就是后缀和,所有位置不是 \(1\) 就是 \(2\),或者说只有 \(a_i\) 的前缀是 \(2\),其他都是 \(1\)。
所以 \(\prod FMT(F_i)\) 的每个位置都是一个 \(2\) 的次幂,而指数就是有多少个 \(a_i\) 的前缀包含它。
那么对 \(a\) 开个桶做一个高维后缀和,每个位置就是 \(\prod FMT(F_i)\) 每个位置的指数,求出 \(\prod FMT(F_i)\) 再 \(IFMT\) 回去。
55D B
数位 dp,记录模 \(7\times 8\times 9\) 的值以及最后一位是否是 \(0\) 或 \(5\),还有哪些数出现了。
感觉会跑的比某些 \(lcm(1\sim 9)\) 的快不少(
865D D
模 拟 费 用 流 / 反 悔 贪 心
\(S\) 连向每个点 \(i\),费用为 \(-p_i\),流量为 \(1\);
每个点 \(i\) 流向 \(T\),费用为 \(p_i\),流量为 \(1\);
\(i\) 流向 \(i+1\),费用为 \(0\),流量为 \(+\infty\)。
然后是最大费用可行流。
把 \(i\to i+1\) 形成的看成一个主干,那么就是若干条连向主干的流,每次是加进来一个从主干流出的流,一个流到主干的流。
如果可以流走,一定是选择前面一个费用最大的,并且和当前这个流走的费用相加 \(>0\),从这个地方流走,然后还会加进来一条反过来流向主干的流,可以用一个堆来维护。
3D D
反悔贪心。
钦点一遍选价格更小的那个括号,然后从前往后 check,每次如果是一个右括号就把改成左括号的代价扔进堆里,如果在哪里右括号多了,就把之前一个代价最小的改成左括号。然后再倒着改一遍。
508D B
建图跑欧拉通路。
把两个字符组成的串看成点,给定的每个串 \(abc\) 看成边(这里 \(abc\) 代表三个字符),然后 \(ab\to bc\),跑有向图欧拉通路。
1473E D
喵喵分层图题。
考虑限制松一些,一条路径的权值变为总权值 \(-\) 任选一条边的权值 \(+\) 任选一条边的权值,发现这个问题和要求是等价的,因为贪心一定会选最大的和最小的。
把减去的权值视作魔法一,加上的权值视作一个魔法二。
建分层图,把图分成四层,分别代表没使用魔法。只使用了魔法一,只使用了魔法二,两个魔法都使用了。然后建出图之后最短路。
trick 大概就是把限制松一松然后发现和原问题还是等价的。
1375E D
构造。
考虑紧一点的限制,是个排列。
如果能每次把 \(n\) (当然 \(1\) 和 \(n\) 是等价的)放到对应的位置,且正好只用掉和下标 \(n\) 有关的逆序对,并且剩下的 \(1\sim n-1\) 号位相对大小关系不变,则可以每次把问题规模缩小 \(1\) 从而解决问题。
记 \(pos_x\) 为 \(x\),\(j\) 代表一开始的 \(a_n\),不断地交换 \((pos_{j+1},n),(pos_{j+2},n),\cdots(pos_n,n)\)
首先这些一定把和下标 \(n\) 有关的逆序对都干翻了,然后我们其实是让 \(j\) 到了 \(j+1\) 的位置,\(j+1\) 到了 \(j+2\) 的位置... \(n\) 到了 \(j\) 的位置,满足把 \(n\) 放到对应位置且剩下的 \(1\sim n-1\) 号位相对大小关系不变。这样每次就能把问题规模缩小 \(1\) 从而解决问题了。
446C C
斐波那契数列:\(f_1=f_2=1,f_n=f_{n-2}+f_{n-1},n\geq 3\);
广义斐波那契数列:\(F_1=p,F_2=q,F_n=F_{n-2}+F_{n-1},n\geq 3\);
注意到 \(a_i=a_{i-2}+a_{i-1},b_i=b_{i-2}+b_{i-1}\Rightarrow a_i+b_i=(a_{i-2}+b_{i-2})+(a_{i-1}+b_{i-1})\).
所以就能把若干个(广义)斐波那契数列合并成一个广义斐波那契数列,只需要用线段树维护然后记录头两项的 tag 即可。
时间复杂度 \(\mathcal{O}(q\log n)\)
有一个更简单的做法是直接利用斐波那契通项公式,然后区间加等差数列区间求和就可以,因为 \(\sqrt 5\) 在模 \(9998244353\) 意义下有二次剩余所以甚至不需要扩域。
1083E B
斜率优化。
145E B
线段树板子。
455D D
直接对每个块内用一个双端队列存值,开一个桶。查询的时候整块之间的直接一边弹出一边弹入,散块就暴力重构一遍双端队列,这些都是易维护桶的,查询就直接整块查桶散块暴力查。
1187D B
把限制紧一紧,只能对长度为 \(2\) 的区间进行排序,发现这个和原问题等价,因为可以给一个区间 sort 可以用冒泡排序而冒泡排序只需要对长度为 \(2\) 的区间排序。
然后只需要依次考虑 \(b_i\) 在 \(a\) 中是否能移到 \(i\),再把 \(b_i\) 在 \(a\) 中删掉,然后就能把问题规模缩小 \(1\)。用线段树维护区间最大值支持单点删除(赋值为负无穷)。
trick 大概就是把限制紧一紧然后发现和原问题还是等价的。正好对应上了 CF1473E 的 trick。
449C D
喵喵题。
先把 \(1\) 和 \(>n/2\) 的质数 \(p\) 给干掉。
对于每一个大于 \(2\) 的质数 \(p\),找出它的倍数且没有被匹配过的数,如果有偶数个直接两两匹配,如果是奇数个,把 \(2p\) 鸽在一遍,其他两两匹配。这样剩下的都是偶数,可以两两匹配。
这样匹配出来的对数正好达到了匹配的上界,所以是对的。
444C B
比较板的数据结构题。
实际上就是区间覆盖,查询区间和。
sol1: 直接分块,整块暴力打标记,散块直接重构,\(\mathcal{O}(n\sqrt n)\)。
sol2:每次覆盖上一种颜色,颜色段最多会产生 \(\mathcal{O}(1)\) 个,开个 set
维护颜色段,再开棵线段树每次分裂/删除/插入的时候在线段树上修改就可以,均摊下来复杂度是 \(\mathcal{O}(n\log n)\)。
311B B
比较板的斜率优化。
注意到最优一定是每次主子接猫一定有一个刚好接到的。
首先处理出 \(t_i\) 代表第 \(i\) 只猫子需要主子在 \(t_i\) 时刻出发正好接到这只猫子,排下序做个前缀和。
\(f_{i,j}\) 表示前 \(i\) 只猫子有 \(j\) 个主子来接的最小等待时间之和,斜率优化一下。
932E B
基础推式子,把普通幂转下降幂就好做了。
1000F B
直接扫描线。
484D D
划分成若干个单调的一定更优,然后就可以快乐dp了。
设 \(f_i\) 为前 \(i\) 个数的答案,如果 \(a_{i-2},a_{i-1},a_i\) 单调则可以 \(f_i=f_{i-1}+|a_i-a_{i-1}|\),否则 \(i\) 单独划分,\(i\) 和 \(i-1\) 划分一段分两种情况转移。
1401E D
考虑每加入一条线段之后产生的新矩形数,每产生一次交点就会使得连通块数 \(+1\),假想线段从边缘往里面延伸的过程,前面经过的连通块不会和后面经过的连通块是同一个连通块,要不然会出现两端都不在边界上的线段。
所以答案就是线段的交点数+两端都触及边界的线段数。
用线段树解决。
1358E B
如果 \(k\) 可以为答案,那么 \(2k\) 一定可以为答案,于是只需要判断是否存在 \(>n/2\) 的解。
对其作一个前缀和,后半部分变成了等差数列。\(k\) 可以为答案当且仅当 \(s_0<s_k,s_1<s_{k+1},...\),问题变成了判断一个数组的前 \(k\) 个是否和一个等差数列后 \(k\) 项一一对应 \(<\)。
如果 \(x\geq 0\) 显然只判断 \(k=n\) 是最优的;
当 \(x<0\) 的时候,一个想法是用线段树做这个东西,\(k\) 从小到大判断,对于一个 \(k\),前 \((k-1)\) 个对应的限制会越来越松,然后会新加进来 \(k\) 位置这个限制。可以提前计算出每个位置需要松几次才能松成合法,然后每加进来一个数的时候,相当于对一个前缀 \(-1\),然后单点插入一个数,查询一个前缀是否都 \(\leq 0\),用线段树做就可以了。
其实也不用这么麻烦,计算出 \(i\) 松几次其实就能算出 \(k\geq p_i\) 的时候这个位置变成合法,直接扫,当 \(\max p_i\leq k\) 的时候输出答案。
626F B
排下序,利用“费用提前计算的思想”设计 dp:
设 \(f_{i,j,k}\) 为考虑前 \(i\) 个,有 \(j\) 组还可以加,总代价是 \(k\),设 \(t=j\times(a_i-a_{i-1})\) 转移有:
-
新开一组还可以添数的:\(f_{i,j,k}\to f_{i+1,j+1,k+t}\);
-
新开一组不能添数的:\(f_{i,j,k}\to f_{i+1,j,k+t}\);
-
添到一组后面且不作为那一组的最后一个数:\(f_{i,j,k}\times j\to f_{i+1,j,k+t}\);
-
添到一组后面且作为那一组的最后一个数:\(f_{i,j,k}\times j\to f_{i+1,j-1,k+t}\)
时间复杂度 \(\mathcal{O}(n^2k)\)
1394B D
虽然是 2300 但我依然没看出来...
一个合法的方案会使得图变成若干个互不相交的环。满足每个点入度和出度都为 \(1\) 即可。
称一种选择为 \(c_x=y\),对于一个点,可以根据它的入边处理出这些选择两两互斥关系,然后枚举 \(c\) 所有情况,\(\mathcal{O}(k^2)\) 来检查是否合法。
1369E B
猜出来做法但是不会证无解
菜为点食客为边连出图来,把菜的个数看成点权。这样更好描述一些。
设点权为 \(w\),度数为 \(d\).
如果一个点 \(i\) 满足 \(w_i\geq d_i\),那么与这个点相邻的边放在最后,一定能被删掉。
现在假装这个点以及其相邻的边不存在,会出现新的一些点满足 \(w_i\geq d_i\),不断这样做下去即可。
如果有边还存在,但不存在符合条件的点,也就是 \(\forall i,w_i<d_i\ \text{or}\ d_i=0\),那么无解。因为无论怎样删边,这个条件依然会满足,在最后所有 \(w\) 都为 \(0\) 的时候,仍然会有边存在。
1340C D
化成分层图,\((x,y)\) 代表在绿灯开始后的第 \(y\) 秒位于 \(x\) 节点,这里的 \(x\) 是安全路口和终点。那么可以建出一张 \(\mathcal{O}(mg)\) 个点,\(\mathcal{O}(mg)\) 条边,边权为 \(0/1\) (只有 \((x,g)\to(x,0)\) 的边为 \(1\),代表走过了一段绿灯+红灯),用 01bfs 求出到 \((m,i)\) 的最短路即可。
1348E D
假如只把相同颜色的果子放在一起,会剩下 \(\sum a\bmod k\) 个红果子,\(\sum b\bmod k\) 个绿果子,这是可以构造出来的答案的下界。
剩下的红果子个数 \(<k\),蓝果子个数 \(<k\),果子和 \(<2k\),最多会凑出一个篮子,所以答案的上界是我们可以轻易构造出的下界 \(+1\).
现在要判断这个上界是否能达到,我们可以假装全部相同颜色装在一起,然后拆篮子,通过在装同一棵树上的果子来消耗掉剩余的果子。
设 \(f_{i,j}\) 代表考虑前 \(i\) 个树,消耗的红果子个数在模 \(k\) 意义下为 \(j\),那么消耗的蓝果子数就是 \((k-j)\bmod k\),是否存在一种方案。
若 \(f_{i,j}=1,k-(\sum b)\bmod k\leq j\leq (\sum a)\bmod k\),那么即存在一种方案可以拆开一些篮子然后消耗掉剩余的果子来达到答案的上界。
直接 dp 的复杂度为 \(\mathcal{O}(nk^2)\),可以前缀和优化优化到 \(\mathcal{O}(nk)\)。
1428F B
第一眼扫描线,然后用个对左端点对应的 \(f\) 开棵值域线段树,支持区间求和,区间清空,单点插入即可解决问题。
但还是做麻烦了,有更简单的做法。
考虑 \(r-1\to r\) 之后左端点对应的 \(f\) 总和增加了哪些。
- \(a_r=0\),没用,什么也没增加;
- \(a_r=1\),设当前这个极长后缀全 \(1\) 段的长度为 \(len\),上一个长度为 \(len\) 的全 \(1\) 段的开头位置为 \(l\),则 \((l,r]\) 中所有的左端点代表的 \(f\) 值都要 \(+1\),这个东西用个数组 \(c_i\) 代表长度为 \(i\) 的全 \(1\) 段最后一次出现的开头在哪里,是很简单就可以维护的。
这样时间复杂度就是线性的,还极度好写。
1392F D
最终情况一定是相邻两项差值 \(\leq 1\)。
考虑从前往后依次考虑山丘,模拟这个过程,发现相邻且相等的平坡最多会有一个。
通过计算看看平坡在哪里即可。
1251E2 D
人类智慧贪心题。
从大到小考虑 \(m=i\) 的选民,假装 \(<i\) 的全部都收入囊中了,看看算上之前收买的,是否还需要收买 \(\geq i\) 的,如果需要就挑 \(p\) 更小的收买掉,用一个优先队列模拟这个过程。
贪心的正确性大概是因为 \(m<n\)?不懂,教教。
1051F D
感觉是简单套路题可是为啥没想到啊。
求个生成树,返祖边上的点称为特殊点,不超过 \(2(m-n+1)=42\) 个。路径分两种:
- 不经过特殊点,直接 LCA 求就行。
- 经过特殊点:\(\min_{k\text{ is special}}dis_{x,k}+dis_{y,k}\)
那么只需要预处理出从特殊点开始的单源最短路径即可。
622F B
多项式,直接插值。
986C D
开虚点优化建图,每个点向自己补集对应的虚点连边,每个虚点向自己对应的实点连边,向自己仅少一个元素的子集连边。
边数大概是个 \(\mathcal{O}(2^nn)\),感觉很能跑过去。
815C D
树上背包/jy
设 \(f_{i,j,0/1}\) 为点 \(i\) 子树内选了 \(j\) 个点,当前点有无使用优惠券。
246E B
整出来bfs序,就是区间数颜色。
也可以线段树合并,以深度为下标,在叶子节点上用个 set
维护颜色集合。
1491E D
一棵树割的方法要不然是割掉大小为 \(f_{n-1}\) 的子树,要不然是有两个 \(f_{n-2}\) 的子树可以割。如果是前者直接割,后者的话任选一个割。
数学归纳法可知后者的两种割法是等价的,区别在于两条边哪一条先割。
斐波那契数列的增长速度是 \(\mathcal{O}(\phi^n)\),所以这样做的时间复杂度为 \(\mathcal{O}(n\log_{\phi}n)\).
1326E D
答案是单调不升的,所以每加入一个 \(q\),就不断判断答案是否合法即可。
假设当前答案为 \(x\),判断当前答案是否会 \(<x\) 当且仅当:
- 最后一个 \(\geq x\) 的数后面至少有一个炸弹;
- 倒数第二个 \(\geq x\) 的数后面至少有两个炸弹;
- \(...\)
也就是对于所有 \(\geq x\) 的 \(p_i\), \([i,n]\) 中的炸弹数 大于等于 \([i,n]\) 中的 \(\geq x\) 的数的个数。
反之,如果存在一个 \(\geq x\) 的 \(p_i\),\([i,n]\) 中的炸弹数 严格小于 \([i,n]\) 中的 \(\geq x\) 的数的个数,则说明这个 \(p_i\) 不会被炸掉,答案是 \(\geq x\) 的。
限制松一松,对于任意的 \(i\),发现还是等价的。
用线段树维护 \(a_i\) 代表 \([i,n]\) 中的炸弹数 \(-\) \([i,n]\) 中 \(>x\) 的数个数。
支持前缀修改,查询全局最大值,线段树。
528D D
用 FFT 解决字符串匹配问题。
分别仅考虑 \(A,C,G,T\),把匹配成功的位置取个交集就可以。
现在仅考虑 \(A\),把 \(S\) 中不会和 \(A\) 匹配上的位置上的字符设为 \(o\),把 \(T\) 中不是 \(A\) 的字符设为 \(\#\).
则构造匹配函数 \(C(x,y)\) (其中 \(x\) 来自 \(S\),\(y\) 来自 \(T\)):
设:
-
\(S\) 中的 \(A\) 值为 \(0\),\(o\) 值为 \(1\);
-
\(T\) 中的 \(A\) 值为 \(1\),\(\#\) 值为 \(0\);
-
\(C(x,y)=(x-y)^2\).
用 FFT 完成计算。
暴力解法:可以把 \(S\) 换成四个 \(01\) 串,\(1\) 代表这个位置可以匹配 \(A/G/C/T\),然后 \(T\) 中一个字符相当于限制住一些匹配位置不合法,那么用 bitset
来暴力做这个东西,每次把 \(t_i\) 对应的 \(S\) 右移 \(i\) 位,再和答案取个或,最终 \(1\) 的位置就是合法的位置,时间复杂度是 \(\mathcal{O}(\frac{nm}{w})\) 的。
379F D
降智了...考虑更强的问题,任意树,每次新建一个点与树中一个点相连。
结论:设原先直径为 \((u,v)\),新建的点为 \(x\),若直径改变,则为 \((u,x)\) 和 \((v,x)\) 其一。
可以用类似证明两次 dfs 求直径方法正确性的思路来证明。
632E B
很明显的多项式快速幂/jk,直接暴力多项式快速幂,\(\mathcal{O}(n^2\log n\log k)\),算量大概是在 2e8,跑过去还挺轻松?
有巧妙(?)的 \(\mathcal{O}(n^3)\) 做法/jk
设最小物品体积为 \(v\),则每个能拼出来的物品一定有 \(k\times v\) 体积在下面垫着,让全部的物品体积都 \(-v\),这样子就会出现体积为 \(0\) 的物品,所以 dp 每个物品用这样的物品最小需要几个非 \(0\) 的物品,如果最小需要的个数 \(<k\),用 \(0\) 补上就可以了。复杂度是 \(\mathcal{O}(n^3)\) 卡着脖子过/jk/jk
1523D D
答案一定是给出的某个集合的子集。
随机这个集合,用它的子集来更新答案,假设选取了 \(x\) 次,那么这 \(x\) 个集合都不在那 \(\frac{n}{2}\) 个集合中的概率为 \(\frac{1}{2^x}\),为了防 hack,让随机到的集合两两不同。
判断这个集合的所有子集是否是答案很简单,只看所有数与这个集合的交集,开个桶,做个高维后缀和就可以。
1375F A
比较谔谔的简单题。先钦点 \(a<b<c\),不失一般性。
选择成为先手,如果出现等差数列,且后手上一次不能对最大的进行操作,那么输出公差就赢了。
发现如果让 \(a,b\) 变成等差数列最后一项,都是让它们加上 \(2c-a-b\).
那么先输出 \(2c-a-b\),如果后手让 \(a,b\) 增加的话就赢麻了,否则就是让 \(c\) 增加。
那么再输出新的 \(2c-a-b\),后手不能让 \(c\) 增加,只能给 \(a,b\) 增加,这样就又赢麻了。
786C D
对于每一个 \(k\),假设能 \(\mathcal{O}(1)\) 找出对于一个 \(l\),最大的 \(r\) 使得 \([l,r]\) 内区间颜色数 \(\geq k\),就能 \(\mathcal{O}(n\log n)\) 解决,因为对于每一个 \(k\) 最多会找 \(\frac{n}{k}\) 次。
那么现在问题变成快速对于一个 \(l\),求一个最大的 \(r\) 使得 \([l,r]\) 内区间颜色数 \(\leq k\),而且要求在线,但对于每个 \(k\),\(l\) 的询问是递增的。
考虑采用 HH的项链 那道题的trick,以 \(l\) 作扫描线,对于 \([l,n]\) 中的每个位置记录它是否是 \([l,n]\) 中第一次出现,区间颜色数即为区间和。
现在问题变成了支持单点修改,快速求一个最大的 \(r\) 使得 \([1,r]\) 的和 \(\leq k\),树状数组上倍增就可以。
总的时间复杂度是 \(\mathcal{O}(n\log^2n)\)
1408E D
给每个集合建一个点,一个元素如果被包含在这个集合中,就和这个集合代表的点连边,连出来是一张二分图。
对于这个二分图上的任意环都可以去掉中间连接的代表集合的点,变成原图中的环;原图中的环都可以在这条边上插入一个代表集合点,这个集合使得这条边连起来了。
这样建立了原图中环和二分图中环的双射,原图中不存在环等价于二分图中不存在环。
此时二分图中每个边都有了断掉这条边所需要的代价,断掉边使得代价总和最小等价于求最大生成树。
798D D
去年还做过但是没看出来...
按照 \(a\) 从大到小排序,\(n\) 为奇数的话钦点选 \(a_1\),偶数的话钦点选 \(a_1,a_2\),然后相邻两个分为一组,对于一组内的 \(a\),发现任选即可满足 \(a\) 的限制,因为最坏情况下是满足条件的。
既然可以任选,选择一组中 \(b\) 较大的那个即可满足 \(b\) 的限制。
1469E D
观察到两个串 \(A,B\) 不相似当且仅当 \(A\) 的反串和 \(B\) 相同。
那么每一个长度为 \(k\) 的串的反串都会限制答案,求一个字典序最小且没有被限制的串。
- 把所有限制串扔到哈希表里,从全 \(0\) 开始枚举答案,每次暴力 \(+1\) 然后暴力进位复杂度是 \(\mathcal{O}(+1次数)\) 的,暴力 \(+1\) 和进位使得可以方便地维护答案串的哈希值来判断当前答案是否合法。
- 另一种解法,确定最后 \(20\) 位之后前面就可以全填 \(0\),因为限制串最多 \(10^6\) 个,而 \(2^{20}>10^6\).注意如果前面有多余的空可以全填 \(0\) 的话,有些串的限制会消失掉,需要处理一下。然后暴力枚举后面 \(20\) 位来判断。
547D A
看到 \(x,y\) 和 \(n\) 数据范围一样就默认 \(x,y\leq n\) 然后挂了好几发...
以行和列看成点,点看成所在行和所在列的边,连出来一张二分图。
现在要求给每个二分图定向,使得每个点入度和出度相差 \(\leq 1\),然后处理方法就很多了。
好像常见的做法是度数为奇数的点一定只有偶数个,把这些点多连一条边到一个虚拟节点(或者建虚拟边两两匹配),然后在新图上跑欧拉回路,依照这个把边定向。
我阿巴了一个解法,不知道本质是不是相同的。
发现如果可以把二分图拆成一个个偶环,即满足条件。去掉偶环,剩下的一定是若干个两两不相交的链,随意按照一个方向定向即满足条件。
写法上的细节就是直接 dfs,做个类似 dinic 当前弧优化的东西来保证复杂度是线性的。
1257F D
没想到折半搜索...
枚举 \(x\) 的前15位,然后把每个数只看前15位的 \(popcount\) 哈希一下放到一个哈希表里面。
枚举 \(x\) 的后15位,现在知道每个数后15位的 \(popcount\),再枚举总数,就知道每个位置的 \(popcount\) 应该是多少,在哈希表里面查一下。
复杂度 \(\mathcal{O}(n\sqrt a\log a)\).
1305F D
有意思。
如果 \(\gcd=2\),那么答案 \(\leq n\),则最终答案中修改值 \(>2\) 的不会超过 \(n/2\) 个,也就是修改值 \(\leq 2\) 的不会多于 \(n/2\) 个。
那么随机一个数 \(a_i\),答案是 \(a_i,a_i-1,,a_i+1\) 的因数的概率是 \(\frac{1}{2}\),多随机几次然后 check 答案。
868F D
神
考虑 \(f_{i,j}\) 代表前 \(i\) 个数分成 \(j\) 段,然后有个决策单调性优化,但是这个一段区间的代价 \(w(l,r)\) 比较难算,如果单独看这个东西是小 Z 的袜子,可以归约到 \(O(\sqrt n)\times O(\sqrt n)\) 的矩阵乘法,看上去很完蛋。
但注意到如果选择分治来算这个决策单调性,\(w\) 用类似莫队的东西暴力移动两个指针,由于分治最多有 \(\log n\) 层,每层的移动次数是 \(\mathcal{O}(n)\) 的,所以这个 \(w\) 的统计次数是 \(\mathcal{O}(n\log n)\) 的,总复杂度就是 \(\mathcal{O}(kn\log n)\).
1481E C
神
一个书不会移动多次,如果移动多次显然只有最后一次有用。
反过来,统计最多有多少个不动。
设 \(f_i\) 为完成最终目标 \([i,n]\) 最多能保留几个不动。
最优化这个有两种方式:
- 把 \([1,i]\) 里面所有书扔到后面:\(f_i\gets f_{i+1}\)
- 保持 \(a_i\) 不变,把 \([1,i-1]\) 里的书扔到后面:
- \(f_i\gets cnt_{a_i}\),其中 \(a_i\) 不是 \(a_i\) 第一次出现,对应先把 \([1,i-1]\) 都扔到后面,然后把后面不是 \(a_i\) 的往后扔。
- \(f_i\gets cnt_{a_i}+f_{r_{a_i}+1}\),\(a_i\) 是最后一次出现,这个就是夹在 \(a_i\) 之间的和当前这个 \(i\) 前面的都扔到后面去。
read(n);
for(int i = 1; i <= n; ++i) read(a[i]), l[a[i]] = !l[a[i]] ? i : l[a[i]], r[a[i]] = i;
for(int i = n; i && ++ct[a[i]]; --i)
if(i != l[a[i]]) f[i] = Max(f[i+1], ct[a[i]]);
else f[i] = Max(f[i+1], f[r[a[i]]+1] + ct[a[i]]);
printf("%d\n", n-f[1]);
631E B
固定 \(i\),看 \(i\) 移到哪个 \(j\) 前面的答案最大,如果往后移动也是同理反过来就行。
设 \(all\) 为不移动的答案,\(s\) 为 \(a\) 前缀和。
有个 \(all-a_i\cdot i+a_i\cdot j+s_{i-1}-s_{j-1}\)
\(all-a_i\cdot i+s_{i-1}\) 是个定值,先不管。
找到一个 \(j\) 满足 \(j\cdot a_i-s_{j-1}\) 最大,直接上李超树维护这个东西。
当然也可以斜率优化,每次在单调栈上面二分。
时间复杂度都是 \(\mathcal{O}(n\log n)\)
467D B
建反图缩点之后拓扑排序dp
1436E B
莫队冲冲冲
判断 mex 是否为 \(x\),相当于判断由 \(x\) 分割成的若干区间内,是否存在一个区间 \([1,x)\) 都出现过。
以 \(r\) 作扫描线,维护每个值最后出现位置,支持单点修改,查询区间最小值就可以了。时间复杂度是 \(\mathcal{O}(n\log n)\)
莫队做法大概就是 "判断由 \(x\) 分割成的若干区间内,是否存在一个区间 \([1,x)\) 都出现过。" 其实判断这些区间的 mex 是否是 \(x\),离线下来跑莫队就可以了,用那个 \(\mathcal{O}(1)\) 修改,\(\mathcal{O}(\sqrt n)\) 查询的值域分块,复杂度就是 \(\mathcal{O}(n\sqrt n)\) 的。
506D D
想不出来的时候就想暴力,然后优化优化,然后尝试平衡复杂度(虽然这题没有把两个暴力拼起来平衡复杂度)
对于每一个颜色开个并查集,会用到的点数只有 \(2m\) 个。
然后对于一个询问 \((u,v)\),对其中一个点出边的颜色所在的并查集,看 \(u,v\) 是否连通,由于 \(u,v\) 是等价的,所以查询度数 \(d\) 较小的那一边。
如果一个询问询问了多次,可以直接用之前已经得出的答案。
这个复杂度是有理有据的,对于 \(d>\sqrt{2m}\) 的点,最多有 \(\sqrt{2m}\) 个,查询的复杂度为 \(\mathcal{O}(\sqrt{2m}\times \sqrt{2m}\times \sqrt{2m})=\mathcal{O}(m\sqrt m)\).
对于 \(d<\sqrt{m}\) 的点,最多查询 \(q\) 次,查询的复杂度为 \(\mathcal{O}(q\sqrt m)\),如果把并查集的复杂度看成常数的话总复杂度就是 \(\mathcal{O}((m+q)\sqrt m)\).
应该还有其他拼暴力的方法,但这个一个暴力就够了。
1325E D
以为求无向图最小环能有更快的方法就没想不出来了。
求乘积是完全平方数,经典处理技巧是把每个质因子的次数的奇偶性看成一个数在模 \(2\) 意义下的向量(其实就是 01 串),乘积为完全平方数等价于求和为全 \(0\)。
因子不超过 \(7\),说明质因子个数不超过 \(2\),先将每个数的完全平方因子给去掉。
如果剩下的质因子个数为 \(0\),就找到一个完全平方数。
为每个质数都开一个点,如果一个数的质因子个数为 \(2\),就在两个质数之间连边。
再开一个虚点,如果一个数的质因子个数为 \(1\),就在这个质数和虚点之间连边。
现在每个数变成了边。发现给出的数的任何一个子集,其积为完全平方数,在图上也对应着一个环,这个环也唯一对应着这个子集。
那么就变成了求无向无权图最小环问题。注意到除了虚点外,如果两点之间如果存在边,那么至少有一个是 \(\leq 10^3\),如果两个都大于,这条边对应的 \(a\) 就超出给定的范围了。所以只对 \(\leq 10^3\) 以及虚点为根,跑 dfs 树 / bfs 找一遍最小环。
1107E D
一开始想到的 dp 是 \(f_{i,j,k,0/1}\) 为区间 \([i,j]\) 删剩余 \(k\) 个 \(0/1\), 然而这样转移还需要枚举中间点,以及左侧剩了多少,时间复杂度是 \(\mathcal{O}(n^5)\) 的。
新套路:区间 dp 不仅可以记录当前区间删剩余了多少,也可以记录假装后面有多少。
\(f_{i,j,k}\) 为区间 \([i,j]\) 和假装后面有 \(k\) 个 \(s_j\) 的最大分数。
- \(f_{i,j,k}\gets f_{i,j-1,0}+a_{k+1}\)
- \(f_{i,j,t}=\max\{f_{k+1,j-1,0}+f_{i,k,t+1},a_j=a_k\}\)
每一种删除方式都被这两种转移所包含。
915F B
最大值和最小值可以拆开分别来算,都是一样的。
一开始想的是点分治一下然后暴力统计,这样需要写个平衡树,是 2log 的。
路径上点权的最大值,可以令边权为相邻节点的点权最大值,这样就能化点权为边权了。
单独考虑每条边的贡献,由于是一棵树,所以按边权排序之后扫一遍,以一条边合并两个连通块时,贡献次数就是两个连通块的 size 乘积。
613D B
建出虚树来贪心一下就可以了。
896C B
经典,典中典。
数据随机启示我们要乱搞,用 set
维护连续颜色段,然后暴力就可以了。
840D A
之前做这题的时候用根号分治卡常擦着时限过的。
还有很多种做法:
设 \(d=\frac{r-l+1}{k}\),根据抽屉原理答案一定出现在区间排名为 \(1,d+1,2d+1,...\) 的数中,对于每一个,看它在区间内出现次数是否符合条件。写个主席树支持查询区间第 \(k\) 大和一个数出现次数。
383E B
设总有效字符数为 \(m=24\)
对于一个集合而言,答案为 包含其中一个字母的单词数 \(-\) 同时包含两个字母的单词数 \(+\) 同时包含三个字母的单词数。
同时包含三个字母的单词数就是完全包含在集合中的单词数,做个高维前缀和就可以了。复杂度 \(\mathcal{O}(2^mm)\)
只看前两项,\(f_S\) 为集合元音字母集合为 \(S\) 时的答案,从 \(f_{S-\mathrm{lowbit}(S)}\) 转移而来。复杂度 \(\mathcal{O}(2^mm)\)
有更简单做法:
经典套路正难则反:与集合有交的集合数 \(=\) 总集合数 \(-\) 与集合不相交集合个数 \(=\) 总集合数 \(-\) 其补集的子集出现次数。
这样一遍高维前缀和就ok了。
12D B
离散化一下,按照 \(a\) 排序从大往小扫,当扫到了 \(i\) 号人,每次相当于查询之前的人中,满足 \(b_j>b_i\) 的 \(j\) 中,\(c_j\) 最大为多少。
以 \(b\) 为下标,\(c\) 为值,每次相当于单点取 \(\max\),查询后缀最大值,用个线段树 / 树状数组即可解决。
348C A
遇到这种奇怪的维护操作就去想根号分治,看到 \(\sum S\) 就去想大小大于根号的 \(S\) 只有根号个,不同大小的 \(S\) 只有根号个(虽然这题没用到这个)
默认 \(n,m,q,\sum |S|\) 同阶。
大小 \(<\sqrt n\) 的称为小集合,\(>\sqrt n\) 的称为大集合,其中大集合的个数不超过 \(\sqrt n\) 个。
可以提前 \(\mathcal{O}(n\sqrt n)\) 地预处理出与其他所有集合之间有多少重复的元素,开个桶就可以。
对于每个大集合,直接记录 \(w\) 为集合内所有数的和,记录一个 \(v\) 代表 \(2\) 操作给这个集合加了多少。
-
对于大集合的修改:\(\mathcal{O}(\sqrt n)\) 复杂度内给其他每个大集合记录下产生贡献(通过预处理已经可以 \(\mathcal{O}(1)\) 算出 \(w\) 应该增长多少)。
-
对于小集合的修改:给原数组对应处的位置加上数,然后也是将 \(\mathcal{O}(\sqrt n)\) 个大集合的 \(w\) 加上某个数。
-
对于大集合的询问:大集合和小集合的修改都已经修改到了 \(w\) 上,所以答案就是对应的 \(w\).
-
对于小集合的询问:首先 \(\mathcal{O}(\sqrt n)\) 遍历原数组对应处位置,能知道小集合的修改对其的贡献;然后遍历 \(\mathcal{O}(\sqrt n)\) 个大集合,根据预处理和 \(v\) 的记录能够 \(\mathcal{O}(1)\) 算出大集合的修改对其的贡献。
综上所述,复杂度为 \(\mathcal{O}(n\sqrt n)\).代码
555E A
点对之间是否存在可达路径 \(\to\) Tarjan(不要想支配树了啊喂你又不会建支配树)
按照边双缩个点,缩出来一棵树(圆方树)。一个边双内的点对肯定能互相到达,连出来一个环就可以。现在只有边双之间的点对,看看是否能满足所有的 \(s\to t\),随便钦点一个根,有边既要朝向根又要朝向叶子就不合法,用个树上差分解决。
yy的边差分竟然是麻烦了,点权代表点和父亲的边权,边差分作子树和更好写。码量巨大...写了3k代码。
1043F D
观察到答案最大:
x1= 3*5*7*11*13*17
x2=2 * 5*7*11*13*17
x3=2*3 * 7*11*13*17
x4=2*3*5 * 11*13*17
x5=2*3*5*7 * 13*17
x6=2*3*5*7*11 * 17
x7=2*3*5*7*11*13
为 \(7\),所以从 \(2\to 7\) 依次判断是否为答案。
\(\gcd\) 为某个数的方案数可能比较难算,可以考虑 \(\gcd\) 为某个数倍数的方案数,然后莫比乌斯容斥。
\(\gcd\) 为某个倍数的方案数就是一个组合数,不过中途的运算结果可能很大,瞎yy个模数就跟哈希一样就可以了。
莫比乌斯容斥(或者说另外一个形式的莫比乌斯反演)有个更好写的写法,或者说这个写法是直接容斥。
设 \(g_i=\sum_{i|n}f(n)\),那就有 \(f_i=g_i-\sum_{j\geq 2}f_{ij}\),倒推就可以,时间复杂度是调和级数。
1329C D
可以直接贪心删,从根开始能删就删,否则递归到左右子树继续删。简单维护每个节点到删到最后要走到的叶子的 dep 即可。
第一眼感觉不大对劲,想想确实有道理。
6D B
远古题。直接爆搜+剪枝
考虑先射后射没有区别,那就从左往右依次发射火球。当前点的火球可能影响上一个的血量,上一个不必 GG 可以到当前再让他 GG。向前一个人发射了多少火球也会影响当前人的血量,向倒数第二个人发射的火球会影响倒数第一个人的血量,而处理当前点是否发射火球,\(i-2\) 及以前的都要 GG,所以我们要考虑的状态到这里为止就可以了。
所以就 \(f_{i,j,k}\) 为 \([1,i-2]\) 都 GG,给 \(i-2\) 了 \(j\) 发火球,给 \(i-1\) 了 \(k\) 发火球。然后大力转移。时间复杂度是 \(\mathcal{O}(nh^3)\),记个后缀 \(\min\) 转移可以做到 \(\mathcal{O}(nh^2)\).
1373F A
设 \(x_i\) 为 \(b_i\) 分给了 \(a_i\) 多少,然后就可以愉快地跑差分约束了,但 \(n\) 特别大。
我凑怎么看错题了只需要判有无解(也是由于看错题才一眼看出差分约束)
那么无解就是判正环,考虑图具体是什么样子的,容易得到记录给前缀和及其加个什么东西的最小值,再判掉不经过源点的环就可以了。
简单的1log做法!考虑二分 \(x_1\) 为多少,这样就能一路推下去具体的分配,然后考虑如果在中途有一个位置不够了,那就是留给自己的 \(x_1\) 多了;如果推到最后 \(a_1\) 不够了,那就是留给自己的 \(x_1\) 少了。据此来看,是单调的,可以二分。
932F B
\(f_x\) 为点 \(x\) 的答案,转移的柿子一看就很斜率优化,用平衡树维护凸包启发式合并就可以了,时间复杂度 2log
平衡树太难写可以动态开点李超树合并,这样不需要斜率优化限制住的性质也是可以做的,根据dqa大佬的分析,其复杂度是 1log 的,大概就是这种李超树插入直线,每条直线最多在一个节点中出现,每次合并的时候要不然一个直线 GG,要不然一个直线所在节点的深度 \(+1\),均摊下来复杂度是 \(\mathcal{O}(n\log n)\),当然如果直接无脑启发式合并就是 2log.
化柿子的时候化成一次函数的形式更直观一些(对我来说)。
如果是单调栈上二分 / 单调队列,这一类的,通常都是斜率或者某些东西具有单调性,这个东西不需要也尽量不要对每一种情况都整理下来应该怎么优化,是死板的。斜率优化是把一类 dp 问题变成数据结构问题,让数据结构维护这个凸包(或者说维护凸包上两点连线的斜率),应该具体情况具体分析。
如果加的决策点没有单调性,通常是 平衡树 / CDQ 分治 来解决,平衡树的话就是直接维护这个凸包,CDQ 分治则是通过分治来转成静态问题,然后用单调栈等数据结构解决。
有一种更普遍的做法,跳出维护凸包给我们思维上的限制,用李超树来维护一次函数(直线),也是一个 \(\log\) 的,而且码力要求和常数上肯定都优于平衡树,但常数还有可能比较大(相比 CDQ 分治来说?),但不需要动脑子(也就是前文说的具体情况具体分析,分析哪些变量是单调的,这个凸包的形状是怎样的,依次加进去的决策点坐标的单调性,截凸包的直线斜率的单调性...),论性价比李超树也是一个很好的选择。
715C D
树上满足某种条件的路径个数要想到点分治
点分治,对于一个分治中心,求出子树中每个节点自上而下的数字 \(d_1\pmod m\),匹配上另一个自下而上的数字 \(d_2\pmod m\),其深度为 \(k\),要满足 \(d_2+d_1\times 10^k\equiv 0\pmod m\Rightarrow d_2\times 10^{-k}+d_1\equiv 0\pmod m,(\because (m,10)=1)\),开个 map
统计就可以了。时间复杂度 2log(map
)或者 1log(unordered_map
)
感觉是应该能看出来的套路题。
525D D
想了两个麻烦的做法,但是没有正解巧妙。
满足条件的充要条件是当且仅当存在这样的 \(2\times 2\) 矩形:
*. .* .. ..
.. .. *. .*
对于每个 *
检查它是不是这种情况,如果是的话,再检查它周围的 *
是否因为它而满足了这些情况。(dfs / bfs)
551E B
直接分块。
580E B
周期和 border 一一对应,长度为 \(x\) 的周期存在说明其存在长度为 \(len-x\) 的 border,那么询问就变成了查询两个子串是否完全相同,还有一个区间覆盖操作。预处理出哈希中 base 的若干次幂,以及相同字母循环串的哈希值,线段树维护哈希值打区间覆盖tag易维护。
数据太水直接 memcpy()
和 memcmp
也能过?启发我们打暴力也要尽可能常数小点指不定就过了呢。
1485F A
简单dp,套路地设 \(f_{i,0/1}\) 代表 \(a_i\) 是 \(b_i\) 还是 \(b_i-\sum_j^{i-1}a_j\),单独讨论 \(1\) 处的取值,用 std::map
易转移。code
1209E2 B
只有最大值前 \(n\) 大的才有用,这样列数降到了 \(n\).
考虑让限制松一松,每一行自己可以随意钦定一个作为这一行的权值,发现和原问题是等价的。
\(\mathcal{O}(2^nn^2)\) 把每一列对于 \((2^n-1)\) 种作为这些行权值的情况的最优选择下的权值和是多少,然后状压 dp,枚举子集更新,时间复杂度为 \(\mathcal{O}(3^nn)\),总时间复杂度就是 \(\mathcal{O}(t(2^nn^2+3^nn))\).
套路 or trick 大概就是观察只有哪些是有用的,剪枝掉无用状态,以及把限制松一松发现和原问题是等价的。
1110F D
自闭了这样的套路都没想出来。
把询问离线下来,在树上 dfs,维护当前点到每个叶子的距离,在 dfs 序维用个线段树维护就可以,区间加减区间最小值。
1260E C
又是想不出来贪心。
设 \(-1\) 在 \(x\) 处。考虑最后一个是肯定要收买的,既然要收买他,他编号又是最大的,就让他尽可能多帮打一些人最后再送人头。所以最优方案是让最后一个刷掉算上自己 \(\frac{n}{2}\) 个人,再从剩下里面让编号最大的刷掉 \(\frac{n}{4}\) 个人,直到 \(>x\) 的都被刷掉了为止。
然后继续贪心,每一步具体要干掉谁可以考虑先暂时鸽着,到不能鸽为止(已经鸽了 \(\frac{n}{2}\) 个人)再选刷掉 \(\frac{n}{4}\) 的是谁,继续往后鸽,到不能鸽为止继续看刷掉 \(\frac{n}{8}\)...
具体到实现上用个堆模拟即可。
442C D
又是贪心...
考虑三个相邻的元素 \(x,y,z\) 满足 \(y\leq x,z\),则三者先删除 \(y\) 更优。
假设最左侧和最右侧有两个不能删除的 \(0\),发现和原问题等价,这样就不需要讨论边界情况了。
考虑反证,不失一般性假设先删除 \(x\).对于任意一种先删除 \(x\) 的策略,在删除 \(x\) 的时候先删除 \(y\) 一定不劣:
假设现在序列是 \(...,v,x,y,z,...\):
- 如果先删除 \(x\),对答案贡献是 \(\min(v,y)\),剩余序列为 \(...,v,y,z,...\);
- 如果先删除 \(y\),对答案贡献是 \(\min(x,z)\),剩余序列为 \(...,v,x,z,...\).
注意到 \(\min(v,y)\leq y\leq \min(x,z)\),以及序列中的数越大答案越大,所以后者相比前者不劣。
然后变成双调的,答案为 \(n-2\) 小的数的和。虽然前面编出来证明了,这里的构造还是w23c3c3教我的/ll
性质:最大值和次大值一定不会对答案做贡献,所以它们具体取值对答案无所谓,存在的意义仅为比其他所有的都大。
充分:给出一种构造,如果第三大值在最大值旁边,则删去最大值,否则第三大值在次大值旁边,删去次大值,递归成子问题。
必要:尝试构造,发现一个数如果对答案贡献 \(x\) 次,那么一定有一个比它大的数少贡献 \((x-1)\) 次,所以每个数仅贡献一次最优。
1527D B
求出 \(mex\geq i\) 的路径数,然后再差分一下可以得到答案。
计算 \(mex\geq i\) 的路径数,考虑 \(0\sim i-1\) 在树上必须形成的一条链,路径数就是两个端点子树大小的乘积。
考虑维护这条链的两个端点,每次新加进来一个点的时候分类讨论一下看看这个点会破坏掉链,还是在链中,还是作为新的端点。
662C D
确实是FWT板子,但是最近联赛级别题做多了就没往那方面想/wq还是太菜。
把一列的信息状压,设 \(f_i\) 为状态 \(i\) 出现的次数,\(g_i=\min(popcount(i),popcount((2^n-1)\oplus i))\),其意义为状态 \(i\) 可以选择反转/不反转这一列得到的最少的 \(1\),设反转的行的状态为 \(ans_i\),则有 \(ans_i=\sum_{j\oplus k=i}f_jg_k\),FWT优化,时间复杂度 \(\mathcal{O}(t(nm+2^nn))\).
1494E D
小套路题但是没想出来/ll
\(k\) 为奇数:判断是否有点对 \((u,v)\) 满足 \(u\to v\) 有边,\(v\to u\) 有边。充分:\(u,v,u,v,...,u,v,u\) 构造,是回文的,所以相等;必要:如果不存在这样的边,满足不了 \(v_i\to v_{i+1}\) 的同时 \(v_{i+1}\to v_i\),也就没有合法的路径。
\(k\) 为偶数:判断是否有点对 \((u,v)\) 满足存在一种颜色使得 \(u\to v\) 存在这种颜色的边,且 $v\to u $ 存在这种颜色的边。充分:在这条边上反复横跳;必要:如果不存在这样的边,满足不了 \(v_i\to v_{i+1}\) 的颜色在 \(v_{i+1}\to v_i\) 同样出现,也就没有合法的路径。
拿个 map
维护。
1548C B
题意:给定 \(n\),\(q\) 次询问 \(x\),求:
\[\sum^n_i \binom{3i}{x} \\ \]\(1\leq n\leq 10^6,1\leq x\leq 3n,q\leq 2\times 10^5\)
这种东西一看就很递推。
设 \(f_{x,j\in \{0,1,2\}}\) 为
放在杨辉三角上易出递推式。
看了题解发现还有简单生成函数做法,思路也很自然。
根据等比数列求和公式,答案的生成函数为:
分子可以直接展开快速求得,处理分母的话直接暴力模拟多项式除法(竖式除)即可。
两种做法的时间复杂度都是 \(\mathcal{O}(n)\).
1229C/1210D C
三元环计数,于是考虑暴力。答案显然为每个点的入度 \(\times\) 出度和,每次修改一个点的时候,遍历所有的入边,将其改为出边,更新答案,一次更新的复杂度是 \(\mathcal{O}(入度)\) 的。
不妨设 \(n,m,q\) 同阶,下面证明其复杂度为 \(\mathcal{O}(n\sqrt n)\):
在初始状态时,设入度 \(\leq \sqrt{2m}\) 的点集为 \(A\),设入度 \(>\sqrt{2m}\) 的点集为 \(B\),定义一个点的势能为入度,一次操作所带来的复杂度即为一个点的势能。
- 操作 \(A\) 中的点,释放 \(\leq \sqrt{2m}\) 的势能,给 \(B\) 带来的势能 \(\leq \sqrt{2m}\);
- 操作 \(B\) 中的点,释放 \(B\) 给其的势能,由于 \(|B|<\sqrt {2m}\),所以这部分 \(\leq \sqrt 2m\);
- 操作 \(B\) 中的点,释放 \(A\) 给其的势能,根据 1. 中的分析,其总量 \(\leq q\sqrt {2m}\).
综上所述,总的时间复杂度为 \(\mathcal{O}(n+m+q\sqrt n)\).Code
468C C
被构造橄榄了/ll
当 \(i<10^{18}\) 时,有 \(f(i)=f(i+10^{18})+1\).
设 \(s=\sum_{i=1}^{10^{18}}f(i)\),根据结论,可以归纳证明 \(\sum_{i=1+b}^{10^{18}+b}f(i)=s+b\pmod a\),所以当 \(b=-s\pmod a\) 的时候,构造 \(L=1+b,r=10^{18}+b\) 即可满足条件。
如何求出 \(s\)?求 \(\sum_{i=1}^{10^{18}-1}\) 再 \(+1\) 即可得到。
考虑任意一位数的贡献,其为 \((0+1+2+3+...+9)\times 10^{17}\),一共有 \(18\) 位,所以 \(s=45\times 18\times 10^{17}=81\times 10^{18}\).
1325F B
已经被烂大街了的套路?/jy
设 \(t=\left\lfloor\sqrt n\right\rfloor\).
考虑求出 dfs 树,然后如果存在一个返祖边和其跨越的树边组成合法的环(跨越的 dep \(\geq t-1\)),那么答案就是这个环。
否则的话,任意返祖边跨越的 dep 都 \(\leq t-2\),考虑构造出这个独立集,自下而上选点,一个点被选之后最多会有 \(t-2\) 个祖先被 ban 掉,所以直接贪心能选就选一定能构造出这个独立集。
911G B
直接分块,对于整块,对于每个值维护其变为多少(tag),散块暴力重构。
假设块长为 \(b\),值域为 \(x\),则整块的复杂度为 \(\frac{nx}{b}\),散块的复杂度为 \(x+b\).
\(\frac{nx}{b}=x+b\) 解出来 \(b=4422\) 时最优,8e8就硬跑
学分块学傻了是不好的,这个标记也是可以在线段树上维护的,所以写线段树就足够了。
1114F B
值域内的质数只有 \(\log\) 个,所以复杂度分析就默认其为 \(\log\).利用 \(\varphi(x)=x\prod (1-\frac{1}{p})\),只需要维护区间乘积,每个质因数在一个区间里是否出现过。
如果对于每一个质因数都开一棵线段树维护其在区间出现次数是很完蛋的。
由于我们只需要知道它是否出现过(信息为 \(0/1\)),而只有 \(\log\) 个,考虑将这些质因数并行计算,压到一个 unsigned long long
里,合并的时候就按位或一下。
这样复杂度就是 \(\mathcal{O}(n\log n)\) 的了,不知道为什么其他题解都写的是 \(\log^2\)?
这个 trick 在 CF567D 和 由乃的OJ 这两道题中也有涉及。
21SD省集三轮那个题有单点修改,值域还比较大,不过带修莫队能冲。
看到之前写的笔记记着
bitset
做法待补,如今却已忘了做法。希望后的笔记尽量能补多少就补多少,别烂尾吧。
594D B
相比上一个题,值域很大,但是只有询问。考虑离线,作个扫描线,同样还是考虑维护 \(\varphi(x)=x\prod (1-\frac{1}{p})\) 后面这个 \(\prod\),利用 HH 的项链那道题的 trick,需要记录每个质因子上一次出现在哪个位置,然后在那个位置到当前这个 \(i\) 区间乘 \((1-\frac{1}{p})\).
时间复杂度也是 \(\mathcal{O}(n\log n)\) 的。
1439C B
大套路题?
无脑吉司机线段树维护一下区间和,然后往后二分下一次到哪里会挂掉(答案不会+1),然后跳到那个地方继续往后走。由于 \(a\) 是不升的,所以每次跳 \(y\) 至少减半,复杂度就是 \(\mathcal{O}(n\log^2n)\) 的了。
但由于是前缀取 \(\max\),所以没必要动用吉司机线段树,会修改的一定是这个前缀的一个后缀,所以二分出这个后缀,然后写个区间覆盖维护区间和的线段树就可以了。
时间复杂度还是 \(\mathcal{O}(n\log^2n)\).
想起来给wym做 CF1428F 的时候,他写了一棵吉司机线段树,然后cbj则指正由于序列单调不升直接线段树区间覆盖就可以。然后我说其实由于只需要知道总和,直接拿个数组维护就可以了。
可见无脑上一个数据结构之前可以先考虑一下操作的特殊性质是否可以让我简化代码 / 使用更简单的数据结构来维护。
1418E B
算出所有方案造成伤害总和,最后除以总方案数即为概率。
容易发现方案数只和每个数与 \(b\) 的大小关系有关。
假设 \(\geq b\) 的有 \(x\) 个。分 \(<b\) 和 \(\geq b\) 两种情况讨论方案数。
\(<b\) 的造成伤害的方案数:
\(\geq b\) 的造成伤害的方案数:
按照 \(d\) 排个序,维护一个前缀和就可以了。
可能推得有小错,但是大体思路是这样?
484E B
直接整体二分。
没看出来的可持久化线段树做法:还是考虑二分答案,\(\geq mid\) 的修改成 \(1\),维护区间极长连续段。初始全零,提前按值的大小从小到大把值改成 \(1\),这个过程可持久化一下,二分答案的时候直接在可持久化线段树上查就可以了。
时间复杂度都是 \(\mathcal{O}(n\log^2 n)\)
741D D
自己想的复杂度白多了个 \(\log\)...
字符集很小,可以把每个字符出现奇偶性压成一个数,然后一条路径合法当且仅当 \(popcount\leq 1\).
考虑一个子树的答案可以分为经过根的和不经过根的,不经过根的就是子树的最大值,经过根的话考虑维护到子树根的链的任意状态,但是向上传的时候一个个都要暴力修改很完蛋。由于我们合并两个状态是异或,可差分,所以每个状态记为其到总树根的状态,这样就可以树上启发式合并做这个东西了。
复杂度是 \(n\log n|\sum|\) ,\(|\sum|\) 是字符集大小。
1239D A
感觉直接 Tarjan 2-SAT 什么的还是想复杂了吧(
观察到一家要不然选人要不然选猫,枚举第一家是选人还是选猫。
假如其选了人,那么第一家人所对应的猫的家,也必须选人(因为猫不能选了)。这样继续往后推,如果所有家都被推得了选人,那么就不合法,否则剩余所有家都选猫,即构造出一组合法方案。
实现上写个 dfs 就可以了。
19D B
坐标离散化一下,线段树维护区间最大值,在线段树上二分,需要查询最小坐标的话再每个横坐标开个 set
1452E C
有 \(n\) 个拖拉机排成一排,你可以选择一个长度为 \(k\) 的区间上的拖拉机放上小红花,选择一个长度为 \(k\) 的区间放上小蓝花,这两个区间可以相交也可以相离。
现在有 \(m\) 个人,第 \(i\) 个人要观赏 \([l_i,r_i]\) 区间内的拖拉机,这个区间内红花多则会产生红花个数的开心度,蓝花多则会产生蓝花个数的开心度,一样多他就会随机挑选一个。求最大的开心度是多少。
\(n,m\leq 2000\).
假设红花区间在左侧,蓝花区间在右侧。
考虑花朵区间从左到右变化的时候和一个人区间的相交长度,是先递增再递减,斜率为 \(\pm 1\) 的,当中点重合的时候取到最大值。
那么这个人观赏蓝花还是红花就确定红花区间中点和蓝花区间中点,哪一个离这个人的区间中点更近。
考虑固定红花区间,蓝花区间,那么在这两个花朵区间的中点的中点, 区间中点在其左侧的人选择红花,在右侧的人选择蓝花。
也就是按区间中点排序,一个前缀的人选红花,一个后缀的人选蓝花。
那么排一下序,对每个前缀预处理出红花和这些人最大相交长度为多少,对于后缀也同理,然后枚举在哪里劈开,取个最大值就可以了。
1407E B
倒过来考虑,在反图上从终点开始 bfs(因为不能堵死的话要构造最短路最大的方案),如果邻点是可以堵的,那么就染色然后堵死。如果不可以堵距离则 \(+1\) 继续入队判断。
正确性显然?不过感觉也不好用简洁的话来说明。
940F B
带修莫队直接冲虽然我没学过就当个黑盒用吧,维护每个次数是否出现过,处理询问的时候暴力判就是根号的,因为假如答案是 \(x\) 的话至少出现 \(\frac{x(x+1)}{2}\) 个数。
愣了一下好像连普通的莫队都忘了以前也是把莫队当黑盒用的,大概看了一下带修莫队,实际上就是在三维空间里扫描线呗感觉都差不多。代码先咕咕咕吧有时间写。flag
1242C D
没注意到所有数互不相同,以为一个数取出可能会有很多个盒子的数可以补进来。
以后读题要注意到题目所给的特殊性质。
一个数取出来之后,补到这个盒子的数的值是一定的,每个值两两不同,所以就可以确定出补到这个盒子的是哪一个数,然后一个一个确定下去,直到出现环为止,这一轮取数放数就这样确定了。
所以有一个思路,把每一个数连向要补进来的数。每个点至多有一个出度,是若干个基环内向森林(有可能有自环和孤立点)
然后我们要选出若干个环,满足每个盒子有且仅有一个数出现在这个环内。
合法的环很少(本质不同的只有 \((2^k-1)\) 种),状压 dp 一下就可以了。
这样就记完 100 道题了,2400+的 codeforces 题就先刷到这里了,接下来去看 ARC/AGC!