uva 1614 Hell on the Markets

题目大意:给定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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值