均衡操作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;
}

  

posted @ 2022-09-11 12:02  我微笑不代表我快乐  阅读(79)  评论(0编辑  收藏  举报