简单的刷题总结

一直有写题解的打算,但一直咕咕咕,现在拉扯不动了,还是开个坑吧
随缘更新,口胡万岁

CF1650G Counting Shortcuts

关键思想:对点以到起点的最短距离进行分层。
\(dis1[i]\)为起点到\(i\)的最短距离,\(dis2[i]\)\(i\)到终点的最短距离;先进行最短路计数:令\(f1[i]\)表示起点到\(i\)的最短路数量,\(f2[i]\)表示\(i\)到终点的最短路数量
这是一个很简单的dp,考虑所有与i相连的点j:

\[f1[i]=\sum{f1[j]} \qquad (dis1[j]=dis1[i]-1) \]

\[f2[i]=\sum{f2[j]} \qquad (dis2[j]=dis1[i]-1) \]

然后考虑怎样计算长度仅多1的路径数量,这样的路径一定满足这样一个性质:包含且仅包含一条两端点在同一层的边
所以我们可以枚举每一条这样的边,考虑其贡献,设两端点分别为u,v,则其贡献为:

\[f1[u]*f2[v] \qquad (dis1[u]+dis2[v]=dis1[t]) \]

所有符合条件的边贡献相加即可

CF1633E. Spanning Tree Queries

注意到m只有300,考虑当x变化时,只有造成边权之间大小关系发生改变时,最小生成树才会发生变化,这启示我们可以暴力枚举所有的最小生成树。
我们可以把每条边的边权看成一个关于x的函数,设初始边权为\(w_i\),\(y=|w_i-x|\),则两个函数的交点的x就是其对应的边大小关系发生变化的x。
直接\(m^2\)暴力处理这m个函数的交点,划分成至多\(m^2\)段,每段对应一个最小生成树的形态,然后对于每一段做最小生成树,然后直接对于每一个询问查一下在哪一段即可。
另外除了函数间的交点,与x轴的交点也要考虑(因为这是正负变化的点)

CF1632D. New Year Concert

我是笨比,只能想到\(n(logn)^2\)的做法。
当我们更改一个数的时候,可以把他修改成一个极大的素数,这样我们可以保证任何包含这个数的区间一定满足条件。
现在考虑我们什么时候需要修改
当我们把\(a_i\)加入时,设上一次修改的数是\(a_k\),显然我们只需要考虑k到i里每一个以i为右端点的子区间,注意到当你在一个区间加入一个数时,区间gcd会变小,而区间长度会变大。现在我们对于i,考虑是否存在一个j(k<j<i),满足\([j,i]\)的区间gcd等于区间长度,存在的话就得改\(a_i\)。由上面的分析,显然可以二分j,然后判断下gcd与区间长度的大小关系,gcd大于区间长度往k靠,反之往i靠。
区间gcd可以套个st表查

CF1696D. Permutation Graph

这道题的思考角度稍微有点不同,我们并不是去考虑如何具体的构造最短路。
考虑\(1\)\(n\)的过程,由于题目要求,显然我们一定会经过最值点(最大与最小都行)。设最值点为\(i\),则可以拆分为\((1,i)\)\((i,n)\)两个子问题。
这样我们可以不断重复这样的过程,考虑\((i,j)\)的段,若中间存在一个最值点\(x\),那么可以拆分成\((i,x)\)\((x,j)\)两段。直到两个端点分别为该段的最大值和最小值时,那么直接到达,产生\(1\)的贡献。

CF1696E. Placing Jinas

\(f(i,j)\)表示过程中\((i,j)\)这个点会出现的娃娃总数,不难发现:\(f(i,j)=f(i-1,j)+f(i,j-1)\)。那么答案就是把所有白点的\(f(i,j)\)的加起来。暴力计算显然会T,进一步观察\(f(i,j)\)递推式的形式,发现这不就是\((0,0)\)\((i,j)\)不同路径数的递推式吗?那么这就变成了一个众所周知的事情了,\(f(i,j)=C_{i+j}^{j}\)
所以,\(Ans=\sum_{i=0}^{n} \sum_{j=0}^{a_i-1}C_{i+j}^{j}=\sum_{i=0}^{n} \sum_{j=0}^{a_i-1}C_{i+j}^{i}=\sum_{i=0}^{n}C_{i+a_i}^{i+1}\),预处理阶乘即可快速计算

CF1691E. Number of Groups

很典的扫描线,对端点按位置小到大排序,遇到左端点加入对应区间,右端点删除。
然后对于所有仍未被删的区间,可以分为两种:一种是已经和其他区间相连的,另一种是仍然独立的。
考虑加入一个新区间(即扫到了一个新的左端点),那么这个区间会和当前所有仍未被删的异色区间相连。
我们可以使用并查集来连接区间。
新加入一个区间时,首先将他与每一个独立的区间连起来(这些独立区间在并查集里是一个单独的点),然后这些独立区间就变成了连接区间。而对于那些已经被连上的区间,这些区间已经在并查集里构成了一个连通块,显然我只需要任取一个点出来和新区间连就行了。
虽然处理独立区间是\(O(n)\)的,但是每个区间最多只会作为独立区间被连一次。
使用set来维护区间加入与删除,总复杂度,\(O(nlogn)\)

CF1697E. Coloring

问题等价于将平面的一些点划分为至多\(n\)个集合,同一集合的点距离两两相等,不同集合的点距离大于其到同集合内的点的距离。
考虑两个点\(a,b\),将它们分到同一个集合内,若存在另一点\(c\),满足\(d(b,c)=<d(a,b)\)或者\(d(a,c)=<d(a,b)\),这样是不合法的
也就是说,对于任意一个点\(a\)来说,它只能和距离自己最近的点在同一集合,且必须把所有和自己最近的点加入集合(若有一个最近点和\(a\)不在同一集合,那么它到\(a\)的距离等于\(a\)集合内点的距离,并不满足第二个限制)
对每一个点预处理出其最近点到它的距离\(d_{min}\),并按\(d_{min}\)排序,从小到大地考虑把每个点加入某个集合。
做到第\(i\)个点时,考虑他能否把自己的所有最近点\(j\)都加入到自己的集合中。某个最近点\(j\)能加入集合,需要满足以下条件:
1.到其他也要加入集合的点的距离均等于\(d_{min}\)。(也就是题目给的第一个限制)
2.到其他不加入集合的点的距离严格大于\(d_{min}\)。(也就是题目给的第二个限制)
若存在一个\(j\)不能加入,其他的所有\(j\)也不能加入。因为不能加入的这个\(j\)\(i\)的距离是等于\(d_{min}\)的。也就是对于\(i\),只有两种决策,要么和所有的最近点\(j\)在一个集合,要么自己单独一个集合。
分完集合后,对于每个集合,要么全部点一个颜色,要么集合内每个点颜色都不同。做一个背包就行了。

CF1839D. Ball Sorting

考虑钦定一些位置不动,其余的位置变动,显然这些不动的位置的值满足单增。同时这些不动的位置会把整个排列划分为\(k\)段,段内就是那些需要移动的位置
接下来就是一个很关键的性质:为了移动这些位置,你对于每个段只需要放1个0,并且通过这一个0,你就可以把所有要移动的点移动到合适的位置。
具体地,考虑每一个被划分出来的段实际上可看作一段值域。比如对于一段:4,3,9,6,你钦定4,6为不动位置,那么这一段就用于维护值在\([4,6]\)的点。对于一段内,你不妨在末尾放一个0(实际上放段内的哪里都行),然后把每一个相邻的点移动到对应的段内(也就是对应的值域内)。移动后这个点显然也可以看作不动点了,接着移动下一个相邻点即可。这样你每一步都会把一个移动点转化为不动点。
考虑你所选的不动点集合为\(S\),将排列划分为\(k\)段,那么对与这个划分,你需要安排\(k\)个0,最少花费为\(n-|S|\),也就是要动的点数。
问题转化为对与每个\(k\),选出最多的点,这些点单增,且将排列划分为\(k\)段,dp一下即可

posted @ 2022-04-19 23:02  nanjoln0  阅读(75)  评论(0编辑  收藏  举报