zoukankan      html  css  js  c++  java
  • poj 2229 Sumsets(类似于n的m划分)

    传送门

    题意

      将一个数N分解为2的幂之和共有几种分法?

    题解

      定义dp[ i ]为 i 的分解方案数。

      初始化dp[0] = 2= 1;

      状态转移方程为:

      for i : 1 to N

        若 i 为偶数,则dp[ i ] = dp[ i / 2] + dp[i – 1] ;

        否则dp[i] = dp[ i – 1];

    对状态转移方程的理解:

      打个表先~~~~

      i  i 的分解方案

      1......1

      2......1+1,2

      3......1+1+1,2+1

      4......(2+1+1),(1+1+1+1),(2+2),(4)

      5......2+1+1+1,1+1+1+1+1,2+2+1,4+1

      6......2+1+1+1+1,1+1+1+1+1+1,2+2+1+1,4+1+1,2+2+2,4+2

      7......(2+1+1+1+1+1),(1+1+1+1+1+1+1),(2+2+1+1+1),(4+1+1+1),(2+2+2),(4+2+1)

      8......(2+1+1+1+1+1+1),(1+1+1+1+1+1+1+1),(2+2+1+1+1+1),(4+1+1+1+1),(2+2+2),(4+2+1+1),(4+2+2),(2+2+2+2),(4+4),(8)

      以8的为例,dp[8]=dp[20+7]+dp[2* 4];

      8分解成2的幂之和,只能分解成2, 2, 2, 23之间的加和。

      如果分解方案中含有20,并且不能出现重复,那可以考虑7的分解方案中的每个方案都+1 <=> 8的含20的分解方案总数(对应表中橘色部分);

      因为dp[7]中的分解方案数是不重复的,所以每个方案数+1也是不重复的;

      那,如何使分解方案中不含有20呢?

      想一下4的分解方案数是怎么得到的?

      4分解成2的幂之,只能分解成2, 2, 22之间的加和;

      如果4中的每个方案都 ×2,那不就正好变成8的分解方案中只不含有20的分解方案了吗(对应表中蓝色部分)?

      如果 i 为奇数,就不能通过某数 ×2 来得到 i;

      那也就是说只能通过 (i-1) 方案中每个方案+1 得到 i 的所有分解方案,故dp[ i ]=dp[ i-1]

    •Code

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 const int MOD=1e9;
     5 const int maxn=1e6+10;
     6 
     7 int N;
     8 int dp[maxn];
     9 
    10 int main()
    11 {
    12     scanf("%d",&N);
    13     dp[0] = 1; // 2^0
    14     for(int i=1;i <= N;++i)
    15     {
    16         if ((i & 0x1) == 0)//判断i是否为偶数
    17             dp[i]=dp[ i / 2]; //将i/2的每个构成数乘以2,得到 i
    18         dp[i] += dp[i - 1]; //将i-1的构成数拿过来加一
    19         dp[i] %= MOD;
    20     }
    21     printf("%d
    ",dp[N]);
    22     return 0;
    23 }
    View Code

    分割线:2019.6.16

    •类比“n的m划分”

    重新理解了一下“n的m划分”这种题的求解方法,想到了这道题;

    感觉这道题和n的m划分很像;

    n的m划分在状态转移时考虑的是“划分数种是否包含0这个元素”;

    而在此题中,考虑的是“是否包含20这个元素”;

    这应该是有两者的性质决定的,前者需要的是任意数的累加,后者需要的是2的幂的累加;

    而任意数中的最小值为0,2的幂的最小值为20=1;

    根据最小值的不同,考虑的不包含的数也不同;

    此题中,数 i 的划分可分为两类:

    ①包含20

    ②不包含20

    包含 2很好办,直接将 i-1 的划分 +1 便可得到 i 的划分中包含 20 的划分方案数;

    主要是不包含20要如何求解?

    与n的m划分相仿,如果 i 为偶数,那么将 i/2 中划分 ×2 得到的就是 i 的划分不包含 20 的划分方案数;

    根据上述讲解定义dp[ i ]表示 i 的划分方案数;

    那么 dp[ i ]=dp[ i ]-1 + ( i为偶数 ? dp[ i/2 ] : 0);

    dp[ 1 ] = 1;

    Code

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 #define ll long long
     5 const int maxn=1e6+50;
     6 const ll MOD=1e9;
     7 
     8 int n;
     9 ll dp[maxn];
    10 
    11 ll Solve()
    12 {
    13     dp[1]=1;
    14     for(int i=2;i <= n;++i)
    15     {
    16         dp[i]=dp[i-1];
    17         if(!(i&1))
    18             dp[i] += dp[i>>1];
    19         dp[i] %= MOD;
    20     }
    21     return dp[n]%MOD;
    22 }
    23 int main()
    24 {
    25     scanf("%d",&n);
    26     printf("%lld
    ",Solve());
    27     return 0;
    28 }
    View Code
  • 相关阅读:
    寒假每日总结——2020.2.1
    亿级用户下的新浪微博平台架构读后感
    京东话费充值系统架构演讲读后感
    京东物流系统架构演讲中的最佳实践读后感
    京东上千页面搭建基石——CMS前后端分离演讲史读后感
    数据蜂巢架构演讲之路读后感
    关于SOA架构设计的案例分析下
    京东虚拟业务多维订单系统架构设计读后感
    在VUE-CLI 3下的第一个Element-ui项目(菜鸟专用)
    在vue-cli3中优雅的使用 icon
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/9931448.html
Copyright © 2011-2022 走看看