UVa 1614 奇怪的股市

https://vjudge.net/problem/UVA-1614

题意:输入一个长度为n的序列a,满足1<=ai<=i,要求确定每个数的正负号,使得所有数的总和为0。

思路:贪心部分的理论依据:前i个数可以凑出1~sum[i]的所有整数。

        数学归纳,n=1时成立,假设n=k之前所有项都成立,当n=k+1时。sum[k+1]=sum[k]+a[k+1]。
        只需证明能凑出sum[k]+1~sum[k+1]间的整数即可。设1≤p≤a[k+1],sum[k]+p=sum[k]+a[k+1]-(a[k+1]-p)。
        因为1≤a[i]≤i,易得sum[k]≥k,a[k+1]-p≤k。又因为已知前k个数可以凑出1~sum[k],所以一定可以凑出a[k+1]-p。
        所以只需从之前凑出sum[k]里面剪掉凑出a[k+1]-p的数就可以凑出sum[k]+p。所以从1~sum[k+1]都可以凑出。

        知道这个之后就很容易了,首先判断sum和是否是偶数,其次排序依次遍历即可。

 1 #include<iostream> 
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 const int maxn = 1e5 + 5;
 7 
 8 struct node
 9 {
10     int x;
11     int id;
12 }a[maxn];
13 
14 int ans[maxn];
15 
16 bool cmp(node a, node b)
17 {
18     return a.x > b.x;
19 }
20 
21 int main()
22 {
23     int n;
24     while (cin >> n)
25     {
26         long long sum = 0;
27         for (int i = 0; i < n; i++)
28         {
29             cin >> a[i].x;
30             a[i].id = i;
31             sum += a[i].x;
32         }
33         if (sum % 2)
34         {
35             cout << "No" << endl;
36             continue;
37         }
38         sum /= 2;
39         sort(a, a + n, cmp);
40         for (int i = 0; i < n; i++)
41         {
42             if (a[i].x <= sum)
43             {
44                 ans[a[i].id] = 1;
45                 sum -= a[i].x;
46             }
47             else ans[a[i].id] = -1;
48         }
49         cout << "Yes" << endl;
50         for (int i = 0; i < n-1; i++)
51             cout << ans[i] << " ";
52         cout << ans[n - 1] << endl;
53     }
54     return 0;
55 }
原文地址:https://www.cnblogs.com/zyb993963526/p/6357777.html