1) 1+1+1+1+1+1+1
2) 1+1+1+1+1+2
3) 1+1+1+2+2
4) 1+1+1+4
5) 1+2+2+2
6) 1+2+4
Help FJ count all possible representations for a given integer N (1 <= N <= 1,000,000).
7Sample Output
6
dp[i]=dp[i-1] //i为奇数
dp[i]=dp[i-1]+dp[i/2] //i为偶数
边界控制:dp[1]=1
当i为奇数,很好理解,奇数是1产生的吧,每个划分里面必须都要有1,把这个1减去,就是偶数i-1的划分。把7的每个划分都减去1不就是6的吗?
i=7
1) 1+1+1+1+1+1+1
2) 1+1+1+1+1+2
3) 1+1+1+2+2
4) 1+1+1+4
5) 1+2+2+2
6) 1+2+4
当i为偶数,把所有的划分 分成两组,带1的和不带1的。带1的不又是比原偶数(6)小1的奇数(5)的划分了吗?不带1的划分里面肯定含有2吧?同时除2,不又产生1了吗(也就是说,又是一个完整的划分了)?
i=6
1) 1+1+1+1+1+1
2) 1+1+1+1+2
3) 1+1+2+2
4) 1+1+4
5) 2+2+2 (1+1+1)
6) 2+4 (1+2)不就是3的所有(完整性)划分了吗?
感觉这个规律总结的十分的巧妙了。如果没有总结出这个规律的也还有完全背包的做法
dp[i][j]:只用前i个数,j的组合数
dp[i][j]=∑dp[i-1][j-k*w[i]] k>=0;
含义:先从前i-1个数里面组合成j-k*w[i].再从第i个里面拿出来k个。有点完全背包的意思。
化简:
原式=∑dp[i-1][j-k*w[i]] k>=0;
=dp[i-1][j]+∑dp[i-1][j-k*w[i]] k>=1;
=dp[i-1][j]+∑dp[i-1][j-w[i]-(k-1)*w[i]] k-1>=0;
=dp[i-1][j]+dp[i][j-w[i]]
dp[i][j]=dp[i-1][j]+dp[i][j-w[i]]
边界控制dp[1][j]=1;
方法1的代码
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#define mod 1000000000
using namespace std;
long long dp[1000010];
int main()
{
int n;
ios::sync_with_stdio(false);
cin>>n;
dp[1]=1;
if(n>1){
for(int i=2;i<=n;i++){
if(i&1){
dp[i]=dp[i-1];
}
else {
dp[i]=(dp[i-1]+dp[i/2])%mod;
}
}
}
cout<<dp[n]<<endl;
return 0;
}
方法2的代码
- #include<iostream>
- #include<cstdio>
- #include<algorithm>
- using namespace std;
- long w[21];//2的20次方刚好比最大数据多一点
- int dp[1000005];
- const long long MOD = (int)1e9;
- int main()
- {
- int N;
- w[1] = 1;
- for (int i = 2; i <= 20; i++) //20个物品,最后一个为2^19;
- w[i] = w[i - 1] * 2;
- while( cin >> N)
- {
- fill(dp, dp + N + 1, 1);
- for (int i = 2; i <= 20; i++)
- for (int j = w[i]; j<=N; j++)
- {
- dp[j] += dp[j - w[i]];
- dp[j] %= MOD;
- }
- cout << dp[N] << endl;
- }
- system("pause");
- }