n很大,不能DP,令我不得不想到了贪心,结果贪心完了莫名其妙的AC。。
之后查找该题的证明,发现网上题解都不求甚解,只有一个博客给出了一个说法: 因为 1 <= a[i] <= i,可用数学归纳法证明,用 a[1]~a[i] 的部分或全部元素通过求和,一定可以凑出 1~sum[i] 的每个整数(sum[i]是前 i 个元素的和)
的确,1 <= a[i] <= i是个奇怪的限制条件,大家不妨记住这个奇妙的结论, 如果我以后得到证明方法会再回来补充 。
有了这个结论, 我们就可以贪心的寻找答案了,从大到小排序,如果加上当前值cur += a[k]超过了sum/2 ,那么说明这个值不对,而且这个值比sum/2 - cur大,那么按照我们上面的结论,大可以不要这个数, 因为剩下的数一定可以凑出sum/2 - cur 。
细节参见代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 100000 + 10; int n,vis[maxn]; struct point{ int id,v,ans; }a[maxn]; bool cmp1(point a,point b) { return a.v > b.v; } bool cmp2(point a, point b) { return a.id < b.id; } int main() { while(~scanf("%d",&n)) { ll sum = 0; for(int i=0;i<n;i++) { scanf("%d",&a[i].v); a[i].id = i; sum += a[i].v; } bool ok=false ; if(sum%2 == 0) ok = true; if(ok) { ok = false; sort(a,a+n,cmp1); ll cur = 0; int i; for(i=0;i<n;i++) { cur += a[i].v; if(cur == sum/2) { a[i].ans = 1; ok = true; break; } else if(cur > sum/2) { cur-=a[i].v; a[i].ans = -1; } else a[i].ans = 1; } for(i=i+1;i<n;i++) a[i].ans = -1; } if(ok) { printf("Yes\n"); sort(a,a+n,cmp2); printf("%d",a[0].ans); for(int i=1;i<n;i++) printf(" %d",a[i].ans); printf("\n"); } else printf("No\n"); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
1614 - Hell on the Markets(贪心)
原文地址:http://blog.csdn.net/weizhuwyzc000/article/details/47084259