【FFT】ZOJ 3856 Goldbach

通道:http://acm.zju.edu.cn/onlinejudge/showProBlem.do?proBlemCode=3856

题意:最多使用三个素数做加法和乘法(无括号),问得到X有多少种方案

思路:

6种情况:

1、A,O(1)判断

2、A+B, FFT处理

3、A*B,lgN*lgN判断

4、A*B*C,lgN*lgN*lgN判断

5、A*B+C,有A*B+C=N,可判断N-C是否在情况3出现过

6、A+B+C,利用之前预处理出来的A+B的种数[记住这里去掉A=B的情况, 并且考虑的是A, B的组合而不是排列(我们假设A < B], 将这个计数的多项式和素数的多项式相乘, 得到的结果当中, 计算了一次A, B, C中有两个相等的情况[A=C或B = C,也就是说有两个数相同的算了一次];三个都不同的算了三次, 分别是(A, B, C), (A, C, B), (B, C, A), [注意前面我们考虑的是组合, 所以(A, B, C)和(B, A, C)一样, 只算一个],所以对于三个都不同的情况要除3。

计算6这种方法,有个特殊的技巧,那就是(s[i]+2*tmp[i])/3,全不相同和全相同可以很好理解,对于其中有2个相同的,可以理解为(1+2*1)/3 也去重了

 

代码:

  1 #include <cstdio>
  2 #include <cmath>
  3 #include <cstring>
  4 #include <vector>
  5 #include <algorithm>
  6 
  7 using namespace std;
  8 
  9 typedef long long ll;
 10 
 11 const ll MAX_N = 80007; 
 12 const ll MAX_M = 100007;
 13 const double PI = acos(-1.0);
 14 
 15 struct Complex {
 16     double r, i;
 17     Complex(double _r, double _i) {
 18         r = _r;
 19         i = _i;
 20     }
 21     Complex operator + (const Complex &c) {
 22         return Complex(c.r + r, c.i + i);
 23     }
 24     Complex operator - (const Complex &c) {
 25         return Complex(r - c.r, i - c.i);
 26     }
 27     Complex operator * (const Complex &c) {
 28         return Complex(c.r * r - c.i * i, c.r * i + c.i * r);
 29     }
 30     Complex operator / (const int &c) {
 31         return Complex(r / c, i / c);
 32     }
 33     Complex(){}
 34 };
 35 namespace FFT {
 36     int rev(int id, int len) {
 37         int ret = 0;
 38         for(int i = 0; (1 << i) < len; ++i) {
 39             ret <<= 1;
 40             if(id & (1 << i)) ret |= 1;
 41         }
 42         return ret;
 43     }
 44     Complex A[MAX_M << 3];
 45     void FFT(Complex *a, int len, int DFT) {
 46         for(int i = 0; i < len; ++i) A[rev(i, len)] = a[i];
 47         for(int s = 1; (1 << s) <= len; ++s) {
 48             int m = (1 << s);
 49             Complex wm = Complex(cos(PI * DFT * 2 / m), sin(PI * DFT * 2 / m));
 50             for(int k = 0; k < len; k += m) {
 51                 Complex w = Complex(1, 0);
 52                 for(int j = 0; j < (m >> 1); j++) {
 53                     Complex t = w * A[k + j + (m >> 1)];
 54                     Complex u = A[k + j];
 55                     A[k + j] = u + t;
 56                     A[k + j + (m >> 1)] = u - t;
 57                     w = w * wm;
 58                 }
 59             }
 60         }
 61         if(DFT == -1) for(int i = 0; i < len; ++i) A[i] = A[i] / len;
 62         for(int i = 0; i < len; i++) a[i] = A[i];
 63     }
 64 };
 65 
 66 bool p[MAX_N];
 67 ll prime[MAX_N], primeCnt;
 68 Complex A[MAX_M << 3], B[MAX_M << 3];
 69 ll s2[MAX_N], s3[MAX_N], s4[MAX_N], s5[MAX_N], tmp[MAX_N];
 70 /* 
 71 s2 : a * b
 72 s3 : a * b * c
 73 s4 : a + b
 74 s5 : a + b + c
 75 s6 : a * b + c
 76 tmp: 至少2个数相同 
 77 */
 78 void init() {
 79     memset(p, 1, sizeof p);
 80     p[0] = p[1] = false; primeCnt = 0;
 81     for (int i = 2; i < MAX_N; ++i) {
 82         if (p[i]) {
 83             prime[primeCnt++] = i;
 84             for (int j = i * 2; j < MAX_N; j += i)
 85                 p[j] = false;
 86         }
 87     }
 88     for (int i = 0; i < primeCnt && prime[i] * prime[i] < MAX_N; ++i) 
 89         for (int j = i; j < primeCnt && prime[i] * prime[j] < MAX_N; ++j) {
 90             ++s2[prime[i] * prime[j]];
 91             for (int k = j; k < primeCnt && prime[i] * prime[j] * prime[k] < MAX_N; ++k) 
 92                 ++s3[prime[i] * prime[j] * prime[k]];
 93         }
 94     int len = 1;
 95     while (len <= MAX_N) len <<= 1; len <<= 1;
 96     for (int i = 0; i < MAX_N; ++i) if (p[i]) A[i] = Complex(1, 0);
 97     else A[i] = Complex(0, 0);
 98     for (int i = MAX_N; i < len; ++i) A[i] = Complex(0, 0);
 99     FFT::FFT(A, len, 1);
100     for (int i = 0; i < len; ++i) A[i] = A[i] * A[i];
101     FFT::FFT(A, len, -1);
102     for (int i = 0; i < MAX_N; ++i) s4[i] = (ll) (A[i].r + 0.5);
103     for (int i = 0; i < primeCnt && prime[i] * 2 < MAX_N; ++i) --s4[prime[i] * 2];
104     for (int i = 0; i < MAX_N; ++i) s4[i] >>= 1;
105     for (int i = 0; i < MAX_N; ++i) A[i] = Complex(s4[i], 0);
106     for (int i = MAX_N; i < len; ++i) A[i] = Complex(0, 0);
107     for (int i = 0; i < MAX_N; ++i) if (p[i]) B[i] = Complex(1, 0);
108     else B[i] = Complex(0, 0);
109     for (int i = MAX_N; i < len; ++i) B[i] = Complex(0, 0);
110     FFT::FFT(A, len, 1); FFT::FFT(B, len, 1);
111     for (int i = 0; i < len; ++i) A[i] = A[i] * B[i];
112     FFT::FFT(A, len, -1);
113     for (int i = 0; i < primeCnt; ++i) {
114         for (int j = 0; j < primeCnt && prime[i] * 2 + prime[j] < MAX_N; ++j) {
115             ++tmp[prime[i] * 2 + prime[j]];
116         }
117     }
118     for (int i = 0; i < MAX_N; ++i) {
119         s5[i] = (ll) (A[i].r + 0.5);
120         s5[i] = (s5[i] + tmp[i] * 2) / 3;
121     }
122     for (int i = 0; i < primeCnt && prime[i] * 2 < MAX_N; ++i) {
123         ++s4[prime[i] * 2];
124         if (prime[i] * 3 < MAX_N) ++s5[prime[i] * 3];
125     }
126 }
127 
128 int n;
129 
130 int main() {
131     init();
132     while (1 == scanf("%d", &n)) {
133         ll ans = 0; if (p[n]) ++ans;
134         ans = ans + s2[n] + s3[n] + s4[n] + s5[n];
135         // cal s6 
136         for (int i = 0; i < primeCnt && prime[i] <= n; ++i) 
137             ans += s2[n - prime[i]];
138         printf("%lld\n", ans);
139     }
140     return 0;
141 }
View Code

 

posted @ 2015-07-24 16:09  mithrilhan  阅读(218)  评论(0编辑  收藏  举报