CF202 Div 1 题解

来源:互联网 发布:python爬虫是什么发展 编辑:程序博客网 时间:2024/05/21 11:21

这场的题目很赞啊!感觉相对201来说还是更喜欢这类题……


A:

题意:有n个人玩游戏,第i个人希望参与a_i轮游戏。每轮游戏只能有n-1个人参加,求最少需要进行多少轮游戏才能使每个人满意。n<=10^5,a_i<=10^9。

解:答案显然可二分。考虑如何检验,设答案为ans,第i个人不参与游戏的轮数为x_i,应满足对于任意1<=i<=n有ans-x_i>=a_i,且\sum{x_i}>=ans。变形可得x_i<=ans-a_i,带入后面的式子得\sum{ans-a_i}>=ans,即ans>=\sum{a_i}/(n-1)。这样我们直接得到了答案的计算式,即为ceil(\sum{a_i}/(n-1))。另外ans还要大于等于所有的a_i。复杂度O(n)。


B:

题意:给定一棵n个点的有根树,所有叶子处有权值。叶子的权值只能减小不能增加。定义非叶子节点的权值为所有儿子的权值之和。对于所有非叶子节点,要求其所有儿子的权值相等。求为了满足这个条件,所有叶子权值和减小量的最小值。n<=10^5,权值<=10^8。

解:假设某个节点x有m个儿子,每个儿子的儿子数量(事实上不是,后面会提到)为son[i](如果为叶子节点则son[i]=1)。那么这m个儿子的权值应该是lcm(son[1..m])的非负整数倍。证明很简单,如果不是这样的话至少存在一个儿子不能把赋予自己的权值均分下去。那么权值就应该是不超过所有儿子中权值最小的儿子的权值的最大倍数。而son[x]应该是lcm(son[1..m])*m,也即在处理其父亲时,自己的子树应该有多少“份”需要被均分的权值。(写的比较意识流,凑合理解一下……)

另外这里lcm可能会超过long long,由于此时得到的权值必然为0,特判一下即可。复杂度O(n)。


C:

题意:给定长度为n的序列a[],另外还有m个下标集合s[1..m],对应a[]中对应下标的元素。有两种共q次操作,一种是询问某个集合对应元素之和,另一种是将某个集合对应的所有元素+x。n,m,q<=10^5,所有集合的大小之和<=10^5。

解:这是道好题!

这里是集合操作,元素不连续,而元素对应的集合也不连续,所以一般的高级数据结构应该是用不了的,只能考虑分块。

对序列分块没有,对询问分块也没什么效果。但是我们可以对集合分类:集合大小>=sqrt(n)的为大集合,其余的为小集合。不难得出大集合不超过sqrt(n)个。

考虑修改。如果修改小集合,我们暴力修改每个元素,同时去更新大集合的答案。如果修改大集合,那么我们直接给集合打标记,同时更新其他大集合的答案。

再考虑查询。如果查询小集合,先暴力查询每个元素,再查询大集合对其的贡献。如果查询大集合,答案直接有了。

问题在于大集合的答案怎么更新。我们可以求出所有小集合与大集合之间的并集的大小,那么修改查询就顺理成章了。

至今为止复杂度都是O(n*sqrt(n)),但是求并的复杂度呢?令p为集合大小之和。最多p个小集合,sqrt(p)个大集合,每个小集合最大sqrt(p),乍一看好像最坏有O(p^2)?实际上不是的,可以做一些简单的推倒:

求并的复杂度是小集合的大小。设有x个大集合,每个大集合大小为sqrt(p),那么小集合的大小之和为(sqrt(p)-x)*sqrt(p)。此时复杂度为(sqrt(p)-x)*sqrt(p)*x,当x=sqrt(p)/2时取到最大值,为n*sqrt(n)/4,也是O(n*sqrt(n))的。而大集合之间求交直接就是O(n*sqrt(n))的。

那么整个问题就在O(n*sqrt(n))的复杂度内解决了~

UPD:发现……实际上复杂度分析根本没这么蛋疼。一共n个元素,对于每个元素看它是否在sqrt(n)个大集合里出现过,就O(n*sqrt(n))了(抠鼻


D:

题意:给定n*m的棋盘,有些格子有障碍。从左上角走到右下角,每次只能向右或者向下走,且不能经过障碍。求有多少对除了起点终点外不相交的路径。n,m<=3000。

解:这题要用到一个十分酷炫屌炸天的定理:http://en.wikipedia.org/wiki/Lindstr%C3%B6m%E2%80%93Gessel%E2%80%93Viennot_lemma

Lindstroem-Gessel-Viennot引理(谁教教我这个名字怎么念……)

定理大致是这样的:对于一个边带权的有向无环图G,定义起点为A={a1,a2,..,an},终点为B={b1,b2,..,bn},e(a,b)代表从点a到点b的所有路径的边权和之和。定义行列式M如下:


那么就有:

这个式子这一这么解释。sigma是一个1~n的排列,第i条路径是从ai到b_{sigma_i}的路径,sign则是和sigma的逆序对有关的函数(行列式嘛)。那么求的就是从A中的某个点出发到B的某个点的所有n元组的方案数的某种有符号和。(抠鼻

……乍一看没啥用啊……别急,看下一段……

如果从a到b只有有限条路径,可以令e(a,b)为从a到b的路径条数。如果只有当a1->b1, a2->b2, .., an->bn的路径n元组才是合法路径时,det(M)就恰好是从A到B的不相交路径n元组数。

对于这道题,我们令a1=(1,2),a2=(2,1),b1=(n-1,m),b2=(n,m-1),那么只有a1->b1和a2->b2的路径二元组才会不相交,那么根据上面那段,我们可以求出e(ai,bi),而这里求e(a,b)是一个经典的DP,复杂度O(nm)。令A=e(a1,b1), B=e(a1,b2), C=e(a2,b1), D=e(a2,b2),答案就是A*D-B*C。

其实也可以这么理解,由于a1->b2和a2->b1必然会交叉,而a1->b1和a2->b2的所有路径二元组中交叉的方案都能唯一对应到a1->b2和a2->b1路径二元组的一个方案(只要把两条路径最后一次交叉到终点的部分交换即可),所以答案就是A*D-B*C。这样理解似乎更加自然也更好想到……考场上之所以那么多人过应该是想到了这个吧,上面那个定理不会那么烂大街吧……

那么复杂度就是DP的O(nm)了,写起来也很简单……

UPD:特殊情况的本质实际上就是容斥原理……这样想的话这个定理也好理解了


剩下一题待补……

原创粉丝点击