您的位置:首页 > 其它

2015acm区域赛长春

2015-11-03 15:30 309 查看
F.Almost Sorted Array(hdu 5532)

LIS

题意:

给你一个数组,问你是否能去掉其中一个元素,使得剩下的是一个非递增序列,或非递减序列

数据范围:

n<=10^5,ai<=10^5

思路:

非递增和非递减分开处理(下面用单增来代替非递减)

判断能否单增,暴力地从左往右扫,扫到不满足单增的相邻两项,判断下是删除左边还是删除右边。然后继续扫,能扫到结尾就是ok,又遇到不满足的就不行了。这样做复杂度是O(n)

由于没有卡nlogn,所以你大可以套LIS模板,这里就是最长单增子序列,二分查找的时候要找上界不是下界。dp完看dp[n-1]是否合法,合法说明能到达这个长度,就是可以的

总结:求最长上升子序列,看长度能否达到n-1

G.Dancing Stars on Me(hdu 5533)

计算几何

题意:

给你n个点,问它们是不是组成一个正n边形

数据范围:

样例数<=300,n<=300,坐标绝对值<=10000

思路:

本题的坑是,坐标是整数输入,然后你会发现,除了正四边形,其他的正n边形都不可能同时为整数点。所以只要判断是不是正方形就可以了

正方形怎么判断?对坐标xy排序,然后第0个点和第3个点一定是对角线,然后就判断长度夹角什么的...

假如坐标不是整数点,我们要先求凸包,看凸包的点数是不是就是n,是的话再判断长度和夹角什么的,注意夹角要带方向

总结:判断n是不是4,是4的话判断是不是正方形

H.Partial Tree(hdu 5534)

背包问题

题意:

n个点,你要连n-1条边使之成为一棵树,并且使得这棵树的美丽值最大。

一棵树的美丽值等于每个点的美丽值之和,一个点的美丽值等于f(这个点的度数),f(x)是一个映射,题目会给出

数据范围:

n<=2015,f(i)<=10000

思路:

一棵树的总度数是2n-2,每个点的度数>=1,设点i的度数是ai,可以证明只要sum(ai)=2n-2并且ai>=1,那么这棵树必定能构造出来。也就是说,只要加上这些限制,度数可以随便调了。那这个题就和图论无关了,变成背包问题了

问题变成,有n个物品,每个物品在不同的花费有不同的价值,你要使得总花费等于2n-2的情况下,价值之和最大

令dp[i][j]表示第i个物品花费了j之后的最大价值

dp[0][0]=0,dp[0][j]=-inf

dp[i][j]=dp[i-1][j-k]+f(k),k>0

尽管空间可以压成一维,但是时间是O(n3)的,这样的dp显然不符合要求

这样考虑,每种度数的点有对应的度数花费,然后每种点有数量限制,这里的数量的含义是这种度数的点最多有多少个。虽然这样好像可以变成多重背包,但实际上也是无法确保dp[2n-2]就是用了n个点的

换另外一个思路,我们先让所有的点的度数为1,然后剩余的度数就是n-2,这时候每种物品的定义是某个点从度数为1升级为点数为i(i>1),对应的花费就是i-1,价值是f[i]-f[1]。

这样做避开了dp中物品数要等于n的限制,因为升级的点和不升级的点的总数总是等于n的,不过同时它们要非负。怎么确定它们都非负,由于升级的点数肯定是非负的,所以你要确保无升级的点数非负,也就是说升级的点数不能超过n。

我们看,物品的最小花费是1,而剩余的度数只有n-2,也就是你最多只能做n-2次升级,因此升级的点数不可能超过n,所以说这样处理可以无视掉点数等于n这个限制

某种物品的所有数量的总花费多于花费的上限,多重背包就能等价于完全背包。所以我们抽象出这些物品,然后直接跑完全背包,得到dp[n-2]。dp[n-2]是升级的价值,加上一开始让所有点的度数为1的价值n*f[1],就是答案

总结:把问题变成背包问题,先让所有点度数为1,再构造物品,跑完全背包

J.Chip Factory(hdu 5536)

字典树


题意:

给你一个数组,求max((ai+aj)⊕ak),要求i≠j≠k

数据范围:

n<=1000,ai<=10^9

思路:

暴力是O(n3)的不用多说,但据说现场能水过...后来hdu加强了数据,我加了个剪枝水过了,剪枝利用的原理是两个数的异或的二进制码的长度(没有前导零),一定是小于等于这两个数的二进制码的长度的最大值的,并且如果这两个数的长度不等,异或出来的数的长度就会等于这两个数长度较大的那个

剪枝就是,先把ai+aj枚举出来,然后分组,按它的二进制码长度分组。就刚才我们知道,只要存在ak的长度不是分组的最大长度,那么答案的长度一定是分组的最大长度。

我们枚举ak,先让ak和分组中最长的那组异或(当然要保证合法的前提),更新答案。然后看当前的最优答案的二进制码长度是否比ak要长。比ak长的话,就刚才的推理,说明了最终答案一定是分组的最大长度,那么既然ak已经和最大长度的ai+aj异或过了,那更短的那些就没必要异或了,就是这里剪枝了!如果答案和ak一样长,那我们老老实实地把剩余分组都异或一下。这样的复杂度应该也是O(n3)的,但是那个剪枝比较强,卡过去了

摆正姿势,正确做法是字典树,把所有的ak以二进制码的形式放进字典树(要包含前导零),然后枚举ai+aj。每次操作前先在字典树删除ai和aj,操作后再加回来,确保i≠j≠k。

操作是ai+aj也变成二进制码,然后在字典树上从高位开始走,在当前的位,尽量选与ai+aj这个位上不同的枝条。比如ai+aj的这个位是1,那去0,没有这个枝条才去1。这样子从高位到低位考虑,每步的决策必然是最优的,在走的时候记得一边走一边算答案就是了

数的二进制码的长度默认是31,总的复杂度是O(31*n2+31n)=O(n2)

总结:用字典树保存ak,枚举ai+aj在字典树上贪心决策

L.House Building(hdu 5538)

水题

题意:

给你一个矩阵,它是一间屋子的平面图。矩阵每个格的数字表示屋子在这个点的高度,你需要给这间屋子的表面涂色(不包括地下部分),问要涂多少格

数据范围:

行列<=50,高度<=1000

思路:

对于某个点的一条柱,它有五个面要考虑(底面不用),向天的面直接+1就好,其他四个面就要看相邻的点的柱子高度。某个面对应的相邻柱子高度比自己高的话,那这个面就没必要涂了。否则,要涂的格就是高度差。

因此对于一个点,你遍历它的邻居就知道这个点的柱子要涂多少格。总的复杂度是O(4*row*col)=O(n2)

在数组的周围一圈标上零,可以省去边界的判断

总结:遍历每个点,考虑它的邻居的高度,计算这个点要涂色的格子数

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  区域赛