原题链接: 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[i−1]+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代码
/*
*邮箱:unique_powerhouse@qq.com
*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;
}