CF 1418 G (四种做法)题解

89 篇文章 1 订阅

Three Occurrences 题解

Solution1 (Hash)

By neal

我们先考虑另一个问题:

有一个长度为 n n n的序列 a , ( 1 ≤ a i ≤ n ) a,(1\leq a_i\leq n) a,(1ain),你要计算有多少对 ( l , r ) (l,r) (l,r)满足 a l , a l + 1 . . . a r a_l,a_{l+1}... a_r al,al+1...ar中每一个数出现的次数是 3 3 3的倍数?

这个问题我们可以考虑 h a s h hash hash,我们先把 n n n个随机值装进 r a n d rand rand数组里,然后从前往后计算颜色 c c c i i i及之前出现的次数 m o d    3 \mod 3 mod3的值,记为 s u m i , c sum_{i,c} sumi,c。由于 [ l , r ] [l,r] [l,r]中每一个数出现的次数 m o d    3 \mod 3 mod3 = 0 =0 =0,所以满足 ∀ k , ( k ∈ [ 1 , n ] ) s u m r , k = s u m l − 1 , k \forall k,(k \in [1,n]) sum_{r,k}=sum_{l-1,k} k,(k[1,n])sumr,k=suml1,k

我们可以设 v a l i = ( ∏ j = 1 n s u m i , j ∗ r a n d j ) m o d    A val_{i}=(\prod _{j=1}^n sum_{i,j}*rand_{j}) \mod A vali=(j=1nsumi,jrandj)modA

然后放进一个hash table 就行了。

那么原问题怎么解决呢?

我们已经能够让所有的颜色出现的次数是3的倍数,但是我们还差要使得出现的次数 ≤ 3 \leq 3 3

不过这也没有关系,因为我们可以把hash 值存在一个vector里,然后从前往后扫描,遇到不行的就pop_front。

时间复杂度 O ( n ) O(n) O(n)

参考资料:https://codeforces.com/blog/entry/82643

Solution 2(Segment Tree)

By MrGary

我们从大到小枚举有边界 r r r

如果存在左边界 l l l满足要求,那么对于每一个颜色 i i i来讲,都是两端区间:

  1. 在所有 r r r左边的颜色为 i i i的位置,的第一个,和 r r r(左开右闭)
  2. 在所有 r r r左边的颜色为 i i i的位置,的第四个,和第三个(左开右闭)

特殊的:如果不存在用0代替。

这样我们可以在线段树上区间加,和查找恰好被覆盖 n n n次的点(覆盖最多的点)的个数。

线段树+懒标记。

时间复杂度 O ( n ∗ log ⁡ 2 ( n ) ) O(n*\log_2(n)) O(nlog2(n))

参考资料:https://codeforces.com/blog/entry/82643?#comment-696498

Solution 3(Sweep Line & Segment Tree)

By errorgorn

与MrGary的那个比较相似就是处理出所有颜色可以的左端点范围,然后用线段树找出来。
时间复杂度也是 O ( n ∗ log ⁡ 2 ( n ) ) O(n*\log_2(n)) O(nlog2(n))

参考资料:https://codeforces.com/blog/entry/82643?#comment-696298

Solution 4(Trit-wise)

By pikmike

维护三进制前缀和: s u m i = ∑ i = 1 n a i ∗ r a n d i sum_i=\sum_{i=1}^n a_i*rand_i sumi=i=1nairandi,其中用trit-wise(类似于 x o r xor xor)来表示, r a n d i rand_i randi是一个平均值。

可以发现如果一个数出现了 m m m = = =一个数出现了 m m o d    3 m\mod 3 mmod3次的值。

然后就比较像前面的neal的hash了。

时间复杂度 O ( n ∗ l o g 2 ( n ) ) O(n*log_2(n)) O(nlog2(n))

参考资料:https://codeforces.com/blog/entry/82673

总结:

这是一题不错的数据结构题,也可以帮助大家理解hash。
注:所有代码可以在参考资料中找到

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值