在下面网址看效果更佳>_<
http://mlz000.github.io/2015/08/17/2015-ACM%E5%A4%9A%E6%A0%A1%E8%AE%AD%E7%BB%83%E7%AC%AC%E4%BA%8C%E5%9C%BA/
题外话
颓废了一万年终于把第二场的题补完了,除了丧病的第一题。。
hdu 5301(1002) Buildings
Solution
水题,仔细讨论各种情况即可
Code
hdu 5302(1003) Connect the Graph
Solution
构造题,比赛时没看,赛后发现挺水的。由于连接黑边白边只有
0,1,2
三种情况,0我们就不管了。
不妨想考虑白色边,
1,2
的情况我们只需要先构造一个长链,解决
2个1和所有2
,然后再把1的搞出来。然后为了防止重边,做黑色边的时候有同样的方法,连边时隔着一个点连即可。
Code
hdu 5303(1004) Delicious Apples
Solution
贪心的好题,有两种情况,一种是都从两个半边取,另外一种是从一边开始取回去后,绕后另外一个半边取。但是注意到环最多肯定是只绕一次的,如果绕两次我们明显可以只绕一次,然后再走一个半边。显然更优。
预处理的时候把所有苹果按位置排序,dp一下即可。
Code
hdu 5304(1005) Eastest Magical Day Seep Group’s Summer
Solution
好题,删掉
m−n
条边后剩下
n
条边,可以看出是一个树上有一个环,看到数据范围很容易想到枚举环上点的集合。然后剩下的便是生成树计数问题,可以用Matrix-tree定理解决。
那么如何求点集为
复杂度
Code
hdu 5305(1006) Friends
Solution
水题,随便搜搜就过了= =
Code
hdu 5306(1007) Gorgeous Sequence
Solution
神题,主要考察复杂度的分析= =然而我并没怎么理解QAQ。。。
打了和正常线段树一样的标记tag,另外记录了一个cov标记,表示该节点下多少个叶子节点被控制,还维护了mx,表示最大值。每次修改的时候,不直接修改,先dfs到叶子节点,清一下之前的标记,然后再返回来修改该节点。sum更改时只要增加tag值控制的节点的sum即可。
感觉非常的玄幻= =太神了。。。蒟蒻不太理解QAQ
Code
hdu 5307(1008) He is Flying
Solution
比赛时没怎么想,赛后发现并不难。
首先容易想到用
s[i]
表示前
i
段的和,答案是
变化一下形式得
这样熟悉FFT的同学马上就会发现这是个卷积的形式,FFT直接搞就可以了。由于精度问题,可以选择大质数的NTT,或者两个int型的NTT再中国剩余定理合并。实测选取大质数NTT会更快一些。
Code
hdu 5308(1009) I Wanna Become A 24-Point Master
Solution
24点= =水题,就是麻烦。。。
我的做法是分为
n是否大于等于12
,如果
n≥12
,那么显然可以搞出
2×3×4
这种形式,分奇偶不同处理一下即可。比如多的一些数是
4
,那就不停的乘4除以4即可。
Code
hdu 5309(1010) JRY is Fighting
Solution
这题看了鸟神的题解一直没看懂= =。。最后问了他才搞明白。。感谢鸟神。
很容易想到二分答案,如何验证是个问题。首先预处理出一个数组
r
,
考虑下面check长度为x的代码,建议和输出答案的
我们将点转换为区间考虑,
d[i]
表示
i
到终点的嗑药次数,如果
- (1)
r[i]>n 表示这个点可以直接到终点,显然我们可以再这点嗑药- (2) r[i]−i<x ,这个点显然不能嗑药,因为间隔 <x
- (3)否则 r[i]+1>i+x ,如果最近的间隔到了 i+l 这一时刻可以到达最后的终点( d[i+x]>d[r[i]+1] ),显然我们这第 i 时刻可以嗑药。
同时由于我们要求字典序最小,显然如果能取前面的就尽量取前面的,这个
d 数组挺难理解的,不知道我自己理解的是否透彻QAQ,可以把 d 数组看做后面整个区间的一个最值,从后往前推时d 值不降,呈阶梯状,变化时表示可以嗑药。注意到第一次嗑药时没限制的,最后特殊判断一下即可。bool check(int x) { d[n] = 0; for (int i = n - 1; i >= 1; --i) { if (r[i] > n) d[i] = d[i + 1] + 1; else if (r[i] - i < x) d[i] = d[i + 1]; else d[i] = d[i + 1] + (d[i + x] > d[r[i] + 1]); } return d[1] > d[r[0] + 1]; } void print() { for (int i = n - 1; i >= 0; --i) nxt[i] = d[i] > d[i + 1] ? i : nxt[i + 1]; int top = 0; int x = nxt[1]; while (x) { s[top++] = x; if (r[x] > n) break; x = nxt[x + ans]; } }
Code
完结撒花!
继续补题!>_<