Goldbach (2013长沙网赛G)

题意很简单,就是给你一个数x(x <= 80000),然后问你用最多三个素数(可以相同)加上两种运算符号(+ 和 *)有几种组合构成这个数x。

思路 : 因为x小于8W,2 ~ 8W中大概有8K左右个素数,配对方式大概有6中 : a 、a  * b、 a * b * c、 a + b 、a + b * c 、 a + b + c。其实稍微考虑下就知道了复杂度和难点是在枚举a + b + c上。我的做法是先预处理出一个add数组(由两个不同的素数相加最多有几种方式), 然后O(n)枚举剩下一个,然后再去考虑下 a + a + b 和 a + a + a,就可以算出答案来了的。

 

给出代码 :

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int MAXN = 80008;
const int mod = 1000000007;

int X,M;
bool Prime[MAXN],mul[MAXN];
int prime[MAXN],add[MAXN];

int Isprime(int x)
{
      for (int i = 2;i * i <= x;i++)if (x % i == 0)
            return 0;
      return 1;
}


void init()
{
      M = 0;
      memset(add,0,sizeof(add));
      memset(Prime,0,sizeof(Prime));
      memset(mul,0,sizeof(mul));
      for (int i = 2;i <= MAXN;i++)if (Isprime(i))
      {
            prime[++M] = i;
            Prime[i] = 1;
      }
      for (int i = 1;i <= M;i++)
            for (int j = i + 1;j <= M;j++)
            {
                  if (prime[i] + prime[j] >= MAXN)break;
                  add[prime[i] + prime[j]] ++;
            }
      for (int i = 1;i <= M;i++)
            for (int j = i ;j <= M;j++)
            {
                  if ((LL)prime[i] * prime[j] >= MAXN)break;
                  mul[prime[i] * prime[j]] = 1;
            }
}

// 这个函数主要是用来求a 、 a * b 、 a * b * c,返回值只可能是1 或 0
int get()
{
      if (Prime[X])return 1;
      if (mul[X])return 1;
      int tmp = X;
      int cnt = 0;
      for (int i = 1;i <= M;i++)
      {
            while (tmp % prime[i] == 0 && tmp > 1)
            {
                  tmp /= prime[i];
                  cnt ++;
                  if (cnt > 3)return 0;
            }
            if (tmp <= 1)
            {
                  if (cnt <= 3)return 1;
                  else return 0;
            }
      }
}

int solve()
{
      LL ans = get();
      LL res = 0;
      //求出 a + b 和 a + b * c 
      for (int i = 1;i <= M;i++)
      {
            int e = X - prime[i];
            if (e <= 0)break;
            if (Prime[e])res += (e == prime[i] ? 2 : 1);//注意a + a 这种情况
            else ans += mul[e];
      }
      ans += res / 2;
      ans %= mod;
      res = 0;
      //求出 a + b + c
      for (int i = 1;i <= M;i++)
      {
            int e = X - prime[i];
            if (e <= 0)break;
            res += add[e];
      }
      for (int i = 1;i <= M;i++)
      {
            int e = X - prime[i];
            if (e <= 0)break;
            if (e % 2 == 0 && Prime[e/2])
            {
                  if (e/2 == prime[i])continue;
                  ans ++;
                  res -= 1; //把一些重复枚举的删除
            }
      }
      ans += (res/3);
      ans %= mod;
      if (X % 3 == 0 && Prime[X/3])ans++;//考虑a + a + a这种情况
      return (int)(ans % mod);
}

int main()
{
      init();
      while (scanf("%d",&X) != EOF)
      {
            printf("%d\n",solve());
      }
      return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值