题干在此:
农夫做完操作数后,满足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)复杂度
思路大体讲完了
码子甩各位脸上:
如果觉得不错请点一个免费的赞吧 这对我有很大帮助 谢谢!(´。• ω •。`)