Codeforces Round #601 (Div. 2)
要补的CF题目欠的太多了…之前还有一堆比赛(甚至南昌regional都)的题目没有补…最近总算把学科内的坑补的差不多了,可以大规模地补一下博客了
A
贪心处理就行了,具体用代码实现可以直接预处理剩余距离<5的情况,然后对5做除法、取余数就行了。
B
有n个节点,m条边,允许有重边,但是不能有自环。每个节点有一个权值 a [ i ] a[i] a[i],连接边 ( u , v ) (u, v) (u,v)的花费是 a [ u ] + a [ v ] a[u] + a[v] a[u]+a[v],问如何连接这些节点可以使得任意一个结点至少与两个不同的点相连,同时花费最少?输出花费和连接的边。
最开始做的时候题目给出的条件是 2 < = n < = 1000 , 1 < = m < = 2000 2 <=n <= 1000,1 <= m <= 2000 2<=n<=1000,1<=m<=2000,后来…
改成了 n > = m n >= m n>=m…当然了,苦逼的m2分站用户是肯定看不到的。。
先讨论一下运气比较好的假算法:
每个点因为要与两个不同的点相连,那么至少每个点会被两条边访问,也就是其度至少为2,如是可以先把基本的大环构造出来,再把剩余的边分配到最便宜的重边上去,就可以获得最小值。因而, m < n m
运气比较好的是,题目条件改完后,该假算法也可以正确跑出来。但是事实上,如果在 n m nm nm之间的大小关系没有限制的条件下,上述算法是有问题的。
可以考虑一个例子:
Input:
5 6
1 2 2 2 2
容易知道,多一个环就会多消耗一条边。上述输入的正确构造法应该是以1为中心,分别形成2个小三元环(122与122)。
构造完成以后其实就可以发现,删去一条边——从度的角度也就是给某“两”个点的度加1的这个操作中,该两点可以相同,图形上的构造便是以这个相同点作为环的一员而其余点的度不变进行构造即可。可以料想到,我们不可能无限制的对某一个点的度+2,而有一个上限,这个边的上限就是以这个点为中心、尽可能多的构造三元环的菊花图中的边的个数。其中,如果n为偶数,那么除了中心点后有奇数个点,最优的构造应该是若干个三元环与一个四元环;而n为奇数时,最优构造就是若干个三元环。只有在这个大菊花图构造好后,才能连最便宜的重边。此时保证构造最优。
不过以上只是我盲目嘴嘴…大概率有点问题。
不过对于这个题目而言,优先地成环肯定是优于连便宜边的。所以把上述算法的细节处理好之后,应该就是这道题目的正解?极不自信
C
容易找到开始和结尾的两个数,然后我们进行构造。当我们开头三个数确定后,后面的数都可以在不断查找中进行比较、验证,而开头三个数仅有2种不确定的情况,我们分别尝试构造即可。
为了快速的查询在一个三元集合种,一个元素对应的另外两个元素,我们把两个数中的一个乘上1e6再加上另一个数本身,就完成了一个有序数对到 long long 的hash。我们开设一个 v e c t o r [ i ] vector[i] vector[i]表示以 i i i开头的三元数对后面两位可能存储的组合,使用之前提到到hash办法。当我们读入三元集合时,每个数可能有6种可能的组合,从而空间消耗是 O ( 6 ∗ n ) O(6 * n) O(6∗n)。
在这些处理结束后,我们开始构造。为了避免添加一些已经使用过的元素(可能会发生这样的事情是因为我们存储了6种组合的情况,这势必会导致某些在前面的元素被挪到了后面),我们还需要开设vis数组。维护两个元素 a 、 b a、b a、b表示连续两位的数值,搜索第三位时只需要在 v e c [ a ] vec[a] vec[a]中解hash后第一位是b的、并且第二位没有被vis过的元素即可。如是反复操作到最后即可获得一种构造。
E1
n个盒子,每个盒子仅可能取0、1。(弱化的数据)
可以将1移动到相邻的盒子,花费为1。问移动最少多少次可以使得每个盒子都能被某个数字(要求大于1)整除?
首先考虑求sum,然后找因子。
最开始误以为合成到gcd是最优的情况,但是考虑下面的情况。
Input
1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1
显然移动到数量为3是最优的。
因为在 1 e 5 1e5 1e5范围内的的数字的因子最多也不会超过 l o g 1 e 5 log1e5 log1e5 ≤ \leq ≤ 20 20 20 。。所以直接暴力走起就行了。
在合并查询花费的时侯开vector存储p个元素的位置(p是正在选取的因子,因为每个盒子只有1,所以选p个进行合并),将其全部合并到中间即可获得最小的花费。绝对值不等式
一顿乱搞就可以了。
暴力遍历所有因子 & 顺序搜索
D
水题一道。读清题意后可以考虑构造一种遍历路径,使得路径上相邻的两个点必定是四方相邻的。我们考虑蛇形处理,并利用取余知道有多少只鸡可以获得比其余鸡多一个饲料的数量。如是操作即可获得一种可行解。
E2
盒子数量加强到 1 e 6 1e6 1e6,每个盒子的值 a [ i ] a[i] a[i]加强到 1 e 6 1e6 1e6。
可以考虑到,对于因子的选取应该选素数。因为在一段和被某因子整除的区间,如果它具有一个更小的素因子,那么就有机会可以将这段区间中物品个数的变化次数变得更小。
之后的做法是题解中一个相当精妙的手法:
愿题意为相邻格子之间可以传递一次物品,花费为1,最后需要满足 p ∣ a [ i ] p|a[i] p∣a[i]。
做一个模型等效转化:记 s [ i ] = ∑ j = 0 i a [ j ] s[i] = \sum_{j = 0}^{i}a[j] s[i]=∑j=0ia[j],那么将 a [ i ] a[i] a[i]传递到 a [ i + 1 ] a[i + 1] a[i+1]相当于 s [ i ] − 1 s[i] - 1 s[i]−1而其余不变;将 a [ i + 1 ] a[i+1] a[i+1]传递到 a [ i ] a[i] a[i]相当于 s [ i ] + 1 s[i] + 1 s[i]+1而其余不变; p ∣ a [ i ] p|a[i] p∣a[i]则等价为关系 p ∣ s [ i ] p|s[i] p∣s[i](可以从正反面做一个简洁而容易的证明)。值得注意的是,每个格子都是非负数,所以还应该保证 s [ i ] s[i] s[i]的不减性。
如是,我们将原题变成了一个新的更容易处理的问题。更容易是因为,我们基于贪心的办法,希望每一个 s [ i ] s[i] s[i]成为最靠近的p的倍数,也就是变化 m i n ( s [ i ] m o d p , p − s [ i ] m o d p ) min(s[i]modp, p - s[i]modp) min(s[i]modp,p−s[i]modp)次。而且,由于起初前缀和的性质, s [ i ] s[i] s[i]已经是不减序列,从而在一次新变化中,无论前一个按照上述规则怎么变化,后一个只要也按照上述规则变化,一定可以保证新生成的序列也是一个不减序列。从而这道题只需要对每一个可能的因子顺序遍历一次 s [ i ] s[i] s[i]不断添加答案即可。
通过这道题学到了一种似曾相识但是不善利用的技巧:对于左右传递的问题,在前缀和的角度下,其实就是在长度为1的区间做一次区间修改,也就是说这是前缀和的一种特殊情况。类似的问题曾经在线性代数行列式有关性质的证明中看到,据此可以抽象出一种前缀和的数学思想:只关心变化区间的某些数学特征,通过某种表达办法使得其对全局关系的影响最小,从而达到简化问题的目的。
另外,针对于本题原本的模型而言,等效的思想也很重要:对于一个点而言,可以考虑它对外变化产生的影响,等价地也可以考虑它被外部的变化而造成的影响。这一点思想在二叉树 n 0 = n 2 + 1 n0 = n2 + 1 n0=n2+1的性质证明中体现的淋漓尽致。所以如果某个元素需要被分配(或分配给他人)才能成为因子的倍数,那么在前缀和的往前循环计算中,其实就是不断在计算可以对其产生影响的元素的贡献。
(这一点感觉阐述的不太对)不过多从不同的等价角度来看问题会有好处