CF刷题记录
380C
*2000
字符串,线段树
不难发现,对于每个区间内的左括号,能匹配就匹配,那么最终能配出的对数就是最大答案。这个贪心策略是正确的。
然后考虑线段树维护区间,对于每个节点储存当前答案、多出的左括号数或右括号数。
合并也很简单,计算新增的配对数即可。
1366D
*2000
数论,构造
一种构造方法,基于 \(\text{if }\gcd(a,b)=1,\gcd(a+b,ab)=1\)。
先证明一下这个结论吧:
首先根据欧几里得定理可推出 \(\gcd(a,a+b)=\gcd(a,(a+b)\bmod a)=\gcd(a,b)=1\),同理 \(\gcd(b,a+b)=1\)。
然后 \(\text{if }\gcd(a,b)=1,\gcd(a,bc)=\gcd(a,c)\)。
\(\therefore \gcd(ab,a+b)=\gcd(b,a+b)=1\)
然后根据唯一分解定理,把原数分解成 \(p_1^{k_1}p_2^{k_2}\dots p_n^{k_n}\)。
首先若 \(n=1\),则必无解。
为了方便,我们令 \(d_1=p_1^{k_1},d_2=p_2^{k_2}\dots p_n^{k_n}\)。
则 \(\gcd(d_1,d_2)=1,\gcd(d_1+d_2,d_1d_2)=1\Leftrightarrow\gcd(d_1+d_2,a)=1\)。
构造完毕。用线性筛筛出最小质因数即可。
1370D
*2000
二分答案
昨天想了一天,只能想出 \(O(nk)\) 的动态规划,并且没有优化思路,菜……
很明显的二分特征,求最小最大值,二分最大值,然后看能否能产生符合条件的奇或偶序列即可。
分别考虑奇偶序列,对于每个序列,采取贪心策略。
假如当前位在偶数,那么就把他加入序列,如果它应该被删除,那么删除下一个加入奇数序列的数是一样的效果。
对于奇数位,能加就加即可,这样产生的合法子串必然是最长的。
1187E
*2100
树型DP
挺简单的一道2100。
应该可以轻易换根DP,但我不会,所以就没用。
不难发现,在初始节点固定之后,答案是固定的,但是枚举起点明显会T。
考虑对于当前节点,根节点只有三种情况:它自己、它子节点里面、它父节点上面。
我们除了 \(f\) 以外新开一个 \(g\),储存当前子树内能获得的最大贡献,且从当前节点作为起始点,注意这里只包括当前子树。
然后考虑答案 \(f\),根节点在当前子树内时当前子树能得到的答案。注意这个答案是对于全局的贡献。
如果当前节点为根节点,直接借用 \(g[i]\),但是当前节点的贡献应该是全局,故而总贡献是 \(g[i]-sz[i]+n\)。(其余子节点贡献都被限制在他们那个子树内)
否则,根节点必在其中一棵子树内,枚举子树找最小值即可。这个公式也很简单,理解一下就是子节点填满后填当前节点,然后类似于上一种情况,但是所有贡献都要去除那个被填满的子树。
461B
*2000
树型DP
挺简单的一道2000。
考虑每个节点的状态,存储“当前节点连接块有一个黑点”和“没有黑点”的所有可行情况。注意这里有没有黑点指的是与父节点相连时,对于后者,发现还可以不与上相连,但这时要求“这一棵子树内合法”,也就等同于当前节点连通块也得有一个黑点。
首先如果当前子树内没有黑点,且与上相连的情况,那么首先当前节点得是白的,然后乘上每一个子节点没有黑点的情况数即可。
面对“当前子树有黑点”和“不与上相连”的情况,不难发现黑点要么在当前节点、要么在其中一棵子树内。对于前者,每一个子节点也都得是无黑点的,处理方式同上。否则,枚举黑点所在位置,用其有黑点的情况乘其他子树无黑点的情况。
然后就没有了,最后答案就是根节点也有黑点的合法情况。
486D
*2100
树型DP
这两天主刷树型DP,有点多。
作为2100感觉还是有点虚高,去掉树上操作就是基本的计数。
考虑动态维护区间内最大值不太好解决,然后 \(n\le2000\),不难想到枚举最大值。
然后只需要找出包含当前节点且当前节点为最大值的连通块即可。
发现会存在数值相等的情况,手动规定就行,比如优先处理编号更小的。
1646D
*2000
树型DP
最重要的就是发现一个性质:除非 \(n=2\),否则一条边两侧的点不能都好。
如果一条边两侧的点都好,那么他们是互相绑定的,假如有一个好点连接了一个好点和另一个点,那么他的值必然为那个好点的值加上其他点的值,也就不然不相等,所以不成立。
所以如果一条边同时连接两个好点,唯一情况就是二者都只有对方一个连接点,而树是联通的,故而当且仅当 \(n=2\),特判即可。
然后求最多好点数就很简单了,对于染色,不难发现所有不是好点的点全部染成 \(1\) 必然最优。额外开一个数组储存当好点最多时,当前子树内最少的染色总和。
首先肯定是加上每个子节点的染色总和,然后考虑当前点,如果不是好点,就是 \(1\),否则它的父亲必然是 \(1\)(特判根节点),并且它的每个子节点也只能是 \(1\),就能直接计算了。
1359D
*2000
双指针
唯一难点就是考虑如何处理“取走最大值”。
首先考虑不取最大值,显然简单,双指针,每当当前区间总和小于 \(0\) 时就必然失去价值了,开启新区间,实时统计答案。
然后考虑取走最大值,发现 \(-30\le a_i\le30\),考虑枚举最大值即可。同时如果 \(a_i>std\),这个区间就是不合法的,开启新区间。
242E
*2000
位运算,数据结构
区间修改+查询,一眼线段树。
区间异或操作是一个很典的Trick,拆位存储+操作即可,最后查询的时候把每一位的答案统计起来。
432D
*2000
字符串,KMP,字符串哈希,动态规划
一道 nxt
运用题。
重点就在于如何求当前前缀出现次数,如果该子串出现多次,那么他们必然是字符串 s
的一个前缀的border。
不难发现,前缀 nxt[i]
的border必然是前缀 i
的 border,所以 nxt[i]
的答案应累加上 i
的答案。从后往前 DP 就可以了。
所以 KMP 求 border,字符串哈希判断前后缀,最后动态规划即可。
386D
*2100
图论,最短路,模拟
2100虚高得离谱
不难发现所有情况数大约是 \(n^3\) 的,所以所有情况数其实特别小,直接BFS就行。
332C
*2200
贪心
翻译一下,我们需要选出 \(p\) 条,然后主任会在 \(p\) 条中选出 \(b\) 最大的 \(k\) 条,并尽可能让 \(a\) 最小。我们需要最大化主任最后得到的 \(a\) 总和。
按 \(b\) 从左至右排序,发现主任不选的 \(p-k\) 条必然在 \(k\) 条左侧,枚举分界点即可。
考虑处理右侧最大的 \(k\) 个,从右往左枚举分界点,就能单调队列维护最大的 \(k\) 个,顺便维护和就行。
但会有问题,当 \(b\) 相同时,主任会优先选 \(a\) 小的,所以为了准确性,若 \(b\) 相同,按 \(a\) 从大到小排序,则必然符合顺序。
620D
*2200
暴力
没错,暴力的2200。
不换的情况 \(O(n)\) 解决,只换一个 \(O(nm)\) 解决。
然后考虑只换两个的情况,不难发现只有两边换的两个位置都不同才有意义,否则等同于上面两种情况。
推一下式子:
假如我们提前将 \(a_1+a_2\) 的所有可能存入数组,然后枚举 \(b_1,b_2\),就可以在数组内二分查找与 \(\sum\limits_{i=1}^n a_i-\sum\limits_{i=1}^m b_i+b_1+b_2\) 最接近的 \(a_1+a_2\)。
整体复杂度 \(O(n^2\log n^2)\)。
183C
*2200
图论,DFS
考虑消去取模运算,正边方向 \(a_v=a_u+1\),反边方向 \(a_u=a_v-1\)。
深搜时就给每个节点编序,如果下一个节点已有序号,那么新老序号之差必为 \(k\) 倍数,很显然。
所以最后 \(k\) 就是所有差值的最大公因数。
由于我们需要按正确的顺序遍历所有边,如果不想拓扑排序的话,考虑建反边即可。
1311D
*2000
枚举
水爆了。
发现 \(a,b,c\le 10^4\),考虑 \(O(n^2)\) 暴力。
不难发现,假如说我们确定了 \(A,B\),那么 \(C\) 实际上是确定的——就是 \(c\) 最近的 \(B\) 倍数。
考虑枚举 \(A\),不难发现数值上界就是 \(\max(a,b,c)\),再往上必然更劣,很好感性证明。
然后考虑枚举 \(B\) 是 \(A\) 的几倍,不难发现 \(B\) 的上界就是最接近 \(c\) 的,再往上必然更劣,同样很好证明。
然后就没了。
449B
*2000
图论,最短路
一道很典的题啊。
考虑如何判断一条铁道是否可删,只需要判断这条铁道在不在对方的最短路中,且对方只有一条最短路即可。
先把所有铁道加进去,然后跑一遍最短路,求出每个点到 \(1\) 的最短距离——因为所有铁道都从 \(1\) 出发,所以大大简单了。
然后只需要判断每个铁道是否在对方最短路上(\(dis_v=dis_u+val\)),且对方只有一条最短路(每找到一条这样的边,就把 \(dg_v\) 自增即可。)
考虑消除两条铁道对同一个节点的影响,每次删完都令 \(dg_v\) 自减。
1132F
*2000
字符串,区间DP
\(n\le500\),很显然的 \(O(n^3)\) 区间DP。
考虑转移,不难发现一个点只有两种情况:被单独删除、和前面某一个同色块一起删除。
就没了。
我写了缩点,但事实上可以不缩。
1349B
*2000
数学
首先,中位数经典套路,转化为 \(-1,0,1\) 串。(事实上所有 \(0\) 都可以归为 \(1\))
注意到,如果我们可以构造出一段长度 \(\ge 2\) 的 \(0\) 连续子串,且数列中存在 \(0\),就可行。
可以理解为,分别往两边扩张,每次扩张 \(1\) 个,只要长度 \(\ge2\),就必然存在将其变为这个序列内的数的方法。
此外,我们发现,当数列中存在 \(0\) 时,也可以构造长度 \(\ge 2\) 的 \(1\) 连续子串。
先扩张到那个 \(0\) 一侧,因为 \(1>0\),所以对它们两个数取中位数,就构造出一段长度为 \(2\) 的 \(0\) 串了。
我们思考如何判断是否存在这个子串,首先得有 \(0\),然后考虑枚举长度找规律:
- 找长度为 \(2\) 的非负连续串,若存在则可行。
- 找长度为 \(3\) 的串,两端均非负。它们就可以构造出一段非负连续串。
- 找长度为 \(4\) 的串,发现没有必要:
- 若中间两个数非负,那么必然包含在前两种情况中。
- 否则,这个串不行。
后面的均同理。所以只需要枚举长度为 \(2,3\) 的子串即可。
1438C
*2000
构造
测智商构造题。
发现奇数偶数必然不等,所以奇偶相间构造即可。
1200E
*2000
字符串,KMP
我尝试写哈希,但常数爆炸,遂TLE。
发现只需要找公共前后缀即可,如果把两个字符串合并为一个,就可以通过找border的方法迅速解决。
发现我在二月做过这题,但没有任何印象。
1244C
*2000
数论,exgcd
首先列出方程:
板子 \(\text{exgcd}\),考虑如何获取 \(x+y\le n\)。
直接在 \([0,n]\) 范围内枚举会TLE,考虑找规律。
发现 \(w,d\) 很小且 \(w>d\),发现 \(wd=dw\),发现 \(y-w\) 时可以 \(x+d\) 等价,所以得出结论:
1385E
*2000
图论,拓扑
不难想到,当原图中有环时必然无解。否则,只需要从拓扑序小的指向拓扑序大的即可。
540C
*2000
DFS
分成两部分:能否到达终点,以及能否从终点掉下去。
前者很简单,\(O(n)\) DFS即可。对于后者,我们需要分类讨论:
- 若起点终点重合,只要它有一个相邻的完整冰,就可以,否则显然无解。
- 否则,如终点是碎冰,显然就没了。
- 再否则:
- 若起点终点相邻,只要一个相邻的完整冰即可。易证。
- 否则,需要两个。因为必有一个点是走来的路径,会变碎。
1288D
*2000
二分答案,压位
最大最小问题,一眼二分。
二分最小值,考虑如何 check
,只需要确保所有 \(\max(a_{i,k},a_{j,k})\ge mid\) 即可。
因为 \(m\le 8\),考虑压位,最后只需要找出两个或值为全集的数列即可。
发现 \(n=10^5\),无法 \(O(n^2)\),但是发现只有 \(2^m\) 种可能状态,储存状态即可。
920F
*2000
数学,线段树
一道纯数学题。
注意到 \(D\) 这个函数值很小,转化几次就变成 \(1,2\) 了(注意力惊人!),然后就可以考虑暴力预处理,并且暴力线段树更新。
然后我就卡住了,没想出这个很神奇的优化。
你会发现,当 \(a_i=1\) 和 \(a_i=2\) 时,\(D(a_i)=a_i\),所以可以优化掉。
然后就没了。。
514C
*2000
字符串,哈希,枚举
发现 \(\sum|s|\) 很小,只有 \(6\cdot10^5\),于是就可以暴力了。
具体的,对于每个字符串,暴力枚举它变化的位置以及变成的的字符(发现只需要枚举三个字符),然后靠字符串哈希硬干过去。
由于哈希会被卡,所以开双哈希。考虑到要绑定两个哈希值防止意外,我写了个常数巨大的勾史 map<ull,set<ll>>
,不推荐学习。
1363E
*2000
树型DP
很水的树型DP啊。考虑每个子树都通过最优的祖先节点洗牌,然后就没了。
对于这个题意翻译表示强烈谴责,鬼知道洗牌是什么意思啊,我以为是任意覆盖,结果是这几个节点的数任意互换。
我还在想怎么可能无解呵呵呵。
118E
*2000
边双,tarjan,DFS
首先,易得整个图是个边双为有解的充要条件。
- 必要性:如果有桥,必然无解。
- 充分性:考虑边双 \(\text{DFS}\) 生成树的性质,发现你只需要让所有返祖边指向祖先、树边从父节点指向子节点、横叉边随意,就必然可以构造出一种方案。
然后也没啥了,直接 \(\text{DFS}\) 一遍出结果。
999E
*2000
缩点
还是 \(\text{tarjan}\) 题。
首先为了消除这样那样的问题(比如根节点判断失误之类的),我们先缩点去环。
然后剩下的答案里只需要让 \(s\) 连到每一个根节点就行。
注意当 \(s\) 自身为根节点时不需要连自环,特判一下。
1763C
*2000
规律
第一个重要的点:对于一个区间,连续操作两次,这个区间会变成 \(0\)。
所以我们可以使整个区间都是最大值,如果我们可以构造出一段不包括原最大值(更准确的,使区间中仍存在最大值)的全 \(0\) 区间。这样显然是可行的最大和。
发现上一条只需要 \(n>3\) 即可满足。
然后考虑分讨或暴力 \(n\le2\) 的情况即可。下面记录分讨做法
省略 \(n=2\) 的部分,我们直接看 \(n=3\) 的情况:
若最大值在边界,显然也可以构造出上述全 \(0\) 区间。
否则,最大值在中间,只有“原来的不变”(因为最大值)和“全部变为一种”(更改必然只剩两个值,同 \(n=2\))
383C
*2000
线段树
对于这种题,有一个我个人认为很经典的套路:给整棵树重新编号。
只要我们按 \(\text{dfs}\) 序给整棵树重编号,那么一棵子树就是一段区间,那么原问题就变成了区间修改单点查询问题,直接线段树即可。
一个不太典的是,操作传递具有奇偶性,开两棵树即可,分别存奇数层值与偶数层值,当然肯定包含所有点,但有效点就是奇数、偶数点。
1674E
*2000
分讨
又是一道恶心分讨题。
最优答案只有两种情况:二者互不干扰,或者互有干扰(相邻)。
对于前者,直接分别操作最小和次小最优。显然无需额外考虑二者相邻的错误情况。
对于后者,一种是中间隔了一个,可以视作一个整体,每次造成 \(2\) 点伤害。
还有一种是相邻,考虑贪心,首先显然先消大的,消到两个相等(如果把一个消完了,那么显然答案就是大的操作次数。),然后又可以把两个视作一个整体,每次造成 \(3\) 的伤害。(其实一开始就可以,但显然需要特判其中一个可以被消完的特殊情况)。
1388D
*2000
贪心,拓扑
考虑贪心策略,若当前节点值大于零,则比 \(b_{now}\) 先操作(若存在),反之同理。
考虑拓扑实现贪心策略。
然后考虑方案,优先输出所有 \(a>0\) 的,然后输出 \(a<0\) 的,则必然满足如上条件。但这是错误的,因为 \(a<0\) 内部可能也存在关系,所以倒序输出 \(a<0\) 的部分防止其内部连边的影响。
337D
*2000
树型DP
首先考虑图上操作,比如多源BFS之类,显然不行。所以从树的角度考虑。
一个很显然的事实是,我们只需要判断当前点距离关键点的最长距离就行了。
我们分别考虑最远关键点在子树内和子树外的情况。对于后者,显然不能直接处理,所以我们先解决前者。
假如我们已经获取了子树内的答案,考虑子树外的情况,那么必然是从其父节点转移而来的。这时候又有两种情况:从父节点其他子树转移来和从父节点子树外转移来。直接转移即可。
注意特判一下父节点最长距离就在当前子树内的情况,所以我们还需要次长距离以供最远关键点所在子树更新。
1900D
*2000
容斥、欧拉反演
我不会欧拉反演,所以考虑容斥。
一个经典的套路是排序后枚举中间点,那么答案就是:
\(k_{i,j}\) 表示 \(\gcd(a_l,a_i)=j\) 的 \(l<i\) 的个数。
那我们容斥一下 \(k\) 即可。我们首先可以得到 \(l<i\) 的 \(a_l\mid j\) 的数量,记作 \(b_j\)。
考虑 \(k_j\) 包含在 \(b_j\) 中,且所有 \(\gcd(a_l,a_i)\ne j\) 的 \(a_l\) 必然已经在枚举 \(\gcd(a_l,a_i)\) 时被计算过,同时 \(j\mid\gcd(a_l,a_i)\),那我们在枚举 \(j\) 至 \(\gcd(a_l,a_i)\) 的时候,对其每一个因子减去当前的值即可。
因此,我们应当从大到小枚举因数。
1900E
*2100
强连通,tarjan缩点,拓扑,DP
我们考虑加边操作的实质,发现每一个强连通分量都变成了完全图,可以从任意一点开始,走到任意一点结束(分量内点)。所以我们可以将这个强连通分量缩点,权为所有点和,长度为点数(因为要最长路,所以不得不走完)。
然后就是弱智的拓扑序DP了。
1416B
*2000
构造
首先这显然是一道构造题,所以我们唯一能做的就是让自己智慧起来。
一个构造方案是先把所有值汇聚到 \(1\) 处,再统一分发。
分发不用说,汇聚的方式是,如果当前值非当前下标倍数,就从 \(1\) 补,然后就全部转移到 \(1\)。
首先证明从 \(1\) 补不会有负数,发现 \(a[i]\ge1\),所以最多要补 \(a[i]-1\),然后前 \(i-1\) 个数最小和为 \(i-1\),所以最劣也会是 \(0\)。
然后证明次数,前者最劣每个数都补一次,\(2n-2\) 次,再加上分发的 \(n-1\) 次,共 \(3n-3\) 次,构造完成。
1359E
*2000
组合,思维
不难,多想一会就秒了。
发现最小的 \(a\) 对于答案关系很大,于是从 \(a_1\) 下手。
多想一会,当前 \(x%a_1=0\) 时,那么取模其它数时,要么为 \(0\) 要么仍为 \(a_1\) 倍数。
所以,数列中所有数,必然为 \(a_1\) 倍数。必要性得证。接下来考虑充分性。
……充分性显然。\(x\bmod (ky)\bmod y=x\bmod y\),就是说取余 \(a\) 倍数之后的余数再取余 \(a\),显然等同于直接取余 \(a\)。
所以只需要求范围内的合法的所有数均为最小数倍数的组合个数即可。
1156C
*2000
贪心,二分
首先,我们考虑一个贪心策略:所有(匹配上的)左侧点均在所有右侧点右侧。
若一个左侧点在右侧点右侧,二者互换显然不劣。
然后我们考虑所有左侧点均在最左侧,右侧点同理。
若一个左侧点左侧有空点,显然互换更优。右侧点同理。
所以,我们知道每一种对数,可能的最优匹配情况是一定的。如果可能匹配上这么多对,显然最左边的点和最右边的点,内部从左至右依次匹配,是最优的。如果这样匹配不上,其他情况易证也无法匹配上当前数量对。
故而我们有了一个 check
,然后就可以二分了。
478D
*2000
DP
你的学生DP不过关。。
智商题做多了,不会做弱智题了,一直想着组合数学或者特殊性质……
就是弱智DP,逐层DP即可。
考虑压缩维度,首先滚动层数维,然后省略绿色数量,只留下红色数量。
值得注意的是,我这种写法也许会被卡,因为可能会出现答案恰好等于 \(10^9+7\) 而被取模为 \(0\) 导致异常退出的情况。
当然也可能不会,会不会算一算就知道了。
1354C2
*2000
数学,几何
纯数学题真的很无语啊……
首先一个很弱智的解法就是三分,显然旋转一单位(转完之后与原来相同的角度)内所求长度是凸的。
然后一个无聊的解法是做数学题。
1344B
*2000
分讨
没有任何算法含量,全是分讨。
考虑讨论不合法的情况:
- 首先,由于每行每列必须有南磁铁,所以每行列的所有黑点必须连续,否则无论磁铁放在哪边,走到另一边或另一边走过来必然经过白点。
- 其次,如果这一行列有黑点,那么白点处不能有南磁铁,不然可以把北磁铁吸过来。同时,由于每行列必须有南磁铁,所以如果存在全白的行列,那么必须有对应全白的列行,不然无论放在哪都违背这一条第一句话。
然后考虑这样是否全合法,也就是构造一个合法状况,不难想到,满足上列条件时,在所有黑色连通块边界以及全白行列交点上放南磁铁即可。或者,在全部黑色块放上也行,因为没有要求南磁铁数量。
这样的话每个连通块只需要一个北磁铁即可。
1268B
*2000
常识
不知道怎么分类,黑白染色取最小值。
1294F
*2000
树论,直径
不难想到,我们可以找树的直径,以及距离直径最远的另一点。
但事实上,我们会发现这个结论没有那么容易证明。
首先,显然的,我们会选取叶节点作为端点,这显然比非叶节点更优。然后,就会发现上述选法选出的距离必然更优了。
这是一句很简要的证明,或许模拟一下会有更好的理解。
总之,上述方法可以BFS实现。没了。
1399E1
*2000
树论,贪心
应该是我这学期最后一次在机房,做的最后一道题,写的最后一篇记录了。
首先,我们可以发现每条边的贡献很好求出,只需要简单得到与其有关的叶节点路径有几条即可。这样,我们可以得到其对于总答案的贡献。
考虑最小化步数,贪心,每次都操作贡献变化最多的边即可。具体的,我们储存下每一条边操作前后对答案的贡献变化量,也就是除二前后的值变化量乘上与其有关的叶节点路径数,每次优先选贡献变化最大的更新即可。
贪心啊……