标签:
题意:给你一个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