2013年长沙网络赛G题

题目: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;
}


 

你可能感兴趣的:(2013年长沙网络赛G题)