标签:
Time Limit: 2000MS | Memory Limit: 200000K | |
Total Submissions: 15105 | Accepted: 6017 |
Description
Input
Output
Sample Input
7
Sample Output
6
Source
有两种做法
第一种是比较暴力的完全背包:
设状态dp[i]为在总和为i的情况下符合题意的方法总数,因为n不超过2 ^ 20,所以可以把这20个数看成是物品,则可以用完全背包的方法写出状态方程
dp[i] = dp[i - (1 << j)] ; ((1 << j) <= n)
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 6 using namespace std; 7 8 const int maxn = 1e6 + 7; 9 const int mod = 1e9; 10 int dp[maxn]; 11 int main() { 12 int n; 13 scanf("%d", &n); 14 dp[0] = 1; 15 for (int i = 0; 1 << i <= n; ++i) { 16 for (int j = 1 << i; j <= n; ++j) { 17 dp[j] = (dp[j] + dp[j - (1 << i)]) % mod; 18 } 19 } 20 21 printf("%d\n", dp[n]); 22 23 24 return 0; 25 }
第二种是略有技巧性的递推:
同样设状态dp[i]为在总和为i的情况下符合题意的方法总数,考虑n为奇数和n为偶数的两种情况。
当n为奇数时,容易知序列中必含有1
dp[i] = dp[i - 1];
当n为偶数时,若序列中有1则至少含有两个1,dp[i] += dp[i - 2];
若序列中没有1,则容易知序列所有数都是偶数,则dp[i] += dp[i / 2];
两式相加得dp[i] = dp[i - 2] + dp[i / 2];
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 6 using namespace std; 7 8 const int maxn = 1e6 + 7; 9 const int mod = 1e9; 10 int dp[maxn]; 11 int main() { 12 int n; 13 scanf("%d", &n); 14 dp[0] = 1; 15 for (int i = 1; i <= n; ++i) { 16 if (i % 2 == 1) { 17 dp[i] = dp[i - 1]; 18 } else { 19 dp[i] = (dp[i - 2] + dp[i / 2]) % mod; 20 } 21 } 22 23 printf("%d\n", dp[n]); 24 25 26 return 0; 27 }
标签:
原文地址:http://www.cnblogs.com/hyxsolitude/p/5103007.html