题目大意:给定n个数字序列,1<= ai <= i ;问如何确定次序列每个数的正负号,使得其和为0.
首先应该知道:如想满足题意,则原序列的和为偶数。
第二就是如何解读题中给定的元素的不等式。
我也是看了别人的报告才知道的。 就是1---sum[i]的每个数都可以使用这个序列的全部后者部分数的和组合而成。
使用数学归纳法可以证明。
这样我们就可以从n-1开始逆序的查找是否可以组合成sum/2即t.
算法是如果当前值大于t,则看下一个数,如果当前值小于t,t-当前值。。。。由上面的结论是这样最后肯定是能使得t=0的。
//
// main.cpp
// uva 1614 - Hell on the Markets
//
// Created by XD on 15/8/17.
// Copyright (c) 2015年 XD. All rights reserved.
//
#include <iostream>
#include <string>
#include <queue>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include<vector>
#include <string.h>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <cstdio>
#define ll long long
using namespace std ;
const int maxn = 100000+ 5 ;
int ans[maxn] ;
int n ;
struct num{
int pos , key ;
bool operator < (const num &n ) const{
return key < n.key ;
} ;
};
num a[maxn] ;
int vis[maxn] ;
bool judge(ll sum)
{
memset(vis, 0,sizeof(int) * n +5) ;
// sort(a, a + n ) ;
int t = n -1 ;
while (sum >0) {
if (sum -a[t].key >= 0 ) {
vis[a[t].pos]= 1 ;
sum -= a[t].key ;
}
t-- ;
}
return true ;
}
int main(int argc, const char * argv[]) {
ll sum = 0 ;
while (scanf("%d",&n)==1 ) {
sum = 0 ;
for (int i = 0;i < n ; i++) {
scanf("%d" ,&a[i].key) ;
a[i].pos = i ;
sum += a[i].key ;
}
if (sum%2 == 1) {
printf("No\n") ;
continue ;
}
else{
ll mid = sum/2 ;
if (judge(mid)) {
printf("Yes\n") ;
printf("%d" , vis[0]==0?1:-1) ;
for (int i =1; i < n; i++) {
printf(" %d",vis[i]==0?1:-1) ;
}
}
}
printf("\n") ;
}
return 0;
}