http://codeforces.com/contest/1453/problem/B
题意:通过对后缀数组的+1-1使数全部相等,开始前你可以直接修改一个数的值,问最小操作数
思路:
差分约束,先不考虑修改数。首先,获取相邻数的差我们设为Si(Si=a[i]-a[i-1],2<=i<=n),假设我们改的后缀数组从j(1<j<=n)开始,那么由于同时更改,j-n的数之间差不变,只改变了j-1和j的数的差,而最终状态我们要使所有的差归零,也就是说要的操作数就是所有差的绝对值之和。
现在考虑,改一个数:
改开头和结尾,可以使S2,Sn归零
改中间,位置设为j(1<j<n):Sj,S(j+1)同增同减:同号没影响;异号操作数减少绝对值小的一个数的两倍
(如-3 -5 -2 ,差是 -2 3,把-5改成-3,差变为0 1,操作数减少4)
最后答案减去改的数减小的操作数就行了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+10;
int a[N],sub[N];
int main() {
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
if(i>1)
sub[i]=a[i]-a[i-1];
}
ll x=0,y=0;
ll maxx=0;
for(int i=2;i<=n;i++){
if(sub[i]<0)x-=sub[i];
else y+=sub[i];
if(i!=n){
if((sub[i]>0&&sub[i+1]>0)||(sub[i]<0&&sub[i+1]<0))continue;
ll k=min(abs(sub[i]),abs(sub[i+1]));
if(k>maxx)maxx=k;
}
}
maxx=2*maxx;
if(abs(sub[n])>maxx)maxx=abs(sub[n]);
if(abs(sub[2])>maxx)maxx=abs(sub[2]);
// cout<<x<<" "<<y<<" "<<maxx<<endl;
cout<<x+y-maxx<<endl;
}
}