链接:
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 }