题目背景
题目名称是吸引你点进来的。
实际上该题还是很水的。
题目描述
- 1+1=? 显然是 22。
- a+b=? P1001 回看不谢。
- 哥德巴赫猜想 似乎已呈泛滥趋势。
以上纯属个人吐槽
给定一个正整数 n,求将其分解成若干个素数之和的方案总数。
输入格式
一行一个正整数 n。
输出格式
一行一个整数表示方案总数。
输入输出样例
输入
7
输出
3
输入
20
输出
26
说明/提示
样例解释
存在如下三种方案:
- 7=7。
- 7=2+5。
- 7=2+2+3。
数据范围及约定
- 对于 30% 的数据 1≤n≤10。
- 对于100% 的数据,1≤n≤1e3。
思路:给定一个数,求有多少种方式可以使素数相加等于这个数, 素数无限取,可以想到完全背包。
完全背包的属性可以是最大值也可以是数量。
明显本题要求的属性为数量,即求有多少种方法可以装满背包。
完全背包求最大值的模板如下:
#include<iostream>
using namespace std;
const int N = 1010;
int n, m;
int f[N], v[N], w[N];
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i ++) cin >> v[i] >> w[i];
for(int i = 1; i <= n; i ++)
{
for(int j = v[i]; j <= m; j ++)
{
f[j] = max(f[j], f[j - v[i]] + w[i]);
}
}
cout << f[m];
}
求有多少种方法填满背包的思路与求背包最大值的思路基本一致,所以对以上模板稍作修改即可。
每个物品的体积就相当于每个素数的大小,没有价值,可以把w数组删掉。
体积数组装素数,来个埃及筛、线性筛什么的先把m以内的素数筛出来。
f[0]的含义为背包容量为0时有几种方法填满它,一个素数也不选,值为1;
记得开long long数组,值可能很大。
AC代码:
#include<iostream>
using namespace std;
typedef long long ll;
const int N = 1010;
int n, m;
int primes[N], cnt = 0;
ll f[N];
bool st[N];
void is_prime(int n)
{
for(int i = 2; i <= n; i ++)
{
if(!st[i])primes[cnt ++] = i;
for(int j = 0; primes[j] <= n / i; j ++)
{
st[primes[j] * i] = true;
if(i % primes[j] == 0)break;
}
}
}
int main()
{
cin >> m;
is_prime(m);
f[0] = 1;
for(int i = 0; i < cnt; i ++)
{
for(int j = primes[i]; j <= m; j ++)
{
f[j] += f[j - primes[i]];
}
}
cout << f[m];
}