• UVa 1614 Hell on the Markets (贪心+推理)


    题意:给定一个长度为 n 的序列,满足 1 <= ai <= i,要求确实每一个的符号,使得它们和为0.

    析:首先这一个贪心的题目,再首先不是我想出来的,是我猜的,但并不知道为什么,然后在网上搜了一下题解,是什么数学归纳法。。。。。。

    贪心策略:1~i的和或者部分和一定能凑出来1~sum[i]。

    利用这个策略,也就是说,只要最后和是偶数,那么就一定有解,那这个解怎么求呢??我们先把所有的数从大到小排序,然后逆向计算,如果前 i-1 项和大于0,

    那么就减掉第 i 项,否则就加上第 i 项,这样的话,最后的和肯定是0.是我猜,但是AC了。

    下面是证明过程,利用的是数学归纳法,当 i = 1时,成立,当 i = k时,假设成立,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。所以一定可以凑出 a[k+1] - p。

    所以只需从之前凑出sum[k]里面剪掉凑出a[k+1]-p的数就可以凑 出sum[k]+p。所以从1~sum[k+1]都可以凑出。

    代码如下:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    
    using namespace std;
    const int maxn = 1E5 + 5;
    struct node{
        int id, num, ans;
    };
    node a[maxn];
    
    bool cmp1(const node &p, const node &q){
        return p.id < q.id;
    }
    
    bool cmp2(const node &p, const node &q){
        return p.num > q.num;
    }
    
    int main(){
        int n;
        while(scanf("%d", &n) == 1){
            int s = 0;
            for(int i = 0; i < n; ++i){  scanf("%d", &a[i].num); a[i].id = i;   s += a[i].num; }
            if(s & 1){  puts("No");  continue;  }
            else  puts("Yes");
    
            s = 0;
            sort(a, a+n, cmp2);
            for(int i = 0; i < n; ++i)
                if(s > 0){  s -= a[i].num;  a[i].ans = -1; }
                else {  s += a[i].num;  a[i].ans = 1;  }
    
            sort(a, a+n, cmp1);
            printf("%d", a[0].ans);
            for(int i = 1; i < n; ++i)  printf(" %d", a[i].ans);
            printf("
    ");
        }
        return 0;
    }
    
  • 相关阅读:
    CISCO一些基本配置
    每日学习
    每日学习(个人作业2)
    每日学习
    团队冲刺第十四天
    每日学习
    团队冲刺第十三天
    每日学习
    团队冲刺第十二天
    2021.5.26
  • 原文地址:https://www.cnblogs.com/dwtfukgv/p/5607687.html
Copyright © 2020-2023  润新知