问题 L(1330): Prime
时间限制: 1 Sec 内存限制: 64 MB题目描述
任何大于 1 的自然数 N,都可以写成若干个大于等于2且小于等于 N 的质数之和表达式(包括只有一个数构成的和表达式的情况),并且可能有不止一种质数和的形式。 例如9 的质数和表达式就有四种本质不同的形式:9 = 2+5+2 = 2+3+2+2 = 3+3+3 = 2+7 。 这里所谓两个本质相同的表达式是指可以通过交换其中一个表达式中参加和运算的各个数的位置而直接得到另一个表达式。 试编程求解自然数 N 可以写成多少种本质不同的质数和表达式。
输入
第1行:一个自然数 N , 2≤N≤2000。
输出
第1行:输出每一个自然数 N 的本质不同的质数和表达式的数目。
样例输入
2
样例输出
1
题目大意:
求将任意一个正整数分解成小于它的质数之和的方案数。
简单的想一下,就知道是一个完全背包问题,即要用若干个质数填满容量为N的的背包。
于是我们先用素数筛法筛出小于N的所有素数,然后做一遍完全背包就行了。
状态转移方程式为:f[j]=f[j]+f[j-prime[i]];
下附AC代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
#define MAXN 2010
#define MAXLEN 110
#define INF 0x3f3f3f3f
#define BIG 100000
typedef unsigned long long ULL;
typedef long long LL;
struct INT
{
int num[MAXLEN];
int len;
INT(){memset(num,0,sizeof(num));len=0;}
void operator = (const int &a)
{
int tmp=a;
while(tmp)
{
num[++len]=tmp%BIG;
tmp/=BIG;
}
}
};
INT operator + (const INT &a,const INT &b)
{
INT rn;
int res=0;
rn.len=max(a.len,b.len);
for(int i=1;i<=rn.len;++i)
{
rn.num[i]=(a.num[i]+b.num[i]+res)%BIG;
res=(a.num[i]+b.num[i]+res)/BIG;
}
if(res)rn.num[++rn.len]=res;
return rn;
}
void print(INT a)
{
printf("%d",a.num[a.len]);
for(int i=a.len-1;i>=1;--i)
printf("%05d",a.num[i]);
}
int A[MAXN];
bool prim[MAXN];
INT f[MAXN];
int N,M;
void prime(int n)
{
N=0;
for(int i=2;i<=n;++i)
prim[i]=1;
for(int i=2;i<=n;++i)
if(prim[i])
{
A[++N]=i;
for(int j=i*2;j<=n;j+=i)
prim[j]=0;
}
}
int main()
{
scanf("%d",&M);
int i,j;
prime(M);
memset(f,0,sizeof(f));
f[0]=1;
for(i=1;i<=N;++i)
for(j=A[i];j<=M;++j)
f[j]=f[j]+f[j-A[i]];
print(f[M]);puts("");
}