1. 程式人生 > >HDOJ-2709 Sumsets(遞推)

HDOJ-2709 Sumsets(遞推)

題目:HDOJ-2709

題目描述:
給出一個正整數N,求出N能由多少種2的冪次方(1,2,4,8…)之和的組合得到。
(1 <= N <= 1,000,000)(由於資料過大,所有答案只取後9位。)

例如當N等於7,有6種方案
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

思路:
當N為奇數(分解方案中必有1):則N-1為偶數,易知N的所有分解方案都是在N-1的基礎上+1
所以此時f(N)=f(N-1)

當N為偶數:
①首先同樣的在N-1的所有分解方案上+1,可以得到部分的分解方案。
②但是,還是存在分解方案內不含1的情況,經分析可以知道將N/2的所有分解方案*2,就得到了所有不含1的分解方案。
所以此時f(N)=f(N-1)+f(N/2)

舉個例子便於理解:
N=2,2種方案:①2  ②1+1
N=3,2種方案:①2+1  ②1+1+1
可以看到N=3時,都是在N=2的基礎上+1。
那麼當N=4時,
首先是在N=3的基礎上+1,得到兩種:①2+1+1  ②1+1+1+1
再者就是將N=2的方案*2,又得到兩種:③4  ④2+2
一共4種方案

+1提供了包含1的方案,*2提供了不包含1的方案,兩者得到依舊是2的冪次方的求和組合。

以下程式碼:

#include<cstdio>
using namespace std;
int main()
{
    __int64 f[1000001];
    int i,
n; f[1] = 1; f[2] = 2; for (i = 3; i <= 1000000; i++) { if (i % 2 == 1) f[i] = f[i - 1]; //為奇數 else f[i] = f[i - 1] + f[i / 2]; //為偶數 f[i] %= 1000000000; //取最後9位 } while (scanf("%d", &n)!=EOF) printf("%I64d\n", f[n]); return
0; }