94 lines
3.2 KiB
Markdown
94 lines
3.2 KiB
Markdown
|
|

|
|||
|
|
|
|||
|
|
### 解题思路
|
|||
|
|
|
|||
|
|
首先猜想最终相等的元素`t`的范围,最终应为数组中的某个元素。
|
|||
|
|
|
|||
|
|
* 若`t`小于数组中所有的元素,则此时增大`t`,那么所有元素变为`t`的次数将减小,可见`t`并非最优解;
|
|||
|
|
* 若`t`大于数组中所有的元素,则此时减小`t`,那么所有元素变为`t`的次数将减小,可见`t`并非最优解;
|
|||
|
|
|
|||
|
|
可见`t`应该位于数组最大与最小值之间,下面证明最优的`t`可以取为数组中的某个元素,从而遍历数组元素即可。
|
|||
|
|
|
|||
|
|
<center><img src='https://img-blog.csdnimg.cn/706d85a45dc54ccbba1c956734aa40e7.png'></center>
|
|||
|
|
|
|||
|
|
如上图所示,设t为数组最大与最小值之间的一个值,若`t`不为数组中的某个元素,则设此时大于`t`的元素有`x`个,小于t的元素为`y`个。
|
|||
|
|
若`x>y`,则上移一格`t`,此时操作数变化量为`-x+y<0`,将会更优;
|
|||
|
|
若`x<y`,则下移一格`t`,此时操作数变化量为`+x-y<0`,将会更优;
|
|||
|
|
若`x=y`,则无论上移与下移,操作数不变。
|
|||
|
|
因此,可以看出若`t`不取数组中的某个元素值,则总可以通过调整`t`,使得操作数更少。因此`t`应该取数组中的某个值。
|
|||
|
|
|
|||
|
|
则**问题转化**为:
|
|||
|
|
遍历数组中的数,找到某个元素`t`,使得`t`到其他元素值的距离之和最小。
|
|||
|
|
由**绝对值不等式**可知,当`t`取数组**中位数**时,该**距离之和最小**。
|
|||
|
|
|
|||
|
|
中位数+绝对值不等式 $AcWing$ $104$. [货仓选址](https://www.cnblogs.com/littlehb/p/15459501.html)
|
|||
|
|
|
|||
|
|
排序之后取中位数,中位数的性质,所有数到他的和是最小的。
|
|||
|
|
|
|||
|
|
```cpp {.line-numbers}
|
|||
|
|
#include <bits/stdc++.h>
|
|||
|
|
|
|||
|
|
using namespace std;
|
|||
|
|
const int INF = 0x3f3f3f3f;
|
|||
|
|
const int N = 1010;
|
|||
|
|
int a[N];
|
|||
|
|
int n, k;
|
|||
|
|
int res = INF;
|
|||
|
|
// 时间复杂度:10000*10000=1e8,C++一秒可过
|
|||
|
|
/**
|
|||
|
|
测试用例I:
|
|||
|
|
3 2
|
|||
|
|
3 6 1
|
|||
|
|
|
|||
|
|
答案
|
|||
|
|
3
|
|||
|
|
|
|||
|
|
测试用例II:
|
|||
|
|
4 2
|
|||
|
|
2 6 11 18
|
|||
|
|
|
|||
|
|
答案:
|
|||
|
|
4
|
|||
|
|
解释:
|
|||
|
|
将2调到6,需要4步。
|
|||
|
|
也可以把2调到3,1步。
|
|||
|
|
把6降到3,3步,共4步。
|
|||
|
|
|
|||
|
|
测试用例III:
|
|||
|
|
5 3
|
|||
|
|
2 6 11 18 14
|
|||
|
|
|
|||
|
|
答案:
|
|||
|
|
7
|
|||
|
|
解释:
|
|||
|
|
将11调到14,需要3步
|
|||
|
|
将18调到14,需要4步,共7步。
|
|||
|
|
|
|||
|
|
|
|||
|
|
测试用例IV
|
|||
|
|
5 3
|
|||
|
|
1 2 7 8 12
|
|||
|
|
答案:5
|
|||
|
|
解释:
|
|||
|
|
最终结果是8,
|
|||
|
|
7+1=8,1步
|
|||
|
|
8不需要动,0步
|
|||
|
|
12-8=4,4步
|
|||
|
|
共1+0+4=5步
|
|||
|
|
*/
|
|||
|
|
int main() {
|
|||
|
|
cin >> n >> k;
|
|||
|
|
for (int i = 0; i < n; i++) cin >> a[i];
|
|||
|
|
|
|||
|
|
for (int i = 0; i < n - k + 1; i++) { // 枚举起点
|
|||
|
|
vector<int> b;
|
|||
|
|
for (int j = i; j <= i + k - 1; j++) b.push_back(a[j]); // 将每个可用范围复制到数组b中
|
|||
|
|
sort(b.begin(), b.end()); // 排序
|
|||
|
|
int cnt = 0; // 变更次数
|
|||
|
|
for (int j = 0; j < b.size(); j++) cnt += abs(b[b.size() / 2] - b[j]); // 枚举每个数字与中位数对比
|
|||
|
|
res = min(res, cnt); // 记录最少变更次数
|
|||
|
|
}
|
|||
|
|
printf("%d\n", res);
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
```
|