题目:http://acm.zju.edu.cn/changsha/showProblem.do?problemId=28
题意:给一个数n,范围是[2,80000],使用加,乘运算和最多3个素数,有多少种方法使得结果恰好等于n。
分析:先素数筛选,然后我们可以看出,设有3个素数a,b,c,那么有如下几种情况。
a + b + c = n;
a + b = n;
a + b*c = n;
a*b = n;
a*b*c = n;
a = n;
那么我们可以用背包的思想来预处理,然后询问即可。
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
const int N = 80005;
const int MOD = 1000000007;
bool prime[N];
int p[N],cnt;
int dp1[N][4],dp2[N][4];
void isprime()
{
cnt = 0;
int i,j;
memset(prime,true,sizeof(prime));
for(i=2;i<N;i++)
{
if(prime[i])
{
p[cnt++] = i;
for(j=i+i;j<N;j+=i)
{
prime[j]=false;
}
}
}
}
void Work()
{
dp1[0][0] = 1;
dp2[1][0] = 1;
for(int i=0; i<cnt; i++)
{
for(int j=0; j<N&&p[i]+j<N; j++)
{
for(int k=0; k<=2; k++)
dp1[j+p[i]][k+1] = (dp1[j+p[i]][k+1] + dp1[j][k]) % MOD;
}
}
for(int i=0; i<cnt; i++)
{
for(int j=0; j<N && p[i]*j<N; j++)
{
for(int k=0; k<=2; k++)
dp2[j*p[i]][k+1] = (dp2[j*p[i]][k+1] + dp2[j][k]) % MOD;
}
}
for(int i=0; i<cnt; i++)
{
for(int j=0; j<N&&j+p[i]<N; j++)
dp1[j+p[i]][3] = (dp1[j+p[i]][3] + dp2[j][2]) % MOD;
}
}
int main()
{
isprime();
Work();
int n;
while(~scanf("%d",&n))
{
int ans = 0;
for(int i=1; i<=3; i++)
{
ans = (ans+dp1[n][i]) % MOD;
if (i != 1)
ans = (ans+dp2[n][i]) % MOD;
}
printf("%d\n",ans);
}
return 0;
}