问题 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
提示
【数据规模】
对于40%的数据 N<=200
对于100%的数据 N<=2000
这是一个套完全背包模板的题。。
先筛出2000内所有素数
作为元素来塞背包
看最后有多少塞法
答案会爆unsigned long long
于是使用高精度。
代码:
#include<cstdio>
#include<cstring>
#define PRIMEL 2200
#define ULL unsigned long long
bool vis[PRIMEL];
int prime[PRIMEL],tot=1;
inline int max(int a,int b){return a>b?a:b;}
void phi(){
int tmp=(PRIMEL+1)/2;
for(int i=2;i<=tmp;i++)
if(!vis[i])for(int j=i+i;j<PRIMEL;j+=i)vis[j]=true;
for(int i=2;i<PRIMEL;i++)
if(!vis[i])prime[tot++]=i;
}
struct Num{
char s[100];
int len;
Num(){len=0;memset(s,0,sizeof s);}
Num(const Num&a){
memcpy(s,a.s,sizeof s);
len=a.len;
}
void print(){
for(int i=len-1;i>=0;i--)
putchar(s[i]+'0');
}
};
Num operator+(Num a,Num b){
Num ret;
int len=max(b.len,a.len);
for(int i=0;i<len;i++){
ret.s[i]+=a.s[i]+b.s[i];
ret.s[i+1]=ret.s[i]/10;
ret.s[i]%=10;
}
if(ret.s[len])len++;
ret.len=len;
return ret;
}
int n;
Num f[2200];
int main(){
f[0].len=1;
f[0].s[0]=1;
phi();
scanf("%d",&n);
for(int i=1;i<tot&&prime[i]<=n;i++)
for(int j=prime[i];j<=n;j++)
f[j]=f[j-prime[i]]+f[j];
f[n].print();
}