均衡操作2
小J面前有N桶水,每个桶装的水的体积不一样
现在小J希望让所有桶的水的体积变得一样
每次他会选择两个相邻的桶子, 将桶中的水都倒掉1个单位
问他至少倒掉多少水,使得所有桶的水一样多,如果达不到目的,输出-1
Format
Input
第一行给出数字T,代表数据的组数
对于每组数据,先给出N 下面一行给出N个数字,代表每个桶的水的体积
N<=1e5
体积<=1e9
Output
如题
Samples
输入数据 1
2
3
8 10 5
6
4 6 4 4 6 4
输出数据 1
14
16
Hint
第1次,将第2个与第3个桶子都倒掉2个单位的水
第2次,将第1个与第2个桶子都倒掉5个单位的水
Sol:我们先来看样例的操作过程
既然要让所有数字变得一样,那当然要找到最大的那个数字10,让10与5一起减少2,这样10就变成了8
与左边的8变成一样。于是变成
8 8 3
然后再将最左边两个数字8 8一起减少5,得到 3 3 3.
此时我们会发现,如果每次在要数列中找最大值来减,是个比较麻烦的事。
又发现,在整个操作中,只要最终达到目的,先减哪个,再减哪个,并不重要。。。。
于是仍以样例来说
8 10 5
我们的目标是让所有数字变成一样
于是对于10来说,它比左边的8大,于是10就要变小,而按题意,相邻的两个数字都要变
于是10就拉上右边的5一起变,变成
8 8 3
通过这样的变化,我们能使整个数列的第1个数字到第N-1数字,它们会变成一个不上升的数列(当然最理想的状态是前N-1个数字变得一样了)
接下来,我们可以将8 8 3倒过来得到3 8 8
再按上面的思路做一遍得到3 3 3
当然这个操作过程中还两个细节
1:
在做完第一遍操作后,整个数列必须是一个不上升的数列,否则是无解的。
例如
8 10 20
这个数据就是无解的。
2:在做第二遍的时候,必须保证最左边那个数字是不能为负数的
例如数据
6 10 3
如果让10与3一起减少4的话,则3会变成-1.
后面的操作就无法进行下去的。。。。。。。负数怎么减少啊!!!
总结:
1:这个题其实是一种步步逼近的方式
2:如果发现操作的先后顺序与最终结果没有关系 ,就不妨统统从左向右做。。。类似于NOIP那个经典题均分纸牌。
#include<bits/stdc++.h>
#define int long long
#define isdight(c) (c>='0'&&c<='9')
#define swap(a,b) a^=b^=a^=b
using namespace std;
int t,n,h[100005];
inline int read() //快读
{
int x=0,f=1;
char c=getchar();
while(!isdight(c))
f=(c^'-'?1:-1),c=getchar();
while(isdight(c))
x=(x<<1)+(x<<3)+c-'0',c=getchar();
return x*f;
}
int solve()
{
int ans=0;
if(n<2)
return 0; //无需改变
for(int j=1;j<=2;j++) //正序变化与倒序变化
{
for(int i=2;i<n;i++)
{
if(h[i]>h[i-1])
{
int differ=h[i]-h[i-1];
ans+=differ*2; //每次喂两袋
h[i+1]-=differ;
h[i]=h[i-1]; //同时变化
}
}
if(h[n]>h[n-1])
return -1; //无解
if(h[n]<0)
return -1; //无解
reverse(h+1,h+1+n); //反转
}
return ans;
}
signed main()
{
t=read();
while(t--)
{
n=read();
for(int i=1;i<=n;i++)
h[i]=read();
printf("%lld\n",solve());
}
return 0;
}

浙公网安备 33010602011771号