ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • polynomial
    232's competitive-programming templates. 2024. 9. 21. 21:32

    TODO : add ntt?

    template <typename T>
    using Polynomial = std::vector<T>;
    
    namespace polynomial {
      using F = long double;
      using complexF = std::complex<F>;
    
      constexpr F pi = 3.1415926535897932L;
    
      void fft(std::vector<complexF>& a) {
        int n = int(a.size());
        for (int i = 1, rev_i = 0; i < n; ++i) {
          for (int bit = n >> 1; ; bit >>= 1) {
            if (((rev_i ^= bit) & bit) != 0) {
              break;
            }
          }
          if (i < rev_i) {
            std::swap(a[i], a[rev_i]);
          }
        }
        for (int b = 1; b < n; b <<= 1) {
          F angle = pi / b;
          complexF w(std::cos(angle), std::sin(angle));
          for (int s = 0; s < n; s += b << 1) {
            complexF theta(1, 0); // for higher precision, use theta(std::cos(angle * i), std::sin(angle * i)) (slower)
            for (int i = 0; i < b; ++i) {
              std::tie(a[s + i], a[s + i + b]) = std::pair {a[s + i] + theta * a[s + i + b], a[s + i] - theta * a[s + i + b]};
              theta *= w;
            }
          }
        }
      }
    
      void ifft(std::vector<complexF>& a) {
        int n = int(a.size());
        std::reverse(std::next(a.begin()), a.end());
        fft(a);
        for (auto& x : a) {
          x /= n;
        }
      }
    
      template <typename T>
      Polynomial<T> multiply(const Polynomial<T>& a, const Polynomial<T>& b) {
        if (a.empty() || b.empty()) {
          return {};
        }
        int n = 1;
        while (n < int(a.size()) + int(b.size()) - 1) {
          n <<= 1;
        }
        std::vector<complexF> ca(n);
        std::copy(a.begin(), a.end(), ca.begin());
        std::vector<complexF> cb(n);
        std::copy(b.begin(), b.end(), cb.begin());
        fft(ca); fft(cb);
        for (int i = 0; i < n; ++i) {
          ca[i] *= cb[i];
        }
        ifft(ca);
        Polynomial<T> res(a.size() + b.size() - 1);
        for (int i = 0; i < int(a.size()) + int(b.size()) - 1; ++i) {
          res[i] = std::llround(ca[i].real());
        }
        return res;
      }
    } // namespace polynomial
    
    template <typename T>
    Polynomial<T> operator+(const Polynomial<T>& a, const Polynomial<T>& b) {
      Polynomial<T> res(std::max(a.size(), b.size()));
      for (int i = 0; i < int(a.size()); ++i) {
        res[i] += a[i];
      }
      for (int i = 0; i < int(b.size()); ++i) {
        res[i] += b[i];
      }
      return res;
    }
    
    template <typename T>
    Polynomial<T> operator-(const Polynomial<T>& a, const Polynomial<T>& b) {
      Polynomial<T> res(std::max(a.size(), b.size()));
      for (int i = 0; i < int(a.size()); ++i) {
        res[i] += a[i];
      }
      for (int i = 0; i < int(b.size()); ++i) {
        res[i] -= b[i];
      }
      return res;
    }
    
    template <typename T>
    Polynomial<T>& operator+=(Polynomial<T>& a, const Polynomial<T>& b) {
      a.resize(std::max(a.size(), b.size()));
      for (int i = 0; i < int(b.size()); ++i) {
        a[i] += b[i];
      }
      return a;
    }
    
    template <typename T>
    Polynomial<T>& operator-=(Polynomial<T>& a, const Polynomial<T>& b) {
      a.resize(std::max(a.size(), b.size()));
      for (int i = 0; i < int(b.size()); ++i) {
        a[i] -= b[i];
      }
      return a;
    }
    
    template <typename T>
    Polynomial<T> operator*(const Polynomial<T>& a, const Polynomial<T>& b) {
      return polynomial::multiply(a, b);
    }
    
    template <typename T>
    Polynomial<T>& operator*=(Polynomial<T>& a, const Polynomial<T>& b) {
      return a = a * b;
    }

    '232's competitive-programming templates.' 카테고리의 다른 글

    MinMaxPQ  (1) 2024.10.03
    Centroid, CentroidTree  (0) 2024.09.26
    lcs_algo  (0) 2024.09.17
    Trie  (1) 2024.09.16
    OfflineDynamicConnectivity  (0) 2024.09.16
Designed by Tistory.