zoukankan      html  css  js  c++  java
  • uva 1614奇怪的股市(归纳法证明,贪心)

    uva 1614奇怪的股市(归纳法证明,贪心)

    输入一个长度为n的序列a,满足(1le a_ile i),要求确定每个数的正负号,使得所有数的总和为0.例如a={1, 2, 3, 4},则4个数的符号分别是1, -1, -1, 1即可。但若a={1, 2, 3, 3},则无解。n<=1e5。

    这道题相当于要找到两堆相等的数。若序列中数的总和为奇数,那么拆出来的两堆数无论如何都不可能相等,所以无解。由于这道题的特殊性质,可用归纳法证明总和为偶数时一定有解。

    现在要证明,用前i个数的全部或部分可以凑出0到sum[i]的所有整数。n=1时这是成立的。假设n=k之前所有项都成立,那么(sum[k+1]=sum[k]+a[k+1])。只需证明能凑出(sum[k]+1)(sum[k]+a[k+1])的所有整数即可。由于(1le a_[k+1]le k+1),而(sum[k]ge k),所以(sum[k]+p=x+a[k+1] (1le ple a[k+1],0le xle sum[k]))恒成立。

    这样一来,就证明了用前n个数,可以凑出sum[n]/2。当sum[n]是偶数时,另一半也就是sum[n]/2。现在的问题就是找出和等于sum[n]/2的数。直接将a数组从大到小排序,然后贪心的取即可。

    为什么贪心的取是正确的呢?因为(1le a_ile i),排序完的数组必定也满足这个条件。所以只要贪心的取显然有解。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    const int maxn=1e5+5;
    struct node{
        int data, id;
    }a[maxn];
    int n, chose[maxn];
    long long sum;
    
    bool cmp1(node &x, node &y){
       return x.data>y.data; }
    
    //100万才需要读优
    int main(){
        while (~scanf("%d", &n)){
            sum=0;
            for (int i=0; i<n; ++i){
                scanf("%d", &a[i].data);
                sum+=a[i].data; a[i].id=i;
            }
            if (sum&1){
                puts("No"); continue; }
            else sum>>=1;
            sort(a, a+n, cmp1);
            for (int i=0; i<n; ++i)
                if (a[i].data<=sum){
                    sum-=a[i].data;
                    chose[a[i].id]=1;
                } else chose[a[i].id]=-1;
            puts("Yes");
            for (int i=0; i<n; ++i)
                printf("%d ", chose[i]);
            puts("");
        }
        return 0;
    }
    
  • 相关阅读:
    第一次作业 —— 【作业7】问卷调查
    讲座观后感
    学习进度表(随缘更新)
    数据结构与算法思维导图
    作业七问卷调查
    《创新者的逆袭,用第一性原理做颠覆式创新》读后感
    结对项目--四则运算生成器(Java) 刘彦享+龙俊健
    个人项目---WordCount实现(Java)
    自我介绍+软工五问
    简洁又快速地处理集合——Java8 Stream(下)
  • 原文地址:https://www.cnblogs.com/MyNameIsPc/p/8495362.html
Copyright © 2011-2022 走看看