【校内模拟】【18-10-24】小C的序列 【数据结构】

题解

没有胡乱分析是因为考场上死磕第三题去了

20pts

小于等于两千,说明n2可行,枚举所有区间即可。

我咋就这么傻呢

40pts

随机生成数据,说明你只需要枚举左端点,因为你加不了几个gcd就变成1了~

60~80pts

我们刚才的思维都集中在如何统计每个区间内的gcd,当然这也是正解思路。不过,我们要考虑更为高效的方法。

考虑刚才的做法,我们时间主要都花在计算每个区间的gcd上了。但实际上,如果我们确定一个左端点,右端点不断右移,那整个区间的gcd只可能变小你变大一个给我看看

对于一个数n,它最多会有logn个质因数,那这说明啥?说明左端点不动,右端点慢慢挪的过程中,统计到的所有区间最多会出现logn个不同的gcd。

进一步分析,也就是当右端点在某些区间挪动的时候,gcd是不会改变的,而这些区间最多只有logn个。

这不就简单了吗?我们只需要找到区间与区间的分界点,就可以轻松算出以一个数为左端点的所有区间的所有gcd是哪些了。

我们考虑二分这些分界点,然后找个数据结构来查询一下从l到二分点的gcd,如果与上一个区间的gcd不一样,就把二分点往左挪,如果跟上个区间的一样就往右挪,直到刚好找到分界点。

这样的算法复杂度是nlog2n的,n个左端点 + 二分的log + 最多log个分界点。

如果我们考虑用线段树来维护区间信息,每次查询有个log,算gcd还有个log,一共就是nlog4n,60pts.

当然,由于没有修改操作,我们可以用st表省掉查询的log,也就是nlog3n,80pts。

100pts

我们来看看,这些log里面哪些可以省掉呢?

首先gcd的log不可能省,要不你算都算不出gcd。log+1。

然后查询也不可能省,你不查询怎么知道区间gcd的。log+1。

然后就是二分一个log,分界点一个log,貌似都不能丢,因为丢掉一个另一个就没用了啊。

那我们一起丢了吧!

别说,正解还真就一起丢了。惊不惊喜,意不意外!

为啥?

来来来,我们考虑一下。如果我们的左端点从最右边开始枚举,那左端点向左移动的过程中,分界点有什么变化呢?

如果你手动计算一下,你就会发现,分界点如果增加,只会出现在这一次的L和上一次的L之间;而对于之前的那些分界点,有的甚至会消失掉,但是绝对没有增加。

其实很好理解,当你新枚举的l和l-1取了gcd之后,这个gcd肯定会是L-1的因数。L-1的因数和l相比,前者的因数最多跟L一样(1*L),所以分界点最多也就是原来以L为左端点的时那么多;而如果L-1的因数变少了,分界点的个数也自然会减小。

但无论如何,可以保证之前确定的分界点的个数是不可能变多的。

所以呢,我们用个链表存下每个分界点,当l向左移动时,我们判断一下这个分界点还有没有用,要是没用就丢了(因为这一次没用以后肯定也没用了),这样就可以在O(1)的时间内找到所有分界点了。

emm,就这样,我们丢了两个log,再也不用辛苦的枚举分界点啦!
最终复杂度O(nlog2n)。

总结

跟上次长者的分析其实差不多,我们要的就是找到思路,然后寻找规律,考虑剪枝等等,最后把算法的复杂度弄到令人满意的范围内。

当然,从线段树和ST表的得分不一样来看,数据结构学的越多,越要弄清在什么时候该用什么结构,不要强行给自己增加时间复杂度,比如倍增能实现的LCA非要去用树链剖分,快排能弄好的非要用优先队列……多个log可能就丢了20分啊~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值