一个整数总可以拆分为2的幂的和,例如: 7=1+2+4 7=1+2+2+2 7=1+1+1+4 7=1+1+1+2+2 7=1+1+1+1+1+2 7=1+1+1+1+1+1+1 总共有六种不同的拆分方式。 再比如:4可以拆分成:4 = 4,4 = 1 + 1 + 1 + 1,4 = 2 + 2,4=1+1+2。 用f(n)表示n的不同拆分的种数,例如f(7)=6. 要求编写程序,读入n(不超过1000000),输出f(n)%1000000000。
每组输入包括一个整数:N(1<=N<=1000000)。
对于每组数据,输出f(n)%1000000000。
示例1
复制
7
复制
6
如果i是奇数,i=1+(i-1),所以f(i)=f(i-1)
如果i是偶数,f(i)=f(i-1)+f(i/2) 此时i的所有划分中有两种情况,一种是包含1,一种是不包含1(我在这里看别人的思路就不太懂,
包含1:i=1+(i-1) :在i-1的每个划分中,给他加上一个1
不包含1:i=2*(i/2):对于i/2的每个划分,对划分中的每个数乘2,这样整个划分中就不会有1了。
举个例子,6的不包含1的划分:
#include
using namespace std;
long long f[1000005];
int main(){
int n;
while(scanf("%d",&n)!=EOF){
f[1]=1;
for(int i=2;i<=n;i++){
if(i%2) f[i]=f[i-1];
else f[i]=(f[i-1]+f[i/2])%1000000000;
}
printf("%lld\n",f[n]);
}
return 0;
}
本题是要将一个整数拆分为2的幂的和,即将n拆分成2^0,2^1,2^2,2^3……2^19,然后正好组成数n。可以理解为:一个背包容量为n,有20种物品,每种物品个数不限,体积分别为2^0,2^1,2^2,2^3……2^19,求有多少种方案能恰好把背包装满,即完全背包问题
int a[20]={2^0,2^1,……2^19};
状态转移方程:
dp[i][j]表示用前j个数字,组成i的方案个数,此时就分为两种情况
此时不再是求哪种方案价值最大,而是总的方案个数,所以不用max,而是相加
dp[i][j]=dp[i][j-1]+dp[i-a[j]][j]
转换为一维数组 dp[i]=dp[i]+dp[i-a[j]] (j要从前往后遍历)
边界:
dp[0]=1
dp[1~n]=0
#include
using namespace std;
long long dp[1000005];
int main(){
long long a[21];
a[0]=1;
for(int i=1;i<20;i++){
a[i]=a[i-1]<<1;
}
int n;
while(scanf("%d",&n)!=EOF){
for(int i=0;i<=n;i++){
dp[i]=0;
}
dp[0]=1;
for(int j=0;j<20;j++){ //20种
for(int i=a[j];i<=n;i++){
dp[i]=(dp[i]+dp[i-a[j]])%1000000000;
}
}
printf("%lld\n",dp[n]);
}
return 0;
}