BZOJ 1677 [Usaco2005 Jan]Sumsets 求和:dp 無限背包 / 遞推【2的冪次方之和】
阿新 • • 發佈:2017-10-04
zoj mem iostream memset bzoj -1 target ont 背包
題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=1677
題意:
給定n(n <= 10^6),將n分解為2的冪次方之和,問你有多少種方法。
題解:
兩種方法。
一、無限背包
將1,2,4,8...看作物品體積就好。
復雜度O(n*k),k約為20。
二、遞推
對於dp[i],有兩種情況。
(1)i為奇數。則分解結果中一定有1。
所以dp[i] = dp[i-1]。
(2)i為偶數。再分兩種情況:
a. 分解結果中有1,所以dp[i] += dp[i-1]
b. 分解結果中沒有1,即所有加數都是2的倍數。可以將所有加數都除以2,所以dp[i] += dp[i/2]
綜上:dp[i] = dp[i-1] + dp[i/2]
AC Code(背包):
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #define MAX_N 1000005 5 #define MOD 1000000000 6 7 using namespace std; 8 9 int n; 10 int dp[MAX_N];11 12 int main() 13 { 14 cin>>n; 15 memset(dp,0,sizeof(dp)); 16 dp[0]=1; 17 for(int i=0;i<=20;i++) 18 { 19 for(int j=(1<<i);j<=n;j++) 20 { 21 dp[j]=(dp[j]+dp[j-(1<<i)])%MOD; 22 } 23 } 24 cout<<dp[n]<<endl;25 }
AC Code(遞推):
1 // if is odd dp[i] = dp[i-1] 2 // if is even dp[i] = dp[i-1] + dp[i/2] 3 #include <iostream> 4 #include <stdio.h> 5 #include <string.h> 6 #define MAX_N 1000005 7 #define MOD 1000000000 8 9 using namespace std; 10 11 int n; 12 int dp[MAX_N]; 13 14 int main() 15 { 16 cin>>n; 17 memset(dp,0,sizeof(dp)); 18 dp[0]=1; 19 for(int i=1;i<=n;i++) 20 { 21 if(i&1) dp[i]=dp[i-1]; 22 else dp[i]=(dp[i-1]+dp[i>>1])%MOD; 23 } 24 cout<<dp[n]<<endl; 25 }
BZOJ 1677 [Usaco2005 Jan]Sumsets 求和:dp 無限背包 / 遞推【2的冪次方之和】