Codeforces 题目集锦

我的CF账号:guozexin
如果题解有哪些疑惑的地方,可以直接在CF上找我的代码查看细节

1601A Array Elimination

这道题目乍一看很花哨,但和位运算有关的题目,手玩一下就可以把原题的操作换作一个很简单的操作。

本题中其实就是在同一位上选择k个1,使这k个1都变成0,若要使一位上的1都变成0,那这一位上1的个数需是k的倍数,所以我们对每一位上的1的个数取gcd,得到k,若k成立,则k的因数也一定成立,输出k的所有因数即可

1601B Frog Traveler※

青蛙爬井问题
在初学OI时也有一道这样的青蛙爬井的题目,当时a和b都是固定的,推出数学式子即可

而这道题的a和b都不固定,且向上爬的高度也不一定是a。可以想到最暴力的做法直接去bfs,找出爬出井的最短时刻,但显然由于向上爬的高度不确定,bfs的复杂度会极大

对于上述问题,有两种解决方法

用并查集来维护一下,将跳过的点和它上面的点合并在一起,因为这个点既然已经跳过,那之后再跳到这个点,答案一定会更劣,所以我们枚举向上跳的时候就可以跳过这个点,用并查集搞下来每个点只会访问一次,复杂度是O(n)的。
这个思路与前几天模拟赛中的一个扫雪的题思路很类似,也是通过并查集来优化掉冗余操作,从而使时间大大增加

另一种解决做法就是依然是正常的bfs,但在建图时用倍增或线段树来优化建图即可

这个题目的一个小trick:青蛙最后一个白天直接就跳出井了,而不会再往下掉,所以我们将今天白天与昨天晚上一起进行处理,而不是将今天白天与今天晚上一起处理

1601C Optimal Insertion※

考虑暴力的做法,用树状数组维护逆序对个数,把每一个b放到a中找它最合适的位置,复杂度为 O ( m n l o g ( n ) ) O(mnlog(n)) O(mnlog(n)),显然过不去

p i p_i pi表示 b i b_i bi a a a中的位置,即当 b i b_i bi恰好在 a j a_j aj之前时, p i = j p_i=j pi=j

存在一个性质,即将 b b b从小到大排序后, p i p_i pi单调递增。证明的话考虑反证法,将两个 b b b调换顺序,答案显然会更劣

根据这个性质进行整体二分,先处理出 b m i d b_{mid} bmid的位置,即 p m i d p_{mid} pmid,然后将 b b b m i d mid mid处划分开,将值域也从 p m i d p_{mid} pmid处划分开,继续进行处理

这样即可高效的优化上述暴力过程,得到每一个 p i p_i pi后,构造出最终的序列 c c c,树状数组+离散化 求一下逆序对个数即可

总复杂度为 O ( ( n + m ) ∗ l o g ( n + m ) ) O((n+m)*log(n+m)) O((n+m)log(n+m))

看大部分神仙们这道题写的都是线段树做法,蒟蒻没读懂代码,只好啃官方英文题解

1601D Difficult Mountain

先将人按照 m a x ( a i , s i ) max(a_i,s_i) max(ai,si)从小到大排序。如果 m a x ( a i , s i ) max(a_i,s_i) max(ai,si)相等,则按 s i s_i si从小到大排序
证明:(来自洛谷题解 0htoAi)
在这里插入图片描述

1601E Phys Ed Online※

多个基础数据结构加起来就不基础了
这道题用到了一个类似于映射的思想吧
很容易通过题目归纳出我们要求的结果即为
∑ i = l + x k , l ≤ i ≤ r , x ∈ Z m i n l ≤ j ≤ i    a j \sum_{i=l+xk,l\leq i\leq r,x\in Z} min_{l\leq j\leq i}\;a_j i=l+xk,lir,xZminljiaj
那我们会发现,对于某一个询问,有一些 a i a_i ai是根本不可能作为答案的,例如要玩 6 6 6天,一张票能玩 2 2 2天,第 6 6 6天的票价无论再便宜,我都不可能在这一天去买票,因为已经没有价值了
所以,我们可以把右端点收缩到一个与左端点在模 k k k的意义下同余的一个数
r = l + k ⌊ r − l k ⌋ r=l+k\lfloor \frac{r-l}k \rfloor r=l+kkrl

预处理出一个 b b b数组, b i b_i bi表示 a i − k − a i a_{i-k}-a_i aikai中的最小值(利用单调队列求解)

再进行 d p dp dp d p i dp_i dpi表示 m i n ( b i ) + m i n ( b i , b i + k ) + m i n ( b i , b i + k , b i + 2 ∗ k ) + . . . + m i n ( b i , b i + k , . . . , b i + x k ) ( x ∈ Z , i + x k ≤ n ) min(b_i)+min(b_i,b_{i+k})+min(b_i,b_{i+k},b_{i+2*k})+...+min(b_i,b_{i+k},...,b_{i+xk})(x\in Z,i+xk\leq n) min(bi)+min(bi,bi+k)+min(bi,bi+k,bi+2k)+...+min(bi,bi+k,...,bi+xk)(xZ,i+xkn)

不难发现,这样其实是把所有数字分成了 k k k组,分别对这 k k k组进行 d p dp dp d p dp dp的过程可以这样倒序求解:
d p i = d p p o s + ( p o s − i ) ∗ b i ( p o s dp_i=dp_{pos}+(pos-i)*b_i(pos dpi=dppos+(posi)bi(pos为第一个在 i i i之后且 b p o s < b i b_{pos}<b_i bpos<bi的下标
至于怎么找右侧第一个小于 b i b_i bi的数,就是单调栈的基本操作了

总结一下我们最后的要求的答案,实际上就是 a l + m i n ( b l + k ) + m i n ( b l + k , b l + 2 ∗ k ) + . . . + m i n ( b l + k , . . . , b l + x k ) ( x ∈ Z , l + x k ≤ r ) a_l+min(b_{l+k})+min(b_{l+k},b_{l+2*k})+...+min(b_{l+k},...,b_{l+xk})(x\in Z,l+xk\leq r) al+min(bl+k)+min(bl+k,bl+2k)+...+min(bl+k,...,bl+xk)(xZ,l+xkr)

这下子就可以发挥 d p dp dp数组的作用了,我们可以利用一个后缀和的操作,来求解 a l a_l al后面的式子

但事情还没有这么简单,因为你在取 m i n min min,所以不可以简简单单的用后缀和来实现,那如果我取到一个在 [ L , R ] [L,R] [L,R]中最小的 b p o s b_{pos} bpos的位置呢,这样就可以进行求解了,答案即为 a l + d p l + k − d p p o s + ( R − p o s + k ) / k ∗ b p o s a_l+dp_{l+k}-dp_{pos}+(R-pos+k)/k*b_{pos} al+dpl+kdppos+(Rpos+k)/kbpos

而这个最小的位置怎么求呢,又到了ST表的基本操作了,和 d p dp dp数组求解过程一样,依然是把 k k k组分别拎出来求解,也就是我们可以做一个映射版的ST表,但尤其需要注意在映射过程中+k,*k,/k等一系列操作的实际含义

1601F Two Sorts※

折半搜索好题
根据折半搜索的思想,首先,我们必须会做出来O(1e6)的做法,也就是O(n)怎么做这个题,我们可以直接暴力dfs去按字典序搜索出每一个范围内的数字,算答案就行

将12位数拆成两半,对两半的六位分别进行上述的O(n)搜索,考虑存储信息与合并,我们可以先求出 a a a的逆排列 b b b数组
例如:
n = 12 n=12 n=12

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值