浙江省第6届大学生程序设计竞赛解题报告

这次比赛一共11道题目,难度上来讲,简单题和中等题都比较多。最难的是H,要dancing link。其次是E,要强联通分量缩点和dp。最简单的是A、F、I,中等题里最简单的是C,稍微要想一下的是K。B和G两道题要些几何知识,而且G写起来有点繁。D是卡时间的,需要想一下降低复杂度;而J需要排序,再dp,直接最佳匹配应该是不行的。

下面是简单分析:

[code]
A Second-price auction

我出的题。秒杀,不多说。


B Light Bulb

VB的题,不太难。稍微分析下:

设人在灯左面的位置为x,当影子不会打到墙上时,影子长为y,则有

y/(x+y)=h/H

于是y=h*x/(H-h)

这样是在x+y<=D的前提下计算出的x范围(影子不打到墙上)是 0<=x<=D*(H-h)/H

因为影子长度函数是单调增的,所以这里只要取x=D*(H-h)/H, 影子最长是h*D/H。

这是前半部分。

重要的在于后半部分,与题目给的图一样了,设影子打到墙上长为L,则有

(D-x)*H+L*x=h*D (这个式子就是定比分点)

于是计算得L=H-(H-h)*D/x

影子长是 y=L+D-x=D-x-(H-h)*D/x+H

=H+D-(x+(H-h)*D/x)

这时的约束自然是 D*(H-h)/H<=x<=D

其实只要讨论这部分的极值即可(因为影子不打在墙上且最长时的x值,就是x区间的左端点。也就是说两部分影子长度的函数是连续的)其实这个东西是单峰的,由均值不等式也好,求导也好,可以算出括号里的最小值是在x0=sqrt((H-h)*D)时取得,这就是函数取到最大值时的x值,但这个值未必在那个区间里。对于一个单峰的函数在一定区间的最大值就考虑两种情况即可,当最大值点在区间里时,就取最大值点对应的函数值,否则函数是单调的,在不考虑单增或单减的情况下,最大值在某一个端点处取得。(在两个端点处(D*(H-h)/H和D)选一个最大的y值即可),这样程序写出来很简单。当然,这里求极值可以使用三分的办法。


C Connect them

我出的题,中等题偏简单吧。就是一个mst的变形。先把边按权值由小到大排序,如果权值相同,则按边的字典序排。然后用prim算法就可以的。按排好的顺序,每次加一条不形成圈的边。这样一条边没被加进来,是因为它加进来会形成圈,而这个圈里的其他边要么权值比它小,要么权值和它一样,但是字典序比它小,于是从这个圈里删边就要删掉它。(实现可以用并查集,判断这个边能不能加)还要注意,最后输出的时候还要再排序以保证字典序。


D Derivatives

VB的题,有点难,暴力会超时。就是有m维,n项的多项式求偏导的问题。

每项都是 c*x0^d0*x1^d1*x2^d2*…*x(m-1)^d(m-1)这样的形式。

于是我们可以定义 b[j][i]为第j项,从第i维开始到最后一维的乘积。(后面对c的定义是与b是反的)

这个可以先预处理每个数的n次方的值,当然这里不预处理也没关系。

然后再把b[j][i]预处理出来, b[j][i]=xji^dji*b[j][i+1]

这部分的复杂度O(m*n)

下面,我们处理对每维求导的结果。

仿照前面的思路,实际上我们是把一段乘积分为两部分,重复使用变量c (系数),对于第i维,我们记录c,x0,x1..xi-1的乘积(含次方数)仍为c,而xi,xi+1…xm-1的乘积(含系数)在b里预处理过。当我们对第i维求导时(外层循环i),再循环j从0..n-1,

然后对第j项,需要累加到结果的值为c[j]*b[j][i+1]*dji*xji^(dji-1), 这些值都已经都算出来了,加上这项后,再在c[j]乘上xji^dji,以便该项在下一维求导时使用。

这样总复杂度O(m*n)


E Disaster Area Reconstruction

VB的题,难题。题目的意思就是在一个有向图里,加一条边,让最大的强联通分量(点数最多)尽可能大。

想法上并不太难:先求全部的强联通分量,然后把每个强联通分量看成一个“大点”,这样的“新图”无圈,每个“大点”有权值,权值等于这个强联通分量里的顶点数,还要记录每个联通分量里标号最小的点和标号次小的点。因为新图无圈,于是可以求一条最长链(一条链,链上的权值“大点”和尽可能大)。这个可以用dp 具体就是, dp[x]= max(dp[y]+w[x])。以 “大点”x为结尾的最长链,是所有以能指向x的点y结尾的最长链的权值与x的权值和。(w[x]表示x的权值),这个过程中记录开头大点和结尾大点的最小的原图顶点。最后输出即可,有些特殊情况,例如最优的最长链只有一个“大点”,这时根本不用加边,所以非要加条边的话,只要加1 2即可。

题目的时限很宽泛。


F 80er’s Memory

Flee的题,简单题。就是给定一个集合的单词。然后问后面给定的每组单词有几个在给定的集合里,直接用set查找即可。


G Reforestation

Flee的题,中等题。首先利用类似最短路的方法求出每棵树最终生长了多长时间,也就是最终树的半径。具体做法是,初始所有的树都是没停止生长的。然后对于每棵没停止生长的树,与其他所有树求一下可以生长多久,然后把时间最小的标记为停止生长。直到所有树都停止生长。

接下来,就是2分时间,对于每个时间,可以知道在这个时间时每棵树的大小。然后用圆的2条切线求出阻碍的区域,这实际上是个极角的区间。求出所有区间的并,如果覆盖了0到2*pi,则可以,否则不行。后半部分的做法应该是经典且常见的做法了,就是问一些圆能否包含一个点,这样类似的题有很多。思路是这样的,好像很容易写错,这题还rejudge了。


H Treasure Map

hh的题,这次比赛的难题。(第2难的应该是E)规模有点吓人。纯搜索题,不过要用dancing link(跳跃表)。就是一个n*m列的表,每个小块可以覆盖一些列,然后要完全覆盖(不重叠)。这是最直白的dancing link了,但是规模太吓人了,而且要求块数最少,因此并不是求到解后就退出,而是要求出所有解来。但是跳跃表写好后效率却出奇的高。对于dancing link,我的认识还不是很深刻,因为我出了一道规模上比这个题小很多的题大概只有不到20列,但效率却出奇的低(没选用)。无论如何,这道规模大的吓人的题,可以用跳跃表以极高的效率解决掉。


I A Stack or A queue

我出的题,也是简单题。不用多说了,两个一样的,不回文就是queue, 回文就是either,两个反序的话就是stack,否则是neither。


J Dream city

我出的题,中等题。其实只要想清楚一个问题,最后选的m棵树,一定是按b从小到大的顺序选的。这是因为如果选定了m棵树(x1,x2…xm),这些树的增量实际上是0*b[x1]+1*b[x2]+2*b[x3]+…+(m-1)*b[xm],显然由排序不等式,顺序和最大。这样只要按b排序,然后是一个简单的dp,dp[j]表示前j棵树在前i天的最大收益。反复使用dp[j]即可。

外层循环i=0..m

内层循环两次:

(1) j from n-1 downto i dp[j+1]= =dp[j]+a[j]+i*b[j];

(2) j=i+1 to n dp[j+1]=max(dp[j+1],dp[j])

最后dp[n]为结果

Dp复杂度是O(m*n)。另外,其实如果单纯的思考,可以构造一个2分图,左边m个点代表m天,右边n个点代表n棵树,权值是第i天取第j棵树的收益,然后求最佳匹配。但是这样一般会超时,因为复杂度极高。


K K-Nice

Navi的题。比较简单,构造法,构造方法很多吧。起初矩阵全0,然后最外圈不变,对中间的(n-2)*(m-2)的子阵,一行一行的,从左到右分别填写1,2,3…直到(n-2)*(m-2)-k即可。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值