Description:
题目大意:Gildong 有一个 n 个数字的数组,有两种操作:
- 给第 i 个和后面的所有数字加一
- 给第 i 个和后面的所有数字减一
他想要所有数字相等,要求我们可以改变任何一个数字的值,求 Gildong 操作的最小次数
解题思路:
算法标签:构造算法
显然,不需要对第一个元素有任何操作,因为所有元素的相对值都未发生改变。从第二个元素开始,需要操作 abs(a2 - a1) 次才能使得 a2 = a1,相同操作,Gildong 需要操作
∑
i
=
2
n
(
a
i
−
a
i
−
1
)
\sum_{i = 2}^{n}(a~i~ - a~i-1~)
∑i=2n(a i −a i−1 ) 次操作。
首先考虑开始和结束的元素,如果把 a1 设置成与 a2相等,那么自然减少 abs(a2 - a1) 次,如果把 an 设置成 an-1,那么自然减少 abs(an - an-1) 次 。
然后考虑中间元素,如果 ai-1 < ai < ai+1 或者 ai-1 > ai > ai+1 ,显然这种情况 Gildong 自己操作次数就是最小的。当 ai-1 > ai < ai+1 或者 ai-1 < ai > ai+1 都会造成多余的操作,所以我们减少的最大次数就是 abs(ai - ai-1) + abs(ai - ai-1) - abs(ai+1 - ai-1)
用
∑
i
=
2
n
(
a
i
−
a
i
−
1
)
\sum_{i = 2}^{n}(a~i~ - a~i-1~)
∑i=2n(a i −a i−1 ) - max(abs(ai - ai-1) + abs(ai - ai-1) - abs(ai+1 - ai-1))就是 Gildong 所需要操作的次数。
代码:
// TSWorld
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <map>
#include <stack>
#include <cmath>
using namespace std;
const int N = 200005;
int main()
{
int a[N] = {0};
int n = 0,T = 0;
long long tot = 0;
int decrease = 0;
cin>>T;
while(T--) {
tot = 0,decrease = 0;
scanf("%d",&n);
for(int i = 1;i <= n;i++)
scanf("%d",&a[i]);
for(int i = 2;i <= n;i++)
tot += abs(a[i] - a[i-1]);
decrease = max(abs(a[2] - a[1]),abs(a[n] - a[n-1]));
for(int i = 2;i < n;i++)
decrease = max(decrease,abs(a[i]-a[i-1]) + abs(a[i+1]-a[i]) - abs(a[i+1]-a[i-1]));
cout<<tot - decrease<<endl;
}
return 0;
}