mrlolthe1st

Fast factorial computation

Nov 9th, 2021
2,560
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.76 KB | None | 0 0
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #pragma GCC Optimize("Ofast")
  3. #include <string.h>
  4. #include <iostream>
  5. #include <vector>
  6. #include <set>
  7. #include <chrono>
  8. #include <string>
  9. #include <time.h>
  10. #include <unordered_set>
  11. #include <iomanip>
  12. #include <cmath>
  13. #include <map>
  14. #include <queue>
  15. #include <numeric>
  16. #include <unordered_map>
  17. #include <algorithm>
  18. #include <fstream>
  19. #include <sstream>
  20. #include <cstddef>
  21. #include <cstdio>
  22. #include <iostream>
  23. #include <memory>
  24. #include <stdexcept>
  25. #include <string>
  26. #include <cmath>
  27. #include <complex>
  28. #include <array>
  29. using namespace std;
  30. typedef long long ll;
  31. const int maxn = 1e2 + 14, lg = 15;
  32.  
  33. const int BASE = 3e3;
  34. int64_t count_ops = 0;
  35. const double PI = acos(-1);
  36. typedef complex<double> base;
  37.  
  38. double SIN[1000000];
  39. #define MAXN 10000000
  40.  
  41. void fft(vector<base>& a, bool invert) {
  42.     int n = (int)a.size();
  43.  
  44.     for (int i = 1, j = 0; i < n; ++i) {
  45.         int bit = n >> 1;
  46.         for (; j >= bit; bit >>= 1)
  47.             j -= bit;
  48.         j += bit;
  49.         if (i < j)
  50.             swap(a[i], a[j]);
  51.     }
  52.  
  53.     for (int len = 2; len <= n; len <<= 1) {
  54.         double ang = 2 * PI / len * (invert ? -1 : 1);
  55.         base wlen(cos(ang), sin(ang));
  56.         for (int i = 0; i < n; i += len) {
  57.             base w(1);
  58.             for (int j = 0; j < len / 2; ++j) {
  59.                 base u = a[i + j], v = a[i + j + len / 2] * w;
  60.                 a[i + j] = u + v;
  61.                 a[i + j + len / 2] = u - v;
  62.                 w *= wlen;
  63.             }
  64.         }
  65.     }
  66.     if (invert)
  67.         for (int i = 0; i < n; ++i)
  68.             a[i] /= n;
  69. }
  70.  
  71. vector<int> multiply(const vector<int>& a, const vector<int>& b) {
  72.     vector<base> fa(a.begin(), a.end()), fb(b.begin(), b.end());
  73.     size_t n = 1;
  74.     while (n < max(a.size(), b.size()))  n <<= 1,
  75.         ++count_ops;
  76.     n <<= 1;
  77.     fa.resize(n), fb.resize(n);
  78.  
  79.     fft(fa, false), fft(fb, false);
  80.     for (size_t i = 0; i < n; ++i)
  81.         fa[i] *= fb[i],
  82.         ++count_ops;
  83.     fft(fa, true);
  84.     vector<long long> res(n);
  85.     for (size_t i = 0; i < n; ++i) {
  86.         res[i] = (long long)(fa[i].real() + 0.5),
  87.             ++count_ops;
  88.         if (res[i] < 0 || res[i] > 1e15) {
  89.             cout << -1;
  90.             res[i] = res[i];
  91.         }
  92.     }
  93.     int carry = 0;
  94.     for (size_t i = 0; i < n; ++i) {
  95.         res[i] += carry;
  96.         carry = res[i] / BASE;
  97.         ++count_ops;
  98.         res[i] %= BASE;
  99.     }
  100.     vector<int> r2(res.begin(), res.end());
  101.     while (r2.size() && r2.back() == 0) r2.pop_back();
  102.     if (!r2.size()) r2.push_back(0);
  103.     return r2;
  104. }
  105.  
  106. #define typ vector<int>
  107.  
  108. const int N = 1000000;
  109. int lp[N + 1];
  110. vector<int> pr;
  111.  
  112. typ prod(vector<typ>& a, int l, int r) {
  113.     if (l > r) return { 1 };
  114.     if (l == r) return { a[l] };
  115.     if (r - l == 1) return multiply(a[l], a[r]);
  116.     return multiply(prod(a, l, (l + r) >> 1), prod(a, ((l + r) >> 1) + 1, r));
  117. }
  118.  
  119. typ primeSwing(int n) {
  120.     vector<typ> mult;
  121.     for (int i = 0; pr[i] <= n; ++i) {
  122.         int q = n;
  123.         typ prime = { pr[i] };
  124.         typ val = { 1 };
  125.         while (q) {
  126.             q /= pr[i];
  127.             if (q & 1) {
  128.                 val = multiply(val, prime);
  129.             }
  130.         }
  131.         if (prime.size() > 1 || prime[0] != 1) {
  132.             mult.push_back(val);
  133.         }
  134.     }
  135.     return prod(mult, 0, mult.size() - 1);
  136. }
  137.  
  138. typ factorial(int n) {
  139.     if (n < 2) {
  140.         return { 1 };
  141.     }
  142.     typ f = factorial(n / 2);
  143.     return multiply(multiply(f, f), primeSwing(n));
  144. }
  145.  
  146. void sieve() {
  147.     for (int i = 2; i <= N; ++i) {
  148.         if (lp[i] == 0) {
  149.             lp[i] = i;
  150.             pr.push_back(i);
  151.         }
  152.         for (int j = 0; j < (int)pr.size() && pr[j] <= lp[i] && i * pr[j] <= N; ++j)
  153.             lp[i * pr[j]] = pr[j];
  154.     }
  155. }
  156.  
  157. signed main() {
  158.     cin.tie(0);
  159.     cout.tie(0);
  160.     ios::sync_with_stdio(false);
  161.     sieve();
  162.     std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
  163.     auto it = factorial(100000);
  164.  
  165.     cout << it.size() * 3;
  166.     std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
  167.     std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() << "[µs]" << std::endl;
  168.     cout << count_ops;
  169.  
  170. }
Advertisement
Add Comment
Please, Sign In to add comment