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; }