zoukankan      html  css  js  c++  java
  • 2013长沙网络赛,Problem 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大的数x,如何通过素数相加或相乘得到,且必须符合如下两个规则

         规则1:最多只能使用三个素数,可以相同,不考虑顺序

         规则2:只能使用加法和乘法两种运算,乘法优先级高于加法,即当同时出现加法和乘法时,优先计算乘法

    解题思路

         这道题时间限制为8s,X最大为80000,做三个数的加法或乘法如果不优化,三重循环会超时,我们可以通过大素数表对其进行优化

         先打两张素数表:一张存放maxn以内的所有素数,便于枚举,通过一般打表方法得到;

                                一张标记maxn以内每个数是否为素数,便于判断素数情况,通过筛法求素数得到。

         再打第三张表:保存maxn以内每一个数通过两素数相乘得到的方法数,mul[i]表示所有通过两素数相乘得到i的方法数

         再进行一一运算:一个素数、两素数相加、三素数相加以及三素数相乘的情况很容积枚举,注意优化;

                               两素数相乘的情况通过查表获得;

                               两素数相乘再与一素数相加的情况,首先枚举第一个加的素数x,在查表获得mul[n-x]。

    具体代码如下

    /* 2013 ACM/ICPC Asia Regional Changsha Online
       Problem G:Goldbach
       Author:DZK
    */
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    
    const int maxn = 80010;
    int num[maxn], prime[maxn];
    int mul[maxn];
    bool Prime(int x)     //判断x是否为素数
    {
        for(int i = 2; i*i <= x; i++)
            if(x % i == 0)
                return false;
        return true;
    }
    void GetPrimeNum()     //保存maxn以内所有素数
    {
        int cnt = 0;
        for(int i = 2; i < maxn; i++)
            if(Prime(i))
                num[cnt++] = i;
    }
    void GetPrime()         //筛法求素数,若i为素数,prime[i]为true,否则我false
    {
        memset(prime, true, sizeof(prime));
        prime[0] = prime[1] = false;
        for(int i = 2; i <= maxn; i++)
            if(prime[i])
                for(int j = 2*i; j <= maxn; j += i)
                    prime[j] = false;
    }
    int main()
    {
        GetPrime();     //第一次打表
        GetPrimeNum();  //第二次打表
        int n;
        for(int i = 2; i <= maxn; i++)      //第三次打表,mul[i]表示所有通过两素数相乘得到i的方法数
        {
            for(int j = 0; num[j] <= sqrt(i); j++)
            {
                if(i % num[j] == 0 && prime[i/num[j]])
                        mul[i]++;
            }
        }
        while(scanf("%d", &n) != EOF)
        {
            int cnt = 0;
            if(prime[n])        //一个数
                cnt++;
            for(int i = 0; num[i] <= n/2; i++)         //两素数相加
                if(prime[n-num[i]])
                    cnt++;
            cnt += mul[n];         //两素数相乘
            for(int i = 0; num[i] <= n/3; i++)        //三素数相加
                for(int j = i; num[j] <= n*2/3; j++)
                {
                    int k = n - num[i]-num[j];
                    if(prime[k] && k >= num[j])
                        cnt++;
                }
            for(int i = 0; num[i]*num[i]*num[i] <= n; i++)       //三素数相乘
            {
                if(n % num[i] == 0)
                {
                    int m = n/num[i];
                    for(int j = i; num[j] <= sqrt(m); j++)
                    {
                        if(m % num[j] == 0)
                        {
                            int k = m/num[j];
                            if(prime[k] && k >= num[j])
                                cnt++;
                        }
                    }
                }
            }
            for(int i = 0; num[i] <= n; i++)           //两素数相乘再与一素数相加
            {
                int m = n-num[i];
                cnt+= mul[m];
            }
            printf("%d
    ", cnt);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    python子网拆分IP段
    动画制作库tween样例学习
    npm淘宝镜像
    nodejs webpack json 大文件,编译,out of memory
    python处理经过gzip压缩的网页内容
    判断百度某一经纬度的地图颜色值python
    考试总结及注意事项
    2152:聪聪可可(点分治)
    3687: 简单题(bitset)
    4514: [Sdoi2016]数字配对
  • 原文地址:https://www.cnblogs.com/dzkang2011/p/Prime.html
Copyright © 2011-2022 走看看