2012 Multi-University Training Contest 7

 

1003 Dragon Ball

不用单调队列也蹭过去了

代码:

http://www.cnblogs.com/pony1993/archive/2012/08/14/2638697.html 

 

 

 

1001

简单的图论题

每条边除了有边权以外,还有一个字母标记。标记可以是“LOVE”里面任意字符。

每个点,要拆成四个点,分别代表到达该点的标记为L,O,V,E的最短路。

第一步就是求最短路,直接spfa就可以了。

trick在于,至少要找到一个LOVE串,在只有一个节点的时候,有几条自环,至少必须走LOVE四条自环。此时,必须另外加一个节点表示开始节点。

还有一个trick就是距离可能超过int。

1 2 1314520 L

1 2 1314520 O

1 2 1314520 V

2 3 1314520 E

3 4 1314520 L

3 4 1314520 O

3 4 1314520 V

4 5 1314520 E

...

这种情况下1313个点,2624条边,每条边长度1314520,并且每条边都必须走,所以,超int了(至少signed不够)。

SPFA跑一趟就可以了。


1002

暴力搜索,由于是两人对弈,即在一棵与或树上搜索.



1003

单调队列+DP

设dp[i][j]表示第i批龙珠中取第j个需要花费的最小体力。

dp[i][j] = min{ dp[i-1][k] + abs(pos[i-1][k]-pos[i][j]) } + cost[i][j];

如果枚举k的话总复杂度位m*n*n,会超时。

可以看出若每个状态只由上一层位置在其左边的状态的转移而来的话:  

dp[i][j]

min { dp[i-1][k] + pos[i][j] - pos[i-1][k] } + cost[i][j]

= min { dp[i-1][k] - pos[i-1][k] } + pos[i][j] + cost[i][j]

dp[i-1][k]-pos[i-1][k]是个确定的值,就是相当于求位置在pos[i][j]左边的上一层状态中值最小的,可以用个单调队列维护。由右边转移来的类似,再处理一遍右边转移来的取最优。

因为要对同一层的点排序,所以总复杂度是m*n*logn。



1004

DP

用dp[i][j][a][b][c][d][2]表示长为i宽为j,四边颜色分别为a、b、c、d,并且当前需要画横线还是竖线时的总方案数,然后枚举画线位置以及其中一部分所染的颜色进行状态转移。颜色表示中需要多加一种表示未染色,即5种。



1005

简单模拟

题意:

已知矩阵A:2 3 1 1

                  1 2 3 1

                  1 1 2 3

                  3 1 1 2已知矩阵B(8位16进制表示)。

求A*B得到的新矩阵。

定义加法为异或运算,乘法分3种情况。

1: 1*Bij = Bij

2: 2*Bij = Bij(左移一位) (若Bij最高位为1需再xor1B)

3: 3*Bij = 2*Bij xor Bij

解法:简单模拟,用%x,%X以及位运算可以简化代码量。



1006

简单题

对于n*n的方格纸,在格子里填颜色,要满足任意水平、垂直翻转后看到的图形都一样,则可填 (n/2+1)*(n/2)/2 种颜色。

有些方格已经填了颜色,对于已填色的方格,会固定对应格子的颜色,使得可填颜色数减1.注意多个已填色格本来就是同色格,不要多减因n范围比较大,不能直接开数组,用map记录即可

最后,填色方法数为 可用颜色种类k^可填颜色数,用下快速幂即可



1007

线段树

题意是要找某个点其子孙中能力值其能力值的中忠诚度最大的。

首先可以遍历一遍将树上每个点标记为一维区间上的某个点,且在同一棵子树内的点是连续的一段。将所有点按忠诚度从大到小排序,忠诚度相同的编号小的排在前面,然后扫描一遍,扫描时维护一颗线段树,先查找该点为根节点的子树内的最优值,然后插入该点的忠诚度。



1008

计算i从1~n*(n-1)/2 所有(Ki^Fib(Ki)+1)的和.

数论+矩阵快速幂,注意精度



1009

几何

题目给出n个柱子一字排开,并且整体倾斜angle角度.向左为正,向右为负.为使考虑简单,当angle为负时,将n个柱子颠倒顺序,angle取绝对值,得到的结果实际上是一样的.因此只需考虑向左倾斜

同时,为了避免大量坐标变换,柱子倾斜,其实就是地平线\水平面倾斜,因此,柱子不变,柱子左下角设为原点.从原点往右下角拉一条线出来作为倾斜的地平线.

      *
      *  *
  *  * **
  ******
*******


  \       -angle 
   \ 
     \ 

接下来,计算每根柱子顶端与地平线的最大垂直距离.那么,水体肯定在2根距离较高的,柱子中间.称这2根柱子匹配 
找到距离最大的柱子,那么,对于左侧的柱子,肯定与右边最近的,与地平线距离大于等于本身的柱子相匹配.对于右侧的柱子,肯定与左边某柱子匹配.因此做向左向右两次循环即可找出所有匹配. 

此时,问题和求没有倾斜时的蓄水量一样了,2种做法 
1.利用普通循环,i为当前扫描的柱子,j从i+1到maxi循环,找到第一个大于等于柱子i的,即找到匹配i->j.复杂度O(n) 
2.从最高柱开始扫描,维护单调栈,stack[top-1]是当前柱子高度,stack[top-2]是前面大于等于当前柱子高度的最近的柱子.左右扫描一遍后,就可以得到当前柱子的匹配柱编号 右侧prev[i] 左侧next[i]. 
因为柱子不会移动,用第1种更简单也更快. 


接下来计算i 和 prev[i] 2个匹配柱之间的装水量.2个柱子之间可以确定水平面连线,计算每条柱子和线之间有多少面积即可. 
因为倾斜角固定,因此对于每根柱子,水平面的下降高度是一样的,水柱都是由一段长方体+顶部三角形组成,顶部三角形面积也是固定的.因此,不需要用到复杂的计算公式,直接加面积即可.要特判一下,有的柱子,顶部的三角形水体只有一部分,计算方式不一样,并且,当角度为0时,避免出现计算异常. 

复杂度O(n)



1010

栈+二分+DP

题目给出n个方块,宽度为1,高度给出,直线排列.

最左侧方块可以移动至最右侧,移动次数不限.

有k个单位的建筑材料,可以补充到任意方块上,且补充后的高度不能超过之前的最高方块,求最大储水量.

若不考虑补充的建筑材料,则将n个方块复制成3份,直接找出中间那份的最高方块,例如


1  3  2  5  2  3   4  |  1  3  2  [5]  2  3  4 |  1  3  2  5  2  3  4

                              i         maxi

那么,maxi左右两侧的水体不会互相相通,因此,计算从maxi开始,以第i块为边界的最大装水量f[i],就可以计算出移动方块时的最大装水量了.

                result = max{f[i]+f[i+n-1],n<=i<2*n}

当i从maxi开始向右扫描时,因为方块i肯定是和左侧最近的,高度大于等于本身的方块相匹配,之间的水体高度取决于方块i,因此,循环时维护一个单调栈,栈的栈顶第2个元素就是要找的匹配方块.因此,在不考虑建筑材料时,O(n)即可得出结果.

如图,每个方块都与前面最近大于等于本身高度的块匹配,装水量为 2个方块间的距离*2个方块的较低高度 - 2个方块间其他方块的高度和,O(1)可算,从maxi开始扫描,每次将栈中小于h[i]的元素都出栈,将h[i]压入栈中.stack[top-2]即为左侧匹配的方块

    
    接下来考虑有k个单位的建筑材料的问题.先考虑加1单位.    
对于任何方块的情况,称起到挡水作用的块为关键块.如下图5块
 
    那么,建筑材料加在非关键块上,肯定不如加在关键块上优.例如加在3、4之间,只能白占存水空间,肯定不如加在关键块4上。    
因此,i从maxi开始循环时,建筑材料要么加在块i,要么加在前面的关键块上。

如果加在前面关键块,i的前面匹配块为prev,f[i][1] 表示maxi到第i块,加了1单位建筑材料的最大装水量
f[i][1] = f[prev][1] + h[now] * (i-prev-1)-(sum[i-1]-sum[prev])
如果加在块i,那么,块i高度+1,前面匹配块可能改变掉,应在stack二分查找刚好>=h[i]+1的prev
f[i][1] = f[prev][0] + min(h[prev],h[i]+1) * (i-prev-1)-(sum[i-1]-sum[prev])取2者最大值

扩展到k单位,就枚举加在当前块i的单位数,加上二分查找前匹配块prev即可.结果会超int,需用LL
复杂度为O(k*k*nlogn)

转载于:https://www.cnblogs.com/pony1993/archive/2012/08/14/2638476.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值