1614 - Hell on the Markets(贪心)

来源:互联网 发布:杀手 知乎 编辑:程序博客网 时间:2024/05/23 19:19

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


1 0
原创粉丝点击