题目链接
题目大意:求把一个整数分解为2的幂的和共有几种方案
7=1+1+1+1+1+1+1
7=1+1+1+1+1+2
7=1+1+1+2+2
7=1+1+1+4
7=1+2+2+2
7=1+2+4
输出6
思路:一开始的时候推过,没推出来。后来看了一眼题解,说是完全背包的变形,顿悟。可还是没想出来怎么变形。看代码吧。
#include
#include
#include
#include
using namespace std;
#define MOD 1000000000
int dp[1000001], data[30];
int main()
{
data[0] = 1;
for(int i = 1; ; i++) {
if(data[i - 1] * 2 > 1000000) break;
data[i] = data[i - 1] * 2;
}
int n;
while(~scanf("%d", &n))
{
memset(dp, 0, sizeof(dp));
dp[0] = 1;
for(int i = 0; i <= 19; i++)
{
for(int j = data[i]; j <= n; j++)
{
dp[j] = (dp[j] + dp[j - data[i]]) % MOD;
//主要是这里没有想出来 其实这里的dp[j]就表示的是用到2^i时凑成j的方案数。
}
}
printf("%d\n", dp[n]);
}
}
然后又看了另一种方法。
首先i是奇数时,dp[i] = dp[i - 1],当时我就在想,这样对不对,会不会有一种情况有1个1,然后再加上1个变成2的,后来发现不可能,因为加上1变成2就一定成偶数了。
i是偶数时,dp[i] = dp[i - 1] + dp[i / 2]
dp[i - 1]就是在奇数的基础上加上1,然后现在dp[i]所有的等式上都是有1的了,少了没有1的,没有1的就是dp[i / 2] 把dp[i / 2]的每一项乘以2就是dp[i]的没有1的方案。
#include
#include
#include
using namespace std;
const int mod = 1e9;
const int maxn = 1e6 + 100;
int data[maxn];
int main()
{
int n;
scanf("%d", &n);
data[0] = 1;
data[1] = 1;
for(int i = 2; i <= n; i++)
{
if(i & 1) data[i] = data[i - 1];
else {
data[i] = data[i - 1] + data[i / 2];
}
data[i] %= mod;
}
printf("%d\n", data[n]);
}
然后做完这个题目,又想起了之前队长说的那道题。给n个数,选<=m个,去凑sum,问有多少种方案。
dp[j][k] j代表用几个,k代表凑几,又是一个完全背包的变形。
#include
#include
#include
using namespace std;
const int mod = 1e9;
const int maxn = 1e3 + 100;
int data[maxn], dp[maxn][maxn];
int main()
{
int n, m, sum;
scanf("%d %d %d", &n, &m, &sum);
for(int i = 0; i < n; i++)
scanf("%d", &data[i]);
dp[0][0] = 1;
for(int i = 0; i < n; i++) {
for(int j = 1; j <= m; j++) {
for(int k = data[i]; k <= sum; k++) {
dp[j][k] = dp[j - 1][k - data[i]] + dp[j][k];
}
}
}
int ans = 0;
for(int i = 1; i <= m; i++)
{
ans += dp[i][sum];
}
printf("%d\n", ans);
}
这个代码只是我们想出来的,没有真正A过题。