2017.1.16【初中部 GDKOI】模拟赛B组

今天早上做着做着XC突然叫我去做小学生的题,耗了一个多小时,回来再做B组时,就没有时间了。

下面是总结:

T1:比赛时用了暴力,因为忘了mod所以0分。正解:树形dp。

我们用一个dfs从根节点往下搜,设f[i]表示第i个节点到它任意一个子节点的路径乘积的和,c[i]表示从i节点的任意一个子节点到i节点,再到i的另一个子节点的路径乘积的和。

然后我们枚举i的子节点,设枚举到的子节点为x,那么f[i]=sum(f[x]*a[i]),a[i]表示i节点的权值。

那c[i]怎么求呢?我们设从i的子节点x走到i,再从i走到i的另一个子节点y,显然,这条路径的乘积就是f[x]*a[i]*f[y]。但是枚举所有的x、y会超时,那我们怎么办呢?

我们设一个节点i有3个子节点,这4个子节点分别为f[1],f[2],f[3],显然,c[i]=a[i]*f[1]*f[2]+a[i]*f[1]*f[3]+a[i]*f[2]*f[3],合并后就是c[i]=a[i]*f[1]*sum(f[2至3])+a[i]*f[2]*f[3]。这样做法就简单了。我们在枚举子节点时,顺便统计已枚举到的子节点的和,设这个和为k,那么c[i]=a[i]*f[x]*k。最后的ans就是sum(f[i])+sum(c[i])。


T2:我们可以发现一个规律:设f[i]表示斐波拉契数列的第i项,s[i]表示到斐波拉契数列的第i项一共有多少个1,len[i]表示到从1到斐波拉契数列的第i项的数列有多长,那么f[i]=f[i-1]+f[i-2],s[i]=s[i-1]+f[i-1]+s[i-2],len[i]=len[i-1]+f[i-1]*i。

根据上面的公式我们可以求出第n位所在的斐波拉契数有多长,设这个长度为i,那么长度为1到i-1的斐波拉契数一定是全部都在数列里的,我们可以用上面的公式求出它们中间有多少个1,那么接下来要求的就是长度为i,在数列中的位置有小于等于n的数所包含的斐波拉契数中1的个数。

长度为i的斐波拉契数又可以分为两部分:全部包含和部分包含。我们根据n和长度为len[i-1]求出全部包含的斐波拉契数有多少个,接着求出它是从那个数到那个数。

比如n=73,则i=6、len[i-1]=46,那么完全包含的斐波拉契数有(73-46)/6=4个,这4个数是从100000到100100,。

有了上面的条件后,我们就可以求出这个区间的1的个数。

以上面100100为例,搜索1的位置(第一个位置特殊处理),当我们搜到位置为4的1时,它可以分成长度小于等于2的斐波拉契数的1的个数加上100的1的个数,即s[2]+1,接下来如此类推。我们还要计算另一个部分。那位置1的1为例,当第四个位置及其后面的位置选1时,它们都要利用到位置为1的1,那么就要加上位置为4所对应的斐波拉契进制,即2。100100每一位所对应的斐波拉契进制即是13、8、5、3、2、1。

最后我们把100100加1,得到它下一个斐波拉契数,再算它的包含位置就行了。


T3:这题可以用水法。

我们先把所有的序列从小到大排序,然后我们先看1、2行序列。我们可以用二重循环将他们两两配对,建立一个大根堆,把每次配对出来的和入堆。我们知道,堆中的节点最多只能有k个,那么当堆中节点个数等于k并且当前配对出来的结果大于等于堆顶是,那么我们就把这个二重循环break掉,否则就把配对出来的和加入堆(如果堆中节点个数等于k,那么删掉堆顶)。

在对1、2层配对完成后,我们得到一个大小为k的堆。我们把这个堆赋值给2层把它从小到大排序,之后再拿二层和三层配对。接下来以此类推,最终把n层配对完成后堆顶就是答案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值