51Nod 1383 整数分解为2的幂

51Nod 1383 整数分解为2的幂

题意

任何正整数都能分解成2的幂,给定整数N,求N的此类划分方法的数量!由于方案数量较大,输出Mod 1000000007的结果。
比如N = 7时,共有6种划分方法。

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

输入:输入一个数N(1 <= N <= 10^6)

输出:输出划分方法的数量Mod 1000000007

解题思路

这个题目我开始想到的想法类似于整数划分问题

整数划分问题中,定义假设函数f(n,m):n为要整数划分的数,m为划分中出现的最大加数

这里我进行了一些改变:n还是要进行划分的数,m表示为2的指数,如m=2表示的数是$$2^2$$。

这样$$f(n, m) = fun(n-2^m, m)+fun(n, m-1)$$

上面的公式表示两部分,一部分是使用了$$2^m$$,一部分是没有使用。

然后使用记忆化搜索即可,使用二维的数组来进行记录,注意第二维,我们根据输入的范围是1e6,小于2的22次方,所以第二维大小是22解可以了。

第二种方法

做完这个题后,我搜了这个题,发现可以用递推的方式来进行

if(N%2==0) F[N]=F[N-1]+F[N>>1]

else F[N]=F[N-1]

  • 对于一个偶数,可以让比他小一数的方案全部加一个1得到,也可以让比他小一半的数的方案元素都乘以2得到。

  • 对于奇数只能由比他小的数加一得到。

代码实现

//第一种方式
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<sstream>
typedef long long ll;
using namespace std;
const ll llinf = 0x3f3f3f3f3f3f3f3f;
const int inf=0x3f3f3f3f;
const double eps=1e-6;
const int MAXN=1e6+7;
const ll mod = 1000000007;
ll n, ans;
int dp[MAXN][22];
int dfs(int x, int p){
    if(p<0)
        return 0;
    if(x==0)
        return 1;
    int y = 1<<p;
    if(x<y){
        do{
            y>>=1;
            p--;
        }while(x<y);
    }
    if(dp[x][p]>=0){
        return dp[x][p];
    }
    dp[x-y][p] = dfs(x-y, p) % mod;
    dp[x][p-1] = dfs(x, p-1) % mod;
    return dp[x][p] = (dp[x-y][p] + dp[x][p-1])%mod ;
}
int main(){
    cin>>n;
    int max2 = 0;
    memset(dp, -1, sizeof(dp));
    for(int i=0, tmp = 1; tmp<=n; i++){
        max2=i;
        tmp <<= 1;
    }
    // cout<<max2<<endl;
    cout<<dfs(n, max2)<<endl;
    return 0;
}
//第二种方式
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6;
const int MOD = 1e9 + 7;
int f[N + 1];

int main(){
    f[0] = 1;
    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 >> 1]) % MOD;
    int n;
    while(~scanf("%d", &n))
        printf("%d
", f[n]);
    return 0;
}
原文地址:https://www.cnblogs.com/alking1001/p/13719215.html