UVa 1614

链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4489

题意:

输入一个长度为n(n≤100000)的序列a,满足1≤ai≤i,要求确定每个数的正负号,使得所有数的总和为0。
例如a={1, 2, 3, 4},则设4个数的符号分别是1, -1, -1, 1即可(1-2-3+4=0),但如果a={1, 2, 3, 3},则无解(输出No)。

分析:

首先证明一个结论:所给的数可以凑出1~sum[n]之间的所有数。
当n = 1时结论成立,设当n = k时结论成立,则当n = k+1时,只需证明sum[k]+1 ~ sum[k+1]之间的所有数都可凑出。
设1≤x≤a[k+1],则sum[k]+x = sum[k]+a[k+1] - (a[k+1]-x)。因为x可由a[1]~a[k+1]凑出,所以0≤a[k+1]-x≤a[k+1]-1。
即所给的数可以凑出1~sum[n]之间的所有数。
知道了这个结论之后,贪心一下就好。

代码:

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 const int UP = 100000 + 5;
 6 struct NODE {
 7     int v, o, r; //值,编号,结果
 8     bool operator < (const NODE& that) const {
 9         return o < that.o;
10     }
11 } a[UP];
12 
13 bool cmp(const NODE& f, const NODE& b){
14     return f.v > b.v;
15 }
16 
17 int main(){
18     int n;
19     for(int i = 0; i < UP; i++) a[i].o = i;
20     while(~scanf("%d", &n)){
21         long long sum = 0;
22         for(int i = 0; i < n; i++) scanf("%d", &a[i].v), sum += a[i].v;
23 
24         if(sum % 2 != 0){
25             printf("No
");
26             continue;
27         }
28 
29         sum /= 2;
30         sort(a, a + n, cmp);
31         for(int i = 0; i < n; i++){
32             if(sum - a[i].v < 0) a[i].r = -1;
33             else sum -= a[i].v, a[i].r = 1;
34         }
35         sort(a, a + n);
36         printf("Yes
%d", a[0].r);
37         for(int i = 1; i < n; i++) printf(" %d", a[i].r);
38         printf("
");
39     }
40     return 0;
41 }
原文地址:https://www.cnblogs.com/hkxy125/p/8453876.html