POJ 2229 Sumsets(dp 递推)

本文探讨了如何计算一个整数N通过不同2的幂次组合的方式,使用递推和完全背包两种方法进行实现,并提供了高效的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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).
Input
A single line with a single integer, N.
Output
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).
Sample Input
7
Sample Output
6

题意:给N,N由很多个2的次幂相加得到,求有多少种方案。
思路:
1.第一眼是完全背包,每个物品的价值是1,2,4,8….然后往N里背。
这样的复杂度是O(NlogN)=20*1e6,看题目是2s以为可以过,T了几发。
2.重新思考一下发现有递推的规律。
1=1;
2=1+1;
2=2;
3=1+1+(1);
3=2+(1);
4=1+1+(1+1);
4=2+(1+1);
4=(1+1)*2=2+2;
4=2*2=4;
如果是奇数 那么i的分解式就是在i-1的分解式上+1,所以f[i]=f[i-1]
如果为偶数 i的分解式是在i-2的所有分解式上加1+1 (与奇数i-1在i-2 基础上的结论相合)加上 i/2 的分解式*2 。

两个可以综合起来,就是f[i]=f[i-2]+f[i/2];

//完全背包,HDU可以A 142ms;然而 POJ要T

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#define mem(array) memset(array,0 , sizeof array)
using namespace std;
const long long MOD=1e9;
int n;
long long dp[1000005];
int main(){
//  freopen("in.txt","r",stdin);
//  freopen("out.txt","w",stdout);
    mem(dp);
    dp[0]=1;
    for(int i=1;i<=1000000;i=i<<1){
    //  cout<<i<<endl;
        for(int j=i;j<=1000000;j++){
            dp[j]=(dp[j-i]+dp[j]) %MOD;
        }
    }
    while(~scanf("%d",&n)){
        printf("%lld",dp[n]);
    }
    return 0;
}

//递推 HDU 14ms POJ也可A

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#define mem(array) memset(array,0 , sizeof array)
using namespace std;
const long long MOD=1e9;
int n;
long long dp[1000005];
int main(){
    //freopen("in.txt","r",stdin);
//  freopen("out.txt","w",stdout);
    mem(dp);
    dp[0]=dp[1]=1;
    for(int i=2;i<=1000000;i++){
    //  cout<<i<<endl;
        dp[i]=(dp[i-2]+dp[i/2]) % MOD ;
    }
    while(~scanf("%d",&n)){
        printf("%lld\n",dp[n]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值