Ducati做题题集

List

Easy Problem

C F 840 D \color {blue} {CF840D} CF840D
C F 1422 D \color {green} {CF1422D} CF1422D
P 2048 \color {blue} {P2048} P2048
P 5283 \color {purple} {P5283} P5283

Good Problem

P 2303 \color {blue} {P2303} P2303
P 4768 \color {blue} {P4768} P4768
C F 1416 D \color {blue} {CF1416D} CF1416D
P 5025 \color {purple} {P5025} P5025

Tips

CF804D

考虑主席树。

每次询问执行主席树上扫描即可。假设本题询问的区间是 [ L , R ] [L,R] [L,R],当前扫到的值域区间 [ l , r ] [l,r] [l,r]。如果左子区间的数在 [ L , R ] [L,R] [L,R]中出现的次数之和超过了 R − L + 1 k \frac {R-L+1} k kRL+1,那么搜索左区间,否则搜索右区间;如果都没超过直接返回。

考虑这么做的时间复杂度是多少。不难发现,对于主席树上的每一层至多只有 k k k个位置被扫描到并继续向下进行搜索;所以总时间复杂度是 O ( n k log ⁡ n ) O(nk \log n) O(nklogn)的。

P2303

通过欧拉反演,不难得到答案为 s u m d ∣ n φ ( i ) n i sum_{d|n} \varphi(i) {\frac n i} sumdnφ(i)in

直接枚举因数是 O ( n ) O(\sqrt n) O(n )的,但是单次计算欧拉函数的代价之和很高。并且这个式子不能使用杜教筛来优化。

参考一下根号分治的思想我们不难得到正解。我们通过线性筛求出所有不超过 l i m lim lim的数的 φ \varphi φ值。我们找到所有 n n n的约数 p i p_i pi,如果 p i p_i pi的值不超过 l i m lim lim直接调用,否则暴力在根号复杂度内计算 φ \varphi φ

l i m lim lim取到 n 0.72 n^{0.72} n0.72的时候可以通过。

CF1422D

考虑规划一条路径为“从一个闪现点到另一个闪现点”,不难发现两点 ( a , b ) ( c , d ) (a,b)(c,d) (a,b)(c,d)之间的路径距离为 m i n ( ∣ a − c ∣ , ∣ b − d ∣ ) min(|a-c|,|b-d|) min(ac,bd)

但是,如果我们枚举所有的点对并连边的话时间复杂度,并跑最短路的时间复杂度为 O ( n 2 ) O(n^2) O(n2)。我们需要优化这个算法。

首先,我们对模型进行一步转化。两点 ( a , b ) ( c , d ) (a,b)(c,d) (a,b)(c,d)之间我们可以连两条边,边权分别是 ∣ a − c ∣ |a-c| ac ∣ b − d ∣ |b-d| bd,这样就将两点之间的边权式子给简化了。同时,我们发现,对于满足横坐标分别为 x 1 , x 2 , x 3 x_1,x_2,x_3 x1,x2,x3 1 , 2 , 3 1,2,3 1,2,3号点, 1 1 1 2 2 2的距离为 x 2 − x 1 x_2-x_1 x2x1 2 2 2 3 3 3的距离为 x 3 − x 2 x_3-x_2 x3x2,而 1 1 1 3 3 3的距离是 1 1 1 2 2 2的距离与 2 2 2 3 3 3的距离之和!所以,我们根本不用连接 1 1 1 3 3 3号点。扩展到多个点的情况,我们只需要将横坐标排序并将相邻两个点做连边操作,再对纵坐标排序并将相邻两个点做连边操作即可。

由于边数为 2 ( n − 1 ) 2(n-1) 2(n1),点数为 n n n,所以跑最短路的复杂度是 O ( n log ⁡ n ) O(n \log n) O(nlogn),可以通过。

P4786

NOI 2018 D1T1竟然是个裸题,NOI 2020 D1T1也是

首先,可爱的Yazid一定是开车到达某个节点 r t rt rt并下车之后步行到终点。

我们建出关于海拔的Kruskal重构树。注意建立的应该是最大生成树而非最小生成树。根据此时重构树的小根堆性质,此时两个点能够互相到达当且仅当它们的LCA的点权大于 p p p

此时我们先考虑一个暴力做法: 在Kruskal重构树上枚举这个LCA,要求这个LCA的点权必须大于 p p p;对于所有满足要求的LCA,与 v v v异子树的叶节点的 d i s dis dis值的最小值即是答案。这里一个节点的 d i s dis dis表示它与 1 1 1号节点的最短路径长度。

考虑如何优化这个暴力。首先, d i s dis dis要用Dijkstra预处理出来 ① ^{①} 。然后,我们处理出每一个子树内的所有叶节点的 d i s dis dis的最小值。对于每次询问,我们直接倍增即可求出答案。

时间复杂度为 O ( T × n log ⁡ n ) O(T×n \log n) O(T×nlogn)

①: 这句话是有深意的。这道题是OI历史上的一个里程碑——SPFA的死去。特加这一个注释,悼念已经离我们而去的SPFA算法。事实上,SPFA并没有完全死去,在Johnsen全源最短路、差分约束、负环判定以及一些极其难卡掉(如一些神奇的费用流建图题)或者数据完全随机的题目中有复杂度为线性,有重要的作用。

CF1416D

考虑给每条边一个边权,表示它在什么时候被删去。特别的,对于那些一直没有被删去的边,令它的权值为 q + 1 q+1 q+1

然后我们正序扫描一遍所有询问。不难发现第 i i i次询问的答案为: 从 u u u开始只经过权值不超过 i i i的边所能到达的节点的最大点权,并将这个点的点权赋为 0 0 0

是不是很熟悉这个模型?我们可以建立出一个关于边权的Kruskal重构树。每次查询的符合要求的节点均在一个子树中,这个子树的根可以倍增找到;找到之后,我们需要查询最小值并动态修改,可以采用dfs序+线段树来维护。

时间复杂度 O ( ( n + m ) log ⁡ n ) O((n+m) \log n) O((n+m)logn),比LCT不知道可爱到哪里去了。

P5025

套路题。

首先考虑暴力做法。先 O ( n 2 ) O(n^2) O(n2)建图,然后缩点并执行一次拓扑排序( d p dp dp)。

考虑如何优化。不难发现这个连边有一个性质: 每个节点连向的点都在一个区间中。所以可以采用线段树来优化这个建图。线段树优化的建图同样可以缩点,只不过每个点本身都有一个权值。

我们可以通过二分找到每次连边的区间 [ l , r ] [l,r] [l,r]。时间复杂度为 O ( n log ⁡ n ) O(n \log n) O(nlogn)

P2048

大套路题,然而我不会。

p r e i = ∑ j = 1 i a j pre_i=\sum_{j=1}^i a_j prei=j=1iaj,那么不难得到 ∑ i = l r a i = p r e r − p r e l − 1 \sum_{i=l}^r a_i=pre_r-pre_{l-1} i=lrai=prerprel1。于是我们将题目做一个转化——在序列中选 k k k对差在 l l l r r r之间的数,可以多次重复选择同一个数,使得每一对数的后者的 p r e pre pre减去前者的 p r e pre pre之和最大。

我们维护许多五元组 ( l , x , y , p o s , v a l ) (l,x,y,pos,val) (l,x,y,pos,val),表示选取的第一个位置 l l l,第二个位置在 [ x , y ] [x,y] [x,y]区间中;满足 p r e p o s − p r e l pre_{pos}-pre_{l} preposprel最大的位置为 p o s pos pos且这个最大值为 v a l val val

我们将这些五元组扔进一个大根堆中。每次我们取出堆顶,并将这个区间拆分为两个形如 ( l , x , p o s − 1 , p o s ′ , v a l ′ ) (l,x,pos-1,pos',val') (l,x,pos1,pos,val)的子五元组,分别重新计算这两个子区间的 p o s ′ pos' pos v a l ′ val' val

采用RMQ来快速计算即可,时间复杂度为 O ( n log ⁡ n + k log ⁡ n ) O(n \log n+k \log n) O(nlogn+klogn)

异或粽子这题只需要将RMQ求区间最大值改为可持久化Trie树上查询,时间复杂度为 O ( n log ⁡ m + k log ⁡ n log ⁡ m ) O(n \log m+k \log n \log m) O(nlogm+klognlogm),其中 m m m为所有 a i a_i ai的最大值。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值