Submission #7143619


Source Code Expand

//整数列a[i],b[i]から列c[k]=sum{a[i]*b[k-i]}を生成する.任意modに対応.O(NlogN).
//NTT_CONVOLUTION_TIME を適切に変更するのを忘れない
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <string>
#include <math.h>
#include <iomanip>
#include <limits>
#include <list>
#include <queue>
#include <tuple>
#include <map>
#include <stack>
#include <set>
#include <complex>
using namespace std;
#define MOD (long long int)(1e9+7)
#define ll long long int
#define rep(i,n) for(int i=0; i<(int)(n); i++)
#define reps(i,n) for(int i=1; i<=(int)(n); i++)
#define REP(i,n) for(int i=n-1; i>=0; i--)
#define REPS(i,n) for(int i=n; i>0; i--)
#define INF (int)(1123456789)
#define LINF (long long int)(112345678901234567)
#define chmax(a, b) a = (((a)<(b)) ? (b) : (a))
#define chmin(a, b) a = (((a)>(b)) ? (b) : (a))
#define all(v) v.begin(), v.end()

std::vector<int> tmp;
size_t sz = 1;

inline int powMod(int n, int p, int m) {
    int res = 1;
    while (p) {
        if (p & 1) res = (ll)res * n % m;
        n = (ll)n * n % m;
        p >>= 1;
    }
    return (int)res;
}
inline int invMod(int n, int m) {
    return powMod(n, m - 2, m);
}

template <int Mod, int PrimitiveRoot>
struct NTTPart {
    static std::vector<int> ntt(std::vector<int> a, bool inv = false) {
        size_t mask = sz - 1;
        size_t p = 0;
        for (size_t i = sz >> 1; i >= 1; i >>= 1) {
            auto& cur = (p & 1) ? tmp : a;
            auto& nex = (p & 1) ? a : tmp;
            int e = powMod(PrimitiveRoot, (Mod - 1) / sz * i, Mod);
            if (inv) e = invMod(e, Mod);
            int w = 1;
            for (size_t j = 0; j < sz; j += i) {
                for (size_t k = 0; k < i; ++k) {
                    nex[j + k] = (cur[((j << 1) & mask) + k] + (ll)w * cur[(((j << 1) + i) & mask) + k]) % Mod;
                }
                w = (ll)w * e % Mod;
            }
            ++p;
        }
        if (p & 1) std::swap(a, tmp);
        if (inv) {
            int invSz = invMod(sz, Mod);
            for (size_t i = 0; i < sz; ++i) a[i] = (ll)a[i] * invSz % Mod;
        }
        return a;
    }
    static std::vector<int> mul(std::vector<int> a, std::vector<int> b) {
        a = ntt(a);
        b = ntt(b);
        for (size_t i = 0; i < sz; ++i) a[i] = (ll)a[i] * b[i] % Mod;
        a = ntt(a, true);
        return a;
    }
};

constexpr int M[] = {1224736769, 469762049, 167772161};
constexpr int PR[] = {3, 3, 3};
constexpr int NTT_CONVOLUTION_TIME = 3;
/*
    X := max(a)*max(b)*min(|a|, |b|) のとき,
    NTT_CONVOLUTION_TIME <- 1: X <         1224736769 = 1.2*10^ 9 ~ 2^30
    NTT_CONVOLUTION_TIME <- 2: X < 575334854091079681 = 5.8*10^17 ~ 2^59
    NTT_CONVOLUTION_TIME <- 3: X < 2^86 (32bit * 32bit * 10^7くらいまで)
*/

inline void garner(std::vector<int> *c, int mod) {
    if (NTT_CONVOLUTION_TIME == 1) {
        for(auto& x : c[0]) x %= mod;
    }
    else if (NTT_CONVOLUTION_TIME == 2) {
        const int r01 = invMod(M[0], M[1]);
        for (size_t i = 0; i < sz; ++i) {
            c[1][i] = (c[1][i] - c[0][i]) * (ll)r01 % M[1];
            if (c[1][i] < 0) c[1][i] += M[1];
            c[0][i] = (c[0][i] + (ll)c[1][i] * M[0]) % mod;
        }
    }
    else if (NTT_CONVOLUTION_TIME == 3) {
        const int R01 = invMod(M[0], M[1]);
        const int R02 = invMod(M[0], M[2]);
        const int R12 = invMod(M[1], M[2]);
        const int M01 = (ll)M[0] * M[1] % mod;
        for (size_t i = 0; i < sz; ++i) {
            c[1][i] = (c[1][i] - c[0][i]) * (ll)R01 % M[1];
            if (c[1][i] < 0) c[1][i] += M[1];
            c[2][i] = ((c[2][i] - c[0][i]) * (ll)R02 % M[2] - c[1][i]) * R12 % M[2];
            if (c[2][i] < 0) c[2][i] += M[2];
            c[0][i] = (c[0][i] + (ll)c[1][i] * M[0] + (ll)c[2][i] * M01) % mod;
        }
    }
}
std::vector<int> mul(std::vector<int> a, std::vector<int> b, int mod) {
    for (auto& x : a) x %= mod;
    for (auto& x : b) x %= mod;

    size_t m = a.size() + b.size() - 1;
    sz = 1;
    while (m > sz) sz <<= 1;
    tmp.resize(sz);
    a.resize(sz, 0);
    b.resize(sz, 0);

    std::vector<int> c[NTT_CONVOLUTION_TIME];
    if (NTT_CONVOLUTION_TIME >= 1) c[0] = NTTPart<M[0], PR[0]>::mul(a, b);
    if (NTT_CONVOLUTION_TIME >= 2) c[1] = NTTPart<M[1], PR[1]>::mul(a, b);
    if (NTT_CONVOLUTION_TIME >= 3) c[2] = NTTPart<M[2], PR[2]>::mul(a, b);
    for (auto& v : c) v.resize(m);
    garner(c, mod);
    return c[0];
}

int main(void){
    int n; cin>>n;
    vector<int> A,B,C;
    A.push_back(0);
    B.push_back(0);
    rep(i,n){
        int a,b; cin>>a>>b;
        A.push_back(a);
        B.push_back(b);
    }
    //NTT_CONVOLUTION_TIMEを変更するのを忘れない
    C = mul(A,B,MOD);
    reps(i,2*n){
        cout<<C[i]<<endl;
    }
    return 0;
}

Submission Info

Submission Time
Task C - 高速フーリエ変換
User Jirotech
Language C++14 (GCC 5.4.1)
Score 100
Code Size 4962 Byte
Status AC
Exec Time 463 ms
Memory 9176 KB

Judge Result

Set Name Sample All
Score / Max Score 0 / 0 100 / 100
Status
AC × 1
AC × 33
Set Name Test Cases
Sample 00_sample_01
All 00_sample_01, 01_00_01, 01_01_19, 01_02_31, 01_03_22, 01_04_31, 01_05_40, 01_06_15, 01_07_39, 01_08_28, 01_09_30, 01_10_23, 01_11_33, 01_12_11, 01_13_28, 01_14_41, 01_15_26, 01_16_49, 01_17_34, 01_18_02, 01_19_33, 01_20_29, 02_00_51254, 02_01_82431, 02_02_17056, 02_03_34866, 02_04_6779, 02_05_65534, 02_06_65535, 02_07_65536, 02_08_65537, 02_09_65538, 02_10_100000
Case Name Status Exec Time Memory
00_sample_01 AC 1 ms 256 KB
01_00_01 AC 1 ms 256 KB
01_01_19 AC 1 ms 256 KB
01_02_31 AC 1 ms 256 KB
01_03_22 AC 1 ms 256 KB
01_04_31 AC 1 ms 256 KB
01_05_40 AC 1 ms 256 KB
01_06_15 AC 1 ms 256 KB
01_07_39 AC 1 ms 256 KB
01_08_28 AC 1 ms 256 KB
01_09_30 AC 1 ms 256 KB
01_10_23 AC 1 ms 256 KB
01_11_33 AC 1 ms 256 KB
01_12_11 AC 1 ms 256 KB
01_13_28 AC 1 ms 256 KB
01_14_41 AC 1 ms 256 KB
01_15_26 AC 1 ms 256 KB
01_16_49 AC 1 ms 256 KB
01_17_34 AC 1 ms 256 KB
01_18_02 AC 1 ms 256 KB
01_19_33 AC 1 ms 256 KB
01_20_29 AC 1 ms 256 KB
02_00_51254 AC 234 ms 4768 KB
02_01_82431 AC 403 ms 9056 KB
02_02_17056 AC 87 ms 2540 KB
02_03_34866 AC 179 ms 4576 KB
02_04_6779 AC 31 ms 896 KB
02_05_65534 AC 286 ms 4840 KB
02_06_65535 AC 286 ms 4840 KB
02_07_65536 AC 343 ms 8936 KB
02_08_65537 AC 344 ms 8936 KB
02_09_65538 AC 343 ms 8936 KB
02_10_100000 AC 463 ms 9176 KB