ZOJ Problem Set - G Goldbach

Goldbach

Time Limit: 8 Seconds      Memory Limit: 32768 KB

Fancy is learning mathematics recently. He's already mastered the use of multiplication and addition days before, so today he's going to learn prime number.

After reading the learning material, he's been asked to complete a simple test. He's been given an integer X larger than 1, using multiplication, addition and at most 3 prime numbers, how many ways could he get the answer as X exactly?

Since that Fancy is a new learner of mathematics, he's still not familiar with brackets. So in the calculation, the addition is always performed after multiplication.

Input

There will be multiple test cases. Each test case contains a single integer X (1 < X ≤ 80000) in one line.

Output

For each test case, please calculate the number of ways which Fancy could get the answer as X. Since that the number of ways might be large, please output it modulo 1000000007.

Sample Input
5
10
8
Sample Output
2
4
4
Hint

In the 3rd case, 8 = 2 * 2 * 2 = 2 + 2 * 3 = 2 + 3 + 3 = 3 + 5, so the answer is 4.

   比赛的时候为了想不计算重复,想了各种方法,比较绕,时间再多一点或许就过了。做距离的那个题时候,不知道为什么死在精度上了。耽误了时间。主要还是暴力。

  一个数由最多三个素数组成,只能用*或+

(1)当由一个素数组成的时候,看其本身是否是素数、

(2)当由两个素数组成的时候,暴力一个素数求另一个素数,有+和*两种情况。

(3)当由三个素数组成的时候,如果是三个素数相乘,暴力可以得到解决。

         如果是三个素数采用 a*b + c的方式,我们暴力c,我们把一个数由两个素数相乘的情况先求出来,sum[n]+=(b[n-c]),暴力c。

       如果是三个素数采用相加的形式即 n = a + b + c;      H:求两个素数(两个素数不相同)组成的和,然后再加入第三个素数.这时候会产生重复,记录一下一个数的情况数:H 想着办法去重就可以了。可以通过: <1>假设a,b,c完全相同很容易实现。<2>假设有两个相同,则枚举这个相同的。      <3>如果三个完全不同,由H: :H 暴力肯定会产生不满足的情况或重复的情况。所谓不满足的情况就是产生了由两个相同的素数,从s[n]中减去先前枚举出来(<2>中)的两个相同的情况。然后/3   就是三个完全不同的数。<1>+<2>+<3>得出三个素数相加情况。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define N 80010
#define mod 1000000007
using namespace std;
bool ch[N];
int a[N],one[N],two_a[N],two_b[N],three[N],sum[N];
int key[N],two_one[N],b[N];
int main()
{
   // freopen("data.in","w",stdout);
    memset(ch,true,sizeof(ch));
    ch[1]=false;
    for(int i=2;i<=80000;i++)
    {
        if(ch[i])
        {
            for(int j=2;i*j<=80000;j++)
            {
                ch[i*j] = false;
            }
        }
    }
    int Top =0;
    for(int i=2;i<=80000;i++)
    {
        if(ch[i])
        {
            a[Top++] = i;
        }
    }
    memset(one,0,sizeof(one));
    for(int i=2;i<=80000;i++)
    {
        if(ch[i])
        {
            one[i] +=1;
        }
    }
    memset(two_a,0,sizeof(two_a));
    for(int i=2;i<=80000;i++)
    {
        for(int j = 0;j<=Top-1;j++)
        {
            int x = a[j];
            int y = i-a[j];
            if(x<=y&&ch[y])
            {
                two_a[i]=(two_a[i]+1)%mod;
            }else if(x>y)
            {
                break;
            }
        }
    }
    memset(two_b,0,sizeof(two_b));
    for(int i=2;i<=80000;i++)
    {
        for(int j=0;j<=Top-1;j++)
        {
            int x = a[j];
            if(i%x!=0)
            {
                continue;
            }
            int y = i/x;
            if(x<=y&&ch[y])
            {
                two_b[i]=(two_b[i]+1)%mod;
            }else if(x>y)
            {
                break;
            }
        }
    }
    memset(three,0,sizeof(three));
    for(int i=2;i<=80000;i++)
    {
        for(int j=0;j<=Top-1;j++)
        {
            int x = a[j];
            if(x*x*x>i)
            {
                break;
            }
            for(int u = j;u<=Top-1;u++)
            {
                int y = a[u];
                if(x*y*y>i)
                {
                    break;
                }
                if(i%(x*y)!=0)
                {
                    continue;
                }
                int z = i/(x*y);
                if(z<y)
                {
                    break;
                }
                if(ch[z])
                {
                    three[i]=(three[i]+1)%mod;
                }
            }
        }
    }
    memset(two_one,0,sizeof(two_one));
    for(int i=2;i<=80000;i++)
    {
        for(int j=0;j<=Top-1;j++)
        {
            int x = a[j];
            if(i<=2*x)
            {
                break;
            }
            int y = i - 2*x;
            if(y!=x&&ch[y])
            {
                two_one[i]+=1;
            }
        }
    }
    memset(sum,0,sizeof(sum));
    for(int i=0;i<=Top-1;i++)
    {
        for(int j=i+1;j<=Top-1;j++)
        {
            if(a[i]+a[j]>80000)
            {
                break;
            }
            sum[a[i]+a[j]]+=1;
        }
    }
    memset(key,0,sizeof(key));
    for(int i=2;i<=80000;i++)
    {
        for(int j=0;j<=Top-1;j++)
        {
            int x = i + a[j];
            if(x<=80000)
            {
                key[x] = (key[x]+sum[i]);
            }
        }
    }
    for(int i=2;i<=80000;i++)
    {
        key[i]=(key[i]-two_one[i])/3;
        key[i]+=(two_one[i]);
    }
    for(int i=2;i<=80000;i++)
    {
        if(i>=6&&i%2==0)
        {
            three[i]=(three[i]+two_a[i-2])%mod;
        }else if(i>=7&&i%2)
        {
            three[i]=(three[i]+key[i])%mod;
            if(i%3==0&&ch[i/3])
            {
                three[i]+=1;  //三个素数全部相等
            }
        }
    }
    for(int i=2;i<=80000;i++)
    {
        for(int j = 0;j<=Top-1;j++)
        {
            int x = a[j];
            if(i<=x)
            {
                break;
            }
            three[i]=(three[i]+two_b[i-x])%mod;
        }
    }
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        int res = (((one[n]+two_a[n])%mod+two_b[n])%mod+three[n])%mod;
        printf("%d\n",res);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值