zoukankan      html  css  js  c++  java
  • Codeforces Round #529 (Div. 3) C. Powers Of Two(数学????)

    传送门

    •题意

      给出一个整数 n ,问能否将 n 分解成 k 个数之和,且这 k 个数必须是 2 的幂。

      如果可以,输出"YES",并打印出任意一组解,反之输出"NO";

    •题解

      预备知识补充:如何求出数 num 最少需要多少个 2的幂之和?

      例如 :

        num = 3 = 20+21至少需要两个

        num = 4 = 22 至少需要一个

        num = 17 = 24+20 至少需要两个

      根据贪心的思想 :

        令 2x ≤ num,求出最大的 x ,那么此时num可以表示为 num = 2x+num1 ( num1 = num-2x );

        num1接着重复上述过程,求出  ≤num1 的最近的2x1,num1 = 2x1+num2 ( num2 = num1-2x1 );

        那么num最少的2的幂之和就为 : 2x+2x1+2x2+.......;

      如何求出x,x1,x2,......呢?

            2x : ≤ num 的距num最近的2的幂

            2x1 : ≤ num1 的距num1最近的2的幂

            2x2 : ≤ num2 的距num2最近的2的幂

            2x3 : ≤ num3 的距num3最近的2的幂

      易得 : 

        (1) : num / 2x = oddNum , num / 2x1 = oddNum , num / 2x2 = oddNum ,......

        (2) : num / a = evenNum , num / b = evenNum , num / c = evenNum ,........

      (1)证明 :

        num / 2x = 1;

        num1 / 2x1 = 1 → (num-2x) / 2x1 = 1 → num / 2x1 - 2x / 2x1 = num / 2x1 - 2x-x1 = 1 → num / 2x1 = 1 + 2x-x1 = oddNum ( 奇+偶 );

        num2 / 2x2 = 1 → (num-2x-2x1) / 2x2 = 1 → num / 2x1 - 2x / 2x2- 2x1 / 2x2 = 1 → num / 2x1 = 1 + 2x-x2+2x1-x2 = oddNum ( 奇+偶+偶 );

        .................

      (2)证明 :

        num / a = (num1+2x) / a = num1 / a + 2x / a = 0+偶 = evenNum;( 2x1 ≤ num1 < a )

        ..................

      所以说:

    1 for i:0 to k
    2     if(num/(2^i)为奇数)
    3         那么2^i就为num最少需要的2的幂之和的成员之一

      并且,$2^i$ 等价于 两个 $2^{i-1}$,所以,可以通过 $2^i$ 转化为 $2^{i-1}$ 开填充;

    •Code

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 
     5 int n,k;
     6 int e[40];//e[i] : num需要e[i]个2^i
     7 
     8 void Solve()
     9 {
    10     int curK=0;
    11     for(int i=0;(1<<i) <= n;++i)
    12         if(n>>i&1)
    13         {
    14             e[i]=1;
    15             curK++;
    16         }
    17     //最少需要curK个2的幂
    18     if(k < curK || k > n)
    19     {
    20         printf("NO
    ");
    21         return ;
    22     }
    23     printf("YES
    ");
    24     for(int i=30;~i;--i)
    25     {
    26         if(!e[i])
    27             continue;
    28         if(curK == k)
    29             break;
    30         int x=min(e[i],k-curK);
    31         e[i] -= x;//减少x个2^i
    32         e[i-1] += 2*x;//增加2*x个2^(i-1)
    33         curK += x;//比之前多了x个
    34     }
    35     for(int i=0;i <= 30;++i)
    36         for(int j=0;j < e[i];++j)
    37             printf("%d ",1<<i);
    38 }
    39 int main()
    40 {
    41     scanf("%d%d",&n,&k);
    42     Solve();
    43     return 0;
    44 }
    View Code

    •感悟  

      其实,在比赛时,并没有做出这道题,不过也有点小想法,还不成熟;

      赛后看排名,无意间看到了hdu大神Claris的排名,然后,看了一下Claris的提交代码,哇,真简洁,

      是我目前无法达到的。

      大约花费了一个多小时的时间才理解了%%%%%%%%%%%%


    分割线2019.5.23

    重新温习了一下这道题;

    假设 n 最少由 k 个2的幂组成:

    n = 2x1 + 2x2 +.......+ 2xk

    那么 n / 2xi 为奇数;

    今天重新想了一下这个,没有像之前那么繁琐的推公式,一想就想到;

    如果 n / 2xi 为偶数,那么 2xi 可以变为 2xi+1 使得组成 n 这个幂值更大,那么,肯定比2xi所需的2的幂少,与假设矛盾;


    再次分割2019.10.24

      二进制思想;

      十进制数 n 对应的二进制的第 i 位如果为 1,那么 $2^i$ 就是二进制转十进制 n 的组成部分;

      那么,也即是说,n 对应的二进制有多少个 1,n 就至少需要多少个 2 的幂之和;

      如果这些不够 k 个,那么就通过一个 $2^i$ 可以转化为两个 $2^{i-1}$ 的形式来增加幂之和的个数; 

  • 相关阅读:
    Java类练习一则
    windows下安装Apache+PHP
    Java 数组/对象练习一则
    windows 安装 apache 报错解决
    延时任务机制
    Javashop电商系统-会员登录方式
    基于canvas商品海报生成源码分享
    uniapp引入微信小程序直播组件
    电商系统中库存的存储于扣减
    电商系统nuxt的中间件代码分享
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/10194775.html
Copyright © 2011-2022 走看看