一些圆环问题
环上连通问题
现在有n个顶点形成一个环,顺时针编号为0,1,…,n−1,相邻的两个顶点有连边。第i个顶点和i+1顶点的连边权重为wi。现在希望有q个请求,每个请求指定两个顶点。现在要求保留环中总权重最小的一组边的子集,且每个请求中给出的两个顶点之间总是存在至少一条路径。
首先讲一个线段树的做法。很显然我们至少可以删除一条边,我们循环遍历删除的那条边,之后发现环成了一个序列,而每个请求变成了一段区间,我们不能删除被区间覆盖的边,但是能删除所有不被区间覆盖的边。很显然正常做的时间复杂度为O(nq),但是实际上可以发现对于相邻的两条边,删除一条并恢复另外一条,实际上区间的总插入和删除次数是O(q)级别的,因此我们可以用线段树维护,总的时间复杂度为O((n+q)log2n)。
下面讲一下更快的O(n+q)做法。思路非常简单,就是我们可以把每个请求视作一段区间(从较小的顶点到较大的顶点),之后记f(i)表示覆盖边(i,i+1)的请求集合。可以发现,如果我们删除边(i,i+1)后,所有出现在f(i)中的请求必须经过(n−1,0),而所有未出现在f(i)中的请求可以,不能经过(n−1,0)这条边,即一旦选择删除边(i,i+1)后,所有查询的连通方案都由f(i)给定的,并且总是有方案的。如果f(i)≠f(j),我们不能同时删除边(i,i+1)和(j,j+1),因为二者的方案存在冲突。因此我们只需要维护f(i),并按照它们代表的集合分组,找到分组总权最大的那个分组中的边删除即可。维护分组是很有难度的,我们可以用随机化的方式,为每个分组维护多重集合的哈希信息,之后判同就变成了O(1)的整数比较问题。如果使用哈希表来分组,时间复杂度会优化到O(n+q)。
环上传递问题
题目1:一个环上有n个人,顺时针编号为1,…,n。第i个人持有ai个糖果。你每个回合可以指定某个人,将他手头的一个糖果传递给顺时针下一个人(前提被选人至少有一个糖果)。现在给定b1,…,bn,保证a1+…+an=b1+…+bn,问至少需要多少个回合,才能使得对于任意1≤i≤n,第i个人正好持有bi个糖果。
记ci表示第i个人向下一位总共传递的糖果数。可以发现bi=ai−ci+ci−1。可以发现如果我们令c1=x,那么有ci=x−ti。而我们需要的回合数为∑ni=1|x−ti|。这个问题等价于在数轴t1,…,tn上都有一个点,现在要在数轴上选择一个点x,它到所有存在的点的总距离最小。很显然我们选择所有存在的点的中位数就能达到最优。
总的时间复杂度为O(n)。(我们最后不需要排序,使用第k大算法即可)
题目2:一个环上有n个人,顺时针编号为1,…,n。第i个人持有ai个糖果。你可以对每个i指定一个0≤ci≤ai。之后第i个人会向顺时针下一个人传递ci个糖果。设之后第i个人持有的糖果数为bi,要求返回b序列总共有多少不同的可能值,结果对素数p取模。
可以发现如果min(c)>0的时候,我们可以让所有ci−min(c),b是不变的。因此我们可以认为min(c)=0。
令di=ci−ci−1。那么有bi=ai−di。很显然有多少不同的d序列,就存在多少不同的b序列。
下面我们证明c和d序列一一对应。假设两个不同的序列c和c′,产生相同的d序列。分两种情况讨论:一种是存在i使得,ci=c′i,那么由于d相同,可以直接得出c=c′。还有一种情况是存在一个i,使得ci=0且c′i>0,这时候由于d相同,可以得出c′i是c′中的最小值,而它不满足min(c′)=0。
因此我们的答案就变成了存在多少c序列,满足0≤ci≤ai,且min(c)=0。答案为∏ni=1(ai+1)−∏ni=1ai。
总的时间复杂度为O(n)。
环上匹配问题
题目1:给定2n个人,顺时针编号为1,…,2n。现在要求让环上的两两拉一条绳子,且绳子之间的交点数最多(重复的交点也要多次统计)。
很显然让i和i+n共拉一条绳子,这时候任意两条绳子都有交点,达到理论最大值(n2)。
总的时间复杂度为O(n)。
题目2:给定2n个人,顺时针编号为1,…,2n。现在要求让环上的两两拉一条绳子,且绳子之间的交点数最多(重复的交点也要多次统计)。其中我们已经存在k条绳子,拉第i条绳子的人为ai和bi。
提供一道题目。
实际上我们把所有未匹配的人按照顺时针排序后,第i个人和第i+n−k个人拉一条绳子即可。
可以发现如果(a,b)和(c,d)形成的两条绳子无交点,那么(a,d)和(c,b)就一定有交点,且与其它绳子的交点总数是不会减少的。换言之最优解的情况下,未选择的绳子必须两两相交,而这时候只有一个唯一解,就是每个人和对面的人拉绳子。
总的时间复杂度为O(n)。