1632 Sumsets【转】

来源:互联网 发布:vb循环语句do while 编辑:程序博客网 时间:2024/05/17 04:32

 

Sumsets

时间限制(普通/Java):2000MS/20000MS     运行内存限制:65536KByte
总提交: 0            测试通过: 0
http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1632

描述

Farmer John commanded his cows to search for different sets of numbers that sum to a given number. The cows use only numbers that are an integer power of 2. Here are the possible sets of numbers that sum to 7:

1) 1+1+1+1+1+1+1
2) 1+1+1+1+1+2
3) 1+1+1+2+2
4) 1+1+1+4
5) 1+2+2+2
6) 1+2+4

Help FJ count all possible representations for a given integer N (1 <= N <= 1,000,000).

输入

A single line with a single integer, N.

 

输出

The number of ways to represent N as the indicated sum. Due to the potential huge size of this number, print only last 9 digits (in base 10 representation).

 

样例输入

 

7

 

样例输出

 

6

 

原创总结:看起来像母函数,如果大数据超时夸张,可以考虑找规律。

 

分析:

 转自:http://hi.baidu.com/mad4alcohol/blog/item/744edc9472ac3c41d0135e1c.html

以s[i]表示i的拆分方案总数,则
如果i为奇数,那么s[i] = s[i - 1],否则s[i] = s[i / 2] + s[i - 1]
为什么?想想以下的例子,你就明白了:
7 =
1 + 1 + 1 + 1 + 1 + 1 + 1 =
1 + 1 + 1 + 1 + 1 + 2 =
1 + 1 + 1 + 2 + 2 =
1 + 1 + 1 + 4 =
1 + 2 + 2 + 2 =
1 + 2 + 4

6 =
1 + 1 + 1 + 1 + 1 + 1 =
1 + 1 + 1 + 1 + 2 =
1 + 1 + 2 + 2 =
1 + 1 + 4 =
2 + 2 + 2 =
2 + 4 =

5 =
1 + 1 + 1 + 1 + 1 =
1 + 1 + 1 + 2 =
1 + 2 + 2 =
1 + 4

4 =
1 + 1 + 1 + 1 =
1 + 1 + 2 =
2 + 2 =
4

3 =
1 + 1 + 1 =
1 + 2

2 =
1 + 1 =
2

1 =
1

可以发现:由于奇数是由一个偶数加1得到的,而这个1对方案总数没有影响,所以奇数的方案总数为它的前一个数的方案总数(即偶数的方案总数);
对于偶数x,上面说了,如果某个数由另一个数加1得到,那么这个1对方案总数没有影响,所以x的方案总数肯定有x - 1的方案总数的份,这样方案中至少包含1 + 的种类考虑到了,如果这个数的拆分方案中不包含1 + 的话(肯定是有的,因为是偶数),比如6,将它的含1 + 的方案剃掉,我们就有
6 =
2 + 2 + 2 =
2 + 4
除以2的话,我们得到了
3 =
1 + 1 + 1 =
1 + 2
这不就是3的方案吗,所以x的方案总数的第二部分就是x/2的方案总数。

综上 s[i] = s[i - 1], i is odd;
s[i] = s[i - 1] + s[i / 2], i is even.

 
另一个想法:
转自:http://hi.baidu.com/rain_bow_joy/blog/item/11f51c1d7e7a7a8287d6b6cd.html
最后思路是一样的找规律。

题意:

就是给定一个n,来计算有2的次方数所能组成N的种数;(ps:就喜欢看这种,简单明了的题。。

算法:(dp 可做,肯定超时啊;找规律);

一看就是个多重背包问题;最优子结构得状态方程:

再增加一个2的次方数X时,dp【i】=sum{dp[k]},k是能通过加上X的倍数等于i;

于是乎,写之;正确是正确,只是这样严重超时啊。。不是一般的超时啊。。

于是把前几十个数的结果打印出来观察;有规律。。

奇数时dp【i】=dp[i-1];

偶数时dp[i]=dp[i-2]+dp[i/2];

只是不知为甚?。。后来看到disscuss,才发现自己的弱智。。(ps:自我鄙视一小下);

当i为奇数时,可以有1加到,就是dp【i】=dp[i-1];

当i为偶数时,可以有1+1,和全部是偶数得到,就是dp[i]=dp[i-2]+dp[i/2];

另外,取后几位的话,取模一下就okay了。。

方丈的代码:

#include<iostream>
using namespace std;

long dp[1100000];
int main()
{
    int N;scanf("%d",&N);
    int d;
    
     dp[1]=1;dp[2]=2;dp[3]=2;dp[4]=4;dp[5]=4;dp[6]=6;
    for(d=7;d<=N;d++)
     {
        if(d%2) {dp[d]=dp[d-1];}
        else
         {
             dp[d]=dp[d-2]+dp[d/2];
            if(dp[d]>999999999) dp[d]%=1000000000;
         }
     }
     printf("%d/n",dp[N]);
return 0;}

原创粉丝点击