关于acwing 农夫约翰最喜欢的操作的做题记录

题干在此:

农夫做完操作数后,满足ai-x均可被M整除,求最少的操作数

说人话就是:求最少的操作数,使得ai被m取模之后是x

那么这个问题就转化成了“货舱选址”问题  

如下:

那么先将所有的ai对m取模求出原本的模数 这些模数经过多少次操作(+1 -1)能变成x 而这个x取出来要使这个操作数最小

就等于这个"货舱选址"问题中货舱放在哪 使得所有的商店到货舱的距离之和最小

那么如何选择货舱使得使得所有的商店到货舱的距离之和最小呢? 这个其实就是中位数定理 自己可数学归纳或者百度 货舱只要放在所有商店的中位数上 那么距离之和就是最小的。

---------------------------------------------------------------------------------------------------------------------------------

同理 这个农夫问题就是求如何放置x 使得所有的ai%m到x的总距离最小(因为每次的操作数都是1,故这里叫做距离)

但我们发现有两种操作可以使ai%m到x  比方说:(ai=8 m=7 x=5)这里可以通过对ai+4/对ai-3  那么明显就是减的那个操作数使用次数更少更优

这题的难点就在这里 。想要求商店到货舱的距离只有一种方法,那就是大减小。ai%m要想求到x的“距离”有两种方法 一种是+1 一种是-1。所以我们将所有的ai%m都放在一个长度为m的环上,此时环上所有的数都可以作为中位数,任选一个点为x,过x和圆心做一个穿过整个圆的直线,在直线右边的点都通过+1来到达x 而左边的模数都通过-1来到达x。

于是破环成链,将n个ai%m存在数组中,再将n个ai%m拷贝到后面n~2n个空位(这里加上偏移量m就表示 这里的ai%m是通过-1操作到达x的)

那么通过破链成环,我们成功避免了在环中遍历x后直接求“距离”,如果在环中直接求距离,你很难知道过x和圆点的那个直线与圆相交在哪个点(即以哪个点开始往左是-1操作 往右是+1操作)。

如果不知道的话,在x已经选定的情况下,你随便取那个点往左是- 往右是+不一定是此情况下到x距离和的最小

注意我们这里求的是:在所有已经选定的x中的,每个已定x都有一个最小操作数,求的是这些所有最小值中的最小值

也就是避免了分类讨论,使得每次遍历不用分类讨论就能求出第一层最小值

---------------------------------------------------------------------------------------------------------------------------------

如果暴力来写的话,选n次区间,算完中位数还要遍历所有的点求距离总和那就是o(n*n)了 题目数据为5e5至少要o(nlogn)(为啥是o(nlogn)也是我这几天查csdn才知道的 xd)

所以我们要使用前缀和来进行优化,使得o(n*n)变成o(n)

这里的距离公式可以推导一下:

x左边区间:a[x]-a[i]+....+a[x]-a[x-1]==(x-i)*a[x]-(a[i]+...+a[x-1])

x右边区间:a[i+n-1]-a[x]+....+a[x+1]-a[x]==(a[x+1]+...+a[i+n-2])-(i+n-1-p)*a[p]

那么加起来就是第一级最小数了,这也是为什么代码中求出这个第一级最小数,下面还要再比出第二级最小数。然后现在有小朋友可能就要问了XD:如果x点刚好有点捏??为啥公式不算进去??其实啊 在x上的点根本不需要操作数,"距离"就是0,就不要管这个边界问题了。

那么看公式我们发现:我标红的这些数组合是不是很熟悉,如果我们遍历相加是O(n),可是用前缀和优化后,计算这部分的和就是o(1)复杂度

思路大体讲完了

码子甩各位脸上:

如果觉得不错请点一个免费的赞吧 这对我有很大帮助 谢谢!(´。• ω •。`)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值