月度归档:2013年06月

[POJ 2482]

Stars in Your Window

这题前面竟然是一封情信,字里行间都饱含作者的深情……于是又搜了下kinfkong,是位中大的前辈哦,都31岁结婚了。他博客里的文章也挺有意思的……

扯远了,回到题目本身吧。题面是:在二维平面上有N颗星星,各有一个亮度值c,问如果用一个长W宽H的矩形来括住某些星星,如何使窗口内星星亮度和最大。

说实在的,题目本身也出得非常巧妙。解题需要两次利用区间值求和的思想,即在[a,b]区间上加c,相当于在顺序遍历的基础上在a点加c,b+1点减c。第一次是在y轴方向上,若在(x,y)点处有一颗星星亮度为c,则在(x,y+H)上增加一颗亮度为-c的星星。这样,由y=0向上更新线段亮度值,便能将矩形区域求最大和转换成线段求最大和。第二次则是在x轴方向上的,对横坐标x亮度为c的星星,增加一颗x+W处亮度为-c的星星,这样便能进一步将线段最大和转换成点最大值。由此,便能利用线段树在每次插入星星的同时O(lgN)地更新最大亮度值了。

不过题目分类里写得这题属于“静态二叉检索树”。。。。这个暂时还没想出来该怎么写。。。

[POJ 2750]

Potted Flower

分类表里最后一道线段树了。

题意大概是:有一个环,环上有N个整数,求在每次更新环上某个值后,环(除整个环外)任意弧上最大的整数和。

乍看下去,虽然提示是用线段树,但还是想了很久也没思路。再看了下输入规模,N最大10^5,更新次数M也是10^5,于是单次更新的处理时间只能是O(lgN)的。这样便能看出来是每次更新都在线段树上作O(lgN)深度的线段信息更新,再由根结点信息得到结果。

这里由左右子结点得到父结点信息的题推关系还是挺麻烦的……要考虑左连续区间最值和对应的最右元素位置,右连续区间最值和对应的最左元素位置,以及区间中任意子连续区间上的最值,再加上区间上全部整数和,总共是6个量。

这里要记录左右最值区间对应边界位置是因为,最后在根结点处计算时是可以将最右和最左看作连续的(环的性质),这样如果子结点上左右区间有重叠时,直接相加便会出错了,因此记录边界便能在仅当左右区间不重叠时才计算值。

另外这题要求不能取整个环上所有元素,因此实际上求的是最小弧,再用全部整数和减去最小值便能得到最大弧了。

[POJ 3678]

Katu Puzzle

很神奇的2-SAT问题。找了一篇赵爽的《2-SAT解法浅析》。作者是高中生啊,查了下却发现是05年交大ACM总冠军队的成员……Orz

题目抽象出来后就不难做了,建一个含2*N个点的有向图,边由逻辑运算给出,边(u,v)表示选了u点则必须选v。编号为i的点对应图中i*2和i*2+1的两个点,分别表示i点取值为1、0。点A、B间由逻辑运算生成的边如下:

A & B == 1: 增加边(A*2+1,A*2)和(B*2+1,B*2);

A & B == 0: 增加边(A*2,B*2+1)和(B*2,A*2+1);

A | B == 1: 增加边(B*2+1,A*2)和(A*2+1,B*2);

A | B == 0: 增加边(A*2,A*2+1)和(B*2,B*2+1);

A ^ B == 1: 增加边(A*2,B*2+1)、(B*2+1,A*2)、(A*2+1,B*2)和(B*2,A*2+1);

A ^ B == 0: 增加边(A*2,B*2)、(B*2,A*2)、(A*2+1,B*2+1)和(B*2+1,A*2+1);

建好图后求强连通分量。最后判断是否对所有的i=0:N-1,是否有i*2和i*2+1不在同一强连通分量中,若成立则原问题有解,否则无解。

这里被 A & B == 1 和 A | B == 0 卡了一下……不可取的点直接引入必败边的做法非常巧妙……

同样分别使用了两次DFS和tarjan来求强连通分量,代码分别如下:

[codeforces] 杀入Div. 1!

各种磕绊过后……终于我也Candidate Master啦!附送链接:eurce01

从#184开始……一场没算分,一场C题sort用了greater_equal导致TLE,一场电脑被A没做之后……终于我也Rating 1742啦!!

其实Div. 2的题还是挺轻松的……各种水题虐虐也能加分,不过也是#189开始才过了D题,结果直接Rank 17了。

但貌似这种难度的题才相当于Div. 1的B题啊……目测接下来还是狂跪的节奏……

无论如何还是bless自己一下吧……

[POJ 2886]

Who Gets the Most Candies?

还是线段树……题目是N个人站成一个环进行N轮的筛人,每轮都筛走一个人,第i轮筛走的人得到f(i)颗糖,要求最先得到最多糖的人。第一个被筛的人为k,每次某人被筛,都会给出下一个被筛的人相对当前位置的偏移量(顺时针方向)ai,ai!=0且|ai|<10^8。 其实知道要用线段树之后,题目就很简单了……k值的维护可以通过剩余人数n-i和a[i]求出,然后每轮筛去还在环中的第k个人即可,用线段树可以log(n)得到每轮被筛的人的编号。但这题竟然卡的是求f(i)。。。换了两种方法求f(i)都超时后便老老实实打表了。。。

[POJ 2777]

Count Color

依然是线段树,和POJ 2528比较类似,增加了查询某段区间内颜色种类数目的要求,这里由于颜色总数T值比较小(1<=T<=30),因此可以用一个int以位相量的形式来表示某段区间包含的颜色情况。这里lazy tag用来表示结点的区间是否只含一种颜色。

用C++最快也只有266ms,但代码量只有第一名a3616001(79ms)的一半……这个可以用作自我安慰吗?

[POJ 2528]

Mayor’s posters

很基础的线段树题目。在范围[1,10000000]内依次覆盖n段区间[ai,bi],问最后未被完全覆盖的区间共有多少个。

做的时候参考了http://bbs.byr.cn/#!article/ACM_ICPC/71462。关键是对每个结点要设置tag记录是否为叶子,每次拆分时,叶子结点的值继承被拆结点的值,并将tag设置为1。插入每段区间时,根据区间和结点之间的上下界关系进行相应处理即可。最后全部插入完毕后,用DFS查找值有效的叶子结点种类数目:

[POJ 3308]

Paratroopers

典型的最小割模型题目。做之前先读了国家集训队论文《最小割模型在信息学竞赛中的应用》。

题目大意是,有一个m*n的网格,m行和n列各对应一个权值。网格里面有l个点,如何在m行和n列中选择某些行列,使所有的点被覆盖,且使行列权值之积最小。

建图时S连所有行,E连所有列,行和列之间的边则对应原图的点且容量为无穷。这样便能应用最小割模型,得到的点集划分中割边必定为有穷边,且对应着原图中选中的行或列,使原图中每个点都能被覆盖(不能同时到S、E可达)。这里由于所求是作乘,将其取log,便转换成加法运算了。用EK求得最大流后,再从S点出发作DFS,就得到了实际的最小割方案,再依次检查遍历情况作乘即可。

不知为何c++竟然没有log2,CE了一次…T__T

[POJ 3352] and [POJ 3177]

Road Construction

Redundant Paths

两题几乎是一样的,除了数据范围有些许差异。题目大意是,有一个连通的无向图,求至少需要添加多少条边,才能使得在图中任意移去一条边后仍然连通。

(又)WA了一天后发现:可以先缩点,将图转换成一颗树,然后求树上叶子结点的数目cnt,如果cnt==1输出0,否则需要增加的边数即为(cnt+1)/2。另外由于是无向图,不需要用入栈标记数组来判横向边,且已知图是连通的,DFS调用一次即可,略为简化了些代码。

具体实现如下:

[POJ 2186]

Popular Cows

题目大意:一个有向图,边(i,j)表示牛i认为牛j受欢迎,这种关系具有传递性。问:图中存在多少只牛被其他所有牛认为是受欢迎的?

很喜欢这种题……简洁的题面和清晰的题意,但足够一想想一天的。

思路是求强连通分支后缩点,再判断缩点后是否存在唯一出度数为0的点(也即最受欢迎牛群k),然后再判在反向图中,是否其余缩点从点k出发都可达。这里有个坑:如果总共只有一只牛,直接输出0。

具体实现上,分别尝试使用了CLRS上的两次DFS和tarjan来求强连通分支。另外,这题也是第一次写缩点,用了并查集,感觉有点累赘。

两次DFS:

tarjan(总感觉自己敲的东西有种山寨感?):

两种算法的耗时相近,但是两次DFS怎么会和一次DFS的tarjan差不多呢?实在不太明白…