思路1:
dp[n]表示n拆分的个数
假如n为奇数,dp[n] = dp[n - 1]
假如n为偶数
1.拆分方案中有1 dp[n - 1]
2.拆分方案中没有1 dp[n / 2]
所以偶数情况下 dp[n] = dp[n - 1] + dp[n / 2]
#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define MAX_N 1000005
#define mod 1000000000
using namespace std;
int dp[MAX_N];
int main()
{
//freopen("in.txt", "r", stdin);
int N;
scanf("%d", &N);
dp[1] = 1;
for (int i = 2; i <= N; i++)
{
if (i & 1)
dp[i] = dp[i - 1] % mod;
else
dp[i] = (dp[i - 1] + dp[i >> 1]) % mod;
}
printf("%d\n", dp[N]);
return 0;
}
思路2:转化成完全背包问题
dp[i][j]表示前i件物品装进容量为j的背包中可能的方案总数
前i件物品的重量分别为2^0,2^1,.....2^i。
w[i]表示第i件物品的重量
递推式为
dp[i][j] = sum( dp[i - 1][ j - k * w[i] ] ) 其中 j - k * w[i] >= 0
和完全背包问题一样的化简方式,化简结果为
dp[i][j] = dp[i - 1][j] + dp[i][j - w[i]]
同时我们注意到可以用滚动数组的方法写,所以状态转移方程就变成了
dp[j] = dp[j] + dp[j - w[i]]
注意一下计算的方向是从左到右就行了,然后不断的迭代20次就得到了答案
代码如下:
#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define MAX_N 1000005
#define mod 1000000000
using namespace std;
int dp[MAX_N];
int fact[20];
void get_fact()
{
fact[0] = 1;
for (int i = 1; i <= 19; i++)
fact[i] = fact[i - 1] * 2;
}
int main()
{
//freopen("in.txt", "r", stdin);
int N;
scanf("%d", &N);
get_fact();
dp[0] = 1;
for (int i = 0; i < 20; i++)
for (int j = fact[i]; j < MAX_N; j++)
dp[j] = (dp[j] + dp[j - fact[i]]) % mod;
printf("%d\n", dp[N]);
return 0;
}
(注意不用滚动数组会超时)