标签:
题意:给你一个n,还有k,求问有多少种数字组合,能够使得数字之和为n,这些数字的范围是1到k。
如,给你n=4, k=2。那么 1+1+1+1=4, 1+1+2=4,2+2=4,四种组合。
思路:完全背包,可以设d[i][j]代表从i个数字相加和为j的组合数。
那么,可以考虑把这些组合数分为,有数字i和没有数字i,那么没有数字i的组合数就为d[i-1][j],有数字i的组合数就为d[i][j-i](可以在这些组合里面加上1个i)。
所以,转移方程可以写成d[i][j] = d[i-1][j] + d[i][j-i](若j<i,那么为0);
按照这些个方程编码后,输入1000 100(最大值),结果就溢出了,显然这个组合数太大了。
那么可以考虑试试用longlong,然后把组合数分成前一半和后一半的数字记录。
AC代码:
#include <cstdio> #include <iostream> #include <cstring> using namespace std; const int N = 1005; const long long MOD = 1000000000000000000; long long a[105][N], b[105][N]; int n,k; void solve() { memset(b, 0, sizeof(b)); memset(a, 0, sizeof(a)); for(int i = 0; i <= k; i++) b[i][0] = 1; for(int i = 1; i <= k; i++) { for(int j = 1; j <= n; j++) { if(j >= i) { b[i][j] = (b[i-1][j]+b[i][j-i])%MOD; a[i][j] = (a[i-1][j]+a[i][j-i])+(b[i-1][j]+b[i][j-i])/MOD; } else { b[i][j] = b[i-1][j]; a[i][j] = a[i-1][j]; } } } if(a[k][n]>0) cout<<a[k][n]; cout<<b[k][n]<<endl; } int main() { //freopen("out.txt", "w", stdout); while(~scanf("%d %d", &n, &k)) { solve(); } return 0; }
滚动数组 AC代码:
#include <cstdio> #include <iostream> #include <cstring> using namespace std; const int N = 1005; const long long MOD = 1000000000000000000; long long a[2][N], b[2][N]; int n,k; void solve() { int f = 1; memset(b, 0, sizeof(b)); memset(a, 0, sizeof(a)); for(int i = 0; i <= 1; i++) b[i][0] = 1; for(int i = 1; i <= k; i++) { for(int j = 1; j <= n; j++) { if(j >= i) { b[f][j] = (b[!f][j]+b[f][j-i])%MOD; a[f][j] = (a[!f][j]+a[f][j-i])+(b[!f][j]+b[f][j-i])/MOD; } else { b[f][j] = b[!f][j]; a[f][j] = a[!f][j]; } } f = !f; b[f][0] = 1; for(int j = 1; j <= n; j++) b[f][j] = 0; } if(a[!f][n]>0) cout<<a[!f][n]; cout<<b[!f][n]<<endl; } int main() { //freopen("out.txt", "w", stdout); while(~scanf("%d %d", &n, &k)) { solve(); } return 0; }
做法2:参考网上,基本和第一种做法一样,只是状态转移方程有点不一样。
方程d[i][j]——整数i的划分个数,划分中最大整数不大于j
从而分类讨论,若i < j,整数i的划分里,最大整数必定小于等于i,故d[i][j] = d[i][i]。
若i = j,整数i的划分里,单独i就已为一个划分,所以,整数i的划分可分为单独一个i和没有i的划分,那么d[i][j] = d[i][j-1]+1
若i > j,整数i的划分可分为有整数j或者没有整数j,从而d[i][j] = d[i][j-1] + d[i-j][j]
做法2 AC代码:
#include <cstdio> #include <iostream> #include <cstring> using namespace std; const int N = 1005; const long long MOD = 1000000000000000000; long long a[N][105], b[N][105]; int n,k; void solve() { memset(b, 0, sizeof(b)); memset(a, 0, sizeof(a)); for(int i = 0; i <= k; i++) b[1][i] = 1; for(int i = 2; i <= n; i++) { for(int j = 1; j <= k; j++) { if(i > j) { b[i][j] = (b[i][j-1] + b[i-j][j])%MOD; a[i][j] = a[i][j-1] + a[i-j][j]+(b[i][j-1] + b[i-j][j])/MOD; }else if(i == j) { b[i][j] = (b[i][j-1]+1)%MOD; a[i][j] = a[i][j-1] + (b[i][j-1]+1)/MOD; //if(b[i][j-1]+1>MOD) a[i][j]++; }else { b[i][j] = b[i][i]; a[i][j] = a[i][i]; } } } if(a[n][k]>0) cout<<a[n][k]; cout<<b[n][k]<<endl; } int main() { //freopen("out.txt", "w", stdout); while(~scanf("%d %d", &n, &k)) { solve(); } return 0; }
标签:
原文地址:http://www.cnblogs.com/sevenun/p/5453748.html