algorithm-dev

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub today2098/algorithm-dev

:heavy_check_mark: verify/aoj-ITP1_1_A-fast_fourier_transform.test.cpp

Depends on

Code

#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/courses/lesson/2/ITP1/1/ITP1_1_A"

#include <cassert>
#include <cmath>
#include <iostream>
#include <random>
#include <vector>

#include "../algorithm/Math/Convolution/fast_fourier_transform.hpp"

int main() {
    constexpr int t = 100;
    std::random_device seed;
    std::mt19937_64 rng(seed());

    constexpr double eps = 1e-6;
    std::uniform_int_distribution<int> uniform_n(1, 200);
    std::uniform_real_distribution<double> uniform(-1e3, 1e3);
    for(int i = 0; i < t; ++i) {
        const int n = uniform_n(rng), m = uniform_n(rng);
        std::vector<double> a(n), b(m);
        for(auto &elem : a) elem = uniform(rng);
        for(auto &elem : b) elem = uniform(rng);

        auto &&target = algorithm::fft::convolve(a, b);
        auto &&want = algorithm::fft::convolve_naive(a, b);

        assert(target.size() == size_t(n + m - 1));
        assert(want.size() == size_t(n + m - 1));
        for(int j = 0; j < n + m - 1; ++j) assert(std::abs(target[j] - want[j]) < eps);
    }

    std::cout << "Hello World" << std::endl;
}
#line 1 "verify/aoj-ITP1_1_A-fast_fourier_transform.test.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/courses/lesson/2/ITP1/1/ITP1_1_A"

#include <cassert>
#include <cmath>
#include <iostream>
#include <random>
#include <vector>

#line 1 "algorithm/Math/Convolution/fast_fourier_transform.hpp"



/**
 * @brief Fast Fourier Transform(高速フーリエ変換)
 * @docs docs/Math/Convolution/fast_fourier_transform.md
 */

#include <algorithm>
#line 12 "algorithm/Math/Convolution/fast_fourier_transform.hpp"
#include <complex>
#include <type_traits>
#include <utility>
#line 16 "algorithm/Math/Convolution/fast_fourier_transform.hpp"

namespace algorithm {

namespace fft {

using D = double;

const D PI = std::acos(-1.0);

// Fast Fourier Transform(高速フーリエ変換).
// 引数の数列の長さは2のべき乗であること.O(N*logN).
void transform(std::vector<std::complex<D> > &a, bool inv = false) {
    const int n = a.size();
    if(n == 0) return;
    int lb = 0;  // lb:=log2(n).
    while(1 << lb < n) lb++;
    assert(n == 1 << lb);
    for(int i = 0; i < n; ++i) {
        int j = 0;
        for(int k = 0; k < lb; ++k) j |= (i >> k & 1) << (lb - 1 - k);
        if(i < j) std::swap(a[i], a[j]);
    }
    for(int b = 1; b < n; b <<= 1) {
        D ang = PI / b;
        if(inv) ang = -ang;
        for(int i = 0; i < b; ++i) {
            std::complex<D> &&w = std::polar<D>(1.0, ang * i);
            for(int j = 0; j < n; j += b << 1) {
                std::complex<D> &&tmp = a[i + j + b] * w;
                a[i + j + b] = a[i + j] - tmp;
                a[i + j] += tmp;
            }
        }
    }
    if(inv) {
        for(int i = 0; i < n; ++i) a[i] /= n;
    }
}

// 畳み込み.
// 数列a[], b[]に対して,c[i]=sum_{k=0}^{i} a[k]*b[i-k] となる数列c[]を求める.O(N^2).
template <typename Type>
std::vector<Type> convolve_naive(const std::vector<Type> &a, const std::vector<Type> &b) {
    const int n = a.size(), m = b.size();
    if(n == 0 or m == 0) return std::vector<Type>();
    std::vector<Type> res(n + m - 1, 0);
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < m; ++j) res[i + j] += a[i] * b[j];
    }
    return res;
}

// 畳み込み.
// 数列a[], b[]に対して,c[i]=sum_{k=0}^{i} a[k]*b[i-k] となる数列c[]を求める.O(N*logN).
template <typename Type, typename std::enable_if_t<std::is_integral_v<Type>, bool> = false>
std::vector<Type> convolve(const std::vector<Type> &a, const std::vector<Type> &b) {
    if(a.size() == 0 or b.size() == 0) return std::vector<Type>();
    const int n = a.size() + b.size() - 1;
    int m = 1;
    while(m < n) m <<= 1;
    std::vector<std::complex<D> > na(m, 0.0), nb(m, 0.0);
    std::copy(a.begin(), a.end(), na.begin());
    std::copy(b.begin(), b.end(), nb.begin());
    transform(na), transform(nb);
    for(int i = 0; i < m; ++i) na[i] *= nb[i];
    transform(na, true);
    std::vector<Type> res(n);
    for(int i = 0; i < n; ++i) res[i] = na[i].real() + (na[i].real() < 0.0 ? -0.5 : 0.5);
    return res;
}

// 畳み込み.
// 数列a[], b[]に対して,c[i]=sum_{k=0}^{i} a[k]*b[i-k] となる数列c[]を求める.O(N*logN).
template <typename Type, typename std::enable_if_t<std::is_floating_point_v<Type>, bool> = false>
std::vector<Type> convolve(const std::vector<Type> &a, const std::vector<Type> &b) {
    if(a.size() == 0 or b.size() == 0) return std::vector<Type>();
    const int n = a.size() + b.size() - 1;
    int m = 1;
    while(m < n) m <<= 1;
    std::vector<std::complex<D> > na(m, 0.0), nb(m, 0.0);
    std::copy(a.begin(), a.end(), na.begin());
    std::copy(b.begin(), b.end(), nb.begin());
    transform(na), transform(nb);
    for(int i = 0; i < m; ++i) na[i] *= nb[i];
    transform(na, true);
    std::vector<Type> res(n);
    for(int i = 0; i < n; ++i) res[i] = na[i].real();
    return res;
}

}  // namespace fft

}  // namespace algorithm


#line 10 "verify/aoj-ITP1_1_A-fast_fourier_transform.test.cpp"

int main() {
    constexpr int t = 100;
    std::random_device seed;
    std::mt19937_64 rng(seed());

    constexpr double eps = 1e-6;
    std::uniform_int_distribution<int> uniform_n(1, 200);
    std::uniform_real_distribution<double> uniform(-1e3, 1e3);
    for(int i = 0; i < t; ++i) {
        const int n = uniform_n(rng), m = uniform_n(rng);
        std::vector<double> a(n), b(m);
        for(auto &elem : a) elem = uniform(rng);
        for(auto &elem : b) elem = uniform(rng);

        auto &&target = algorithm::fft::convolve(a, b);
        auto &&want = algorithm::fft::convolve_naive(a, b);

        assert(target.size() == size_t(n + m - 1));
        assert(want.size() == size_t(n + m - 1));
        for(int j = 0; j < n + m - 1; ++j) assert(std::abs(target[j] - want[j]) < eps);
    }

    std::cout << "Hello World" << std::endl;
}
Back to top page