zoukankan      html  css  js  c++  java
  • UVa1614

    这道题是一道好题,我想了很久都没有想出合适的方案,这道题考了我们贪心(不确定)+数学推导(确定)的能力,看来我的数学逻辑以及推理能力还需要加强啊。

    题意不说,直接上思路:

    由于1<=ai<=i的条件,我们需要从这里入手求解,首先,我们需要证明什么时候优解,什么时候没解,解决这些再讨论怎么解的问题。

    结论:对于在1 <= a[i] <= i时, 前i个数一定可以凑出1~sum[i]的所有整数

    证明:数学归纳,n=1时成立,假设n=k之前所有项都成立,当n=k+1时。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。又因为已知前k个数可以凑出1~sum[k],所以一定可以凑出a[k+1]-p。
            所以只需从之前凑出sum[k]里面剪掉凑出a[k+1]-p的数就可以凑出sum[k]+p。所以从1~sum[k+1]都可以凑出。

    https://www.cnblogs.com/zyb993963526/p/6357777.html

    这个是从别人的博客上面找到的,这个大家自行理解,我就不说了。

    然后是如何求解的问题,下面是解决思路:

    我们把sum除2,然后就可以随便选了啊(从后往前选),只要a[i]的值小于当前sum值,我们就选了,赋值成1;否则赋值为-1;

    我看有的题解要排序,其实不需要,排序无非是从大到小取...我反正觉得意义不大...

    https://www.cnblogs.com/fzfn5049/p/7825185.html

    这个大家看一看,我看到这个部分时,会有疑惑,为什么这样能够求出解呢?到底需不需要排序呢?????

    经过思考后,我明白了这样解的正确性,并且知道不需要排序,为什么?

    下面是证明:

    当sum < a[i]时,我们不能够用sum = sum - a[i],目的也很简单(我们不能够得到负数,如果是负数,就不能保证得到的正负数的绝对值恰好是一半了),

    那么我们需要确定i之前(即1 - i-1)是否满足它们的和 >= sum,由于a[i] <= i, a[1]+a[2]+...+a[i-1]>=i-1, 如果sum<a[i]那么sum<i所以我们发现a[1]+a[2]+...+a[i-1]>=sum,

    类比最上面的结论(数学归纳的那部分)我们可以得到1 - i-1这部分一定能够组成sum,所以放心的继续向下查找。

    当sum>=a[i]时,我们让sum = sum-a[i],其实证明与sum<a[i]的那部分类似,在-a[i]之前sum一定<=a[1]+a[2]+...+a[i-1](想一想,为什么),所以两边同时减去a[i],

    自然也能够保证1 - i-1这部分一定能够组成sum-a[i],所以减完以后也放心的向下查找。

    下面是实现:

    // UVa 1614
    // 数学证明(贪心) 
    #include <cstdio> 
    #include <cstring> 
    #include <algorithm>
    using namespace std; 
    
    const int maxn = 100000 + 10; 
    int n, a[maxn], ans[maxn];  
    
    int main() { 
      while (scanf("%d", &n) == 1) {
        long long sum = 0; 
        for (int i = 0; i < n; ++i) {
          scanf("%d", &a[i]); 
          sum += a[i]; 
        }
        if (sum&1) {
          printf("No
    ");    
        } else {
          printf("Yes
    "); 
          memset(ans, 0, sizeof(ans));
          sum >>= 1;  
          for (int i = n-1; i >= 0; --i) 
            if (sum >= a[i]) {
              sum -= a[i]; 
              ans[i] = 1; 
            } 
          for (int i = 0; i < n; ++i) {
            if (ans[i] == 0) printf("1 "); 
            else printf("-1 ");   
          }
          printf("
    ");
        }
      }
      return 0;
    }
  • 相关阅读:
    GitHub 源码,Framework 框架
    转int啥啥啥的
    查看apk签名 和 keystore 的信息
    一次apk打开时报内存溢出错误,故写下内存溢出的各种原因和解决方法
    客户端传值里面包含URL特殊字符的应对方法
    Linux全硬盘搜索文件名是xxxxx的命令
    pythonmysql运行报错解决过程中遇到的其中一个报错解决文章来源
    linux查看硬盘占用情况
    Linux使用nginx反向代理。可实现域名指向特定端口
    Linux下使用yum安装软件命令
  • 原文地址:https://www.cnblogs.com/yifeiWa/p/11249887.html
Copyright © 2011-2022 走看看