1614 - Hell on the Markets(贪心)

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;
}


你可能感兴趣的:(ACM,uva)