A. Avoiding Zero(前缀和+贪心)Codeforces Global Round 11

原题链接: https://codeforces.com/contest/1427/problem/A

在这里插入图片描述
测试样例

input
4
4
1 -2 3 -4
3
0 0 0
5
1 -1 1 -1 1
6
40 -31 -9 0 13 -40
output
YES
1 -2 3 -4
NO
YES
1 1 -1 1 -1
YES
-40 13 40 0 -9 -31

Note

Explanation of the first testcase: An array with the desired properties is b=[1,−2,3,−4]. For this array, it holds:

  • The first element of b is 1.
  • The sum of the first two elements of b is −1.
  • The sum of the first three elements of b is 2.
    The sum of the first four elements of b is −2.

Explanation of the second testcase: Since all values in a are 0, any rearrangement b of a will have all elements equal to 0 and therefore it clearly cannot satisfy the second property described in the statement (for example because b1=0). Hence in this case the answer is NO.

Explanation of the third testcase: An array with the desired properties is b=[1,1,−1,1,−1]. For this array, it holds:

  • The first element of b is 1.
  • The sum of the first two elements of b is 2.
  • The sum of the first three elements of b is 1.
  • The sum of the first four elements of b is 2.
  • The sum of the first five elements of b is 1.

Explanation of the fourth testcase: An array with the desired properties is b=[−40,13,40,0,−9,−31]. For this array, it holds:

  • The first element of b is −40.
  • The sum of the first two elements of b is −27.
  • The sum of the first three elements of b is 13.
  • The sum of the first four elements of b is 13.
  • The sum of the first five elements of b is 4.
  • The sum of the first six elements of b is −27.

题意: 给你一个长度为 n n n的整数序列 a a a,现在需要你对该序列进行重新排列使得前缀和不为 0 0 0,若不存在这样的排列,则输出“NO“。

解题思路: 我们想要让所有的前缀和 p r e pre pre都不为 0 0 0,那么该如何进行处理呢?对于 p r e [ i ] pre[i] pre[i],它是等于 p r e [ i − 1 ] + a [ i ] pre[i-1]+a[i] pre[i1]+a[i]。所以每个前缀和其实和上一个前缀和有关系,换句话说,如果我用一个 a n s ans ans遍历一遍排列好的数组, a n s ans ans累加元素和。如果出现 a n s = 0 ans=0 ans=0,则说明不可行。 那么我们根据贪心原则,我们要使得 a n s ≠ 0 ans≠0 ans=0,我们要么现在前面一直放正数,然后再放负数,要么现在前面一直放负数,然后一直放正数。(注意: 0 0 0是可以放放中间任意位置的,都没有影响) 这个时候我们就发现一个奇妙的东西了。如果正数和等于负数和,那么是不可能的,因为长度为 n n n的前缀和一定为 0 0 0,那么其他的情况是否一定满足呢?答案是一定的,我们一定要使得前缀和不为 0 0 0,那么如果正数和大于负数和,那么我们先一直放正数,然后放 0 0 0,然后放负数,就相当于是递减排序,这样前缀和是永远大于0的。如果负数和大于正数和,那么我们先一直放负数,然后放 0 0 0,然后放正数,就相当于是递增排序,这样前缀和是永远小于0的。

AC代码

/*
*邮箱:[email protected]
*blog:https://me.csdn.net/hzf0701
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*
*/
#include<bits/stdc++.h>	//POJ不支持

#define rep(i,a,n) for (int i=a;i<=n;i++)//i为循环变量,a为初始值,n为界限值,递增
#define per(i,a,n) for (int i=a;i>=n;i--)//i为循环变量, a为初始值,n为界限值,递减。
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define fi first
#define se second
#define mp make_pair

using namespace std;

const int inf = 0x3f3f3f3f;//无穷大
const int maxn = 1e5;//最大值。
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll>  pll;
typedef pair<int, int> pii;
//*******************************分割线,以上为自定义代码模板***************************************//

int t,n;
int main(){
    
    
	//freopen("in.txt", "r", stdin);//提交的时候要注释掉
	IOS;
	while(cin>>t){
    
    
		while(t--){
    
    
			cin>>n;
			vector<int> num(n);
			int pos=0,neg=0;//pos统计正数和,neg统计负数和。一定要初始化。
			rep(i,0,n-1){
    
    
				cin>>num[i];
				if(num[i]>0){
    
    
					pos+=num[i];
				}
				else if(num[i]<0){
    
    
					neg+=num[i];
				}
			}
			//目的使得前缀和不为0,故要么前面全是正数使得和最大,再用负数去减。要么前面全是负数使得和最小,再用正数去加。
			if(pos+neg==0){
    
    
				//这种必不可能,无论你怎么排列,长度为n的前缀和必为0.
				cout<<"NO"<<endl;
			}
			//那么其他就可行。
			else if(pos+neg>0){
    
    
				//说明正数和大,先放正数,再放负数,必满足,我们直接从大到小排列即可。
				sort(num.begin(),num.end(),greater<int>() );
				cout<<"YES"<<endl;
				rep(i,0,n-1){
    
    
					cout<<num[i]<<" ";
				}
				cout<<endl;
			}
			else{
    
    
				//说明负数和大,先放负数,再放正数,必满足,我们直接从小到大排列即可。
				sort(num.begin(),num.end());
				cout<<"YES"<<endl;
				rep(i,0,n-1){
    
    
					cout<<num[i]<<" ";
				}
				cout<<endl;
			}
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/hzf0701/article/details/109007379