HDU - 2709 Sumsets 【递推】
题目链接
http://acm.hdu.edu.cn/showproblem.php?pid=2709
题意
给出一个数N 要求有多少种方式 求和 能够等于N
加的数 必须是 2的幂次
思路
首先可以想到的是
如果 N 是奇数的话
那么 到达N 的方法数 就是 到达 N - 1 的方法数
因为就相当于 把 所有到达N-1 的方法数 都再 + 1
如果 N 是偶数的话
就有两种情况
0.分解的数字中至少有两个1 那么 dp[n] = 1 + 1 + dp[n - 2]
1.分解的数字中没有1 也就是说 是由dp[n - 2] 中每个分解方式中的数字 都*2 就是 n
所以 dp[n] = dp[n - 2] + dp[n / 2]
AC代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<map>
#include<set>
#include<string>
#include<list>
#include<stack>
#include <queue>
#define CLR(a, b) memset(a, (b), sizeof(a))
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 1e6 + 5;
const int MOD = 1e9;
ll dp[maxn];
void init()
{
dp[0] = 1;
for(int i=1;i<maxn;++i)
{
if(i&1) dp[i]=dp[i-1];
else dp[i]=(dp[i-2]+dp[i/2]) % MOD;
}
}
int main()
{
init();
int n;
while (~scanf("%d", &n))
{
printf("%lld\n",dp[n]%MOD);
}
}
思路二
可以枚举式子中 最大的那位 是多少
比如 最大的那位是 1
dp[1] = 1;
那么
dp[n] = dp[n - 1]
此时表示的状态是 每个到N的方式 组成的数字中 只有1
最大位是2
那么
dp[n] += dp[n - 2]
因为我们是按照 最大数 枚举上去的
而不是 按照 之前的状态转移的
比如 最大数是2
那么 dp[n] 就要加上 dp[n - 2] dp[n - 2] 表示 最大数是2 来到达n - 2 的方式总数
而不是 到达 n - 2 的所有方式
AC代码
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <stack>
#include <set>
#include <list>
#include <numeric>
#include <sstream>
#include <iomanip>
#include <limits>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair<string, int> psi;
typedef pair<string, string> pss;
const double PI = acos(-1.0);
const double E = exp(1.0);
const double eps = 1e-8;
const int INF = 0x3f3f3f3f;
const int maxn = 1e6 + 5;
const int MOD = 1e9;
int binary[25];
int dp[maxn];
void init()
{
CLR(binary, 0);
CLR(dp, 0);
binary[0] = 1;
dp[0] = 1;
for (int i = 1; i < 25; i++)
binary[i] = binary[i - 1] * 2;
for (int i = 0; i < 25 && binary[i] < maxn; i++)
{
for (int j = binary[i]; j < maxn; j++)
{
dp[j] += dp[j - binary[i]];
dp[j] %= MOD;
}
}
}
int main()
{
init();
int n;
while (~scanf("%d", &n))
cout << dp[n] % MOD << endl;
}