提交记录 21349


用户 题目 状态 得分 用时 内存 语言 代码长度
rogeryoungh 1002i. 【模板题】多项式乘法 Compile Error 0 0 ns 0 KB C++17 8.64 KB
提交时间 评测时间
2024-02-29 21:14:49 2024-02-29 21:14:50
// GENERATE DATE: 2024-02-29 02:21:56.087411


// GENERATE FROM: https://github.com/rogeryoungh/algorithm-cpp
#include <type_traits>
#include <cstdint>

using i8 = std::int8_t;
using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using i128 = __int128_t;
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using u128 = __uint128_t;
using usize = std::size_t;
using f32 = float;
using f64 = double;
using f80 = long double;

template<class T>
struct type_identity { using type = T; };

template <class T>
using TI = typename type_identity<T>::type;

#include <cstdio>
#include <vector>

struct FreadBuf {
  std::FILE *const f;
  std::vector<u8> buf;
  const u8 *p, *end;
  usize read_cnt = 0;
  FreadBuf(std::FILE *const f, usize size) : f(f), buf(size) {
    p = buf.data(), end = p + size - 8;
    read_cnt = std::fread(buf.data(), 1, end - p, f);
    buf[read_cnt] = 0;
  }
  void load() {
    u8 *p2 = std::move(p, end, buf.data());
    read_cnt = std::fread(p2, 1, end - p2, f);
    p2[read_cnt] = 0, p = buf.data();
  }
  bool eof() const {
    return read_cnt == 0;
  }
  void reserve(usize n) {
    if (end - p < i64(n))
      load();
  }
  u8 top() const {
    return *p;
  }
  u8 pop() {
    return *p++;
  }
};



#include <cstring>
#include <vector>

struct AtoiHelper {
  std::vector<u16> pre;
  AtoiHelper() : pre(0x10000, -1) {
    for (u32 i = 0; i != 0x100; ++i) {
      for (u32 j = 0; j != 10; ++j) {
        u32 t = i * 0x100 | j | 0x30;
        if ('0' <= i && i <= '9')
          pre[t] = j * 10 + i - 0x30;
        else
          pre[t] = j | 0x100;
      }
    }
  }
  u64 getu(u8 c, const u8 *&p0) {
    const u8 *p = p0;
    u64 x = c & 0xf;
    while (true) {
      u16 t;
      std::memcpy(&t, p, 2);
      auto ft = pre[t];
      p += 2;
      if (ft < 100) { // len = 2
        x = x * 100 + ft;
      } else { // len = 1
        if (ft < 0x1000)
          x = x * 10 + ft - 0x100;
        else
          --p;
        break;
      }
    }
    return p0 = p, x;
  }
};


template <class Buf>
struct Reader {
  Buf buf;
  AtoiHelper atoi;
  Reader(std::FILE *f, usize size = 1 << 18) : buf(f, size) {}
  bool eof() const {
    return buf.eof();
  }
  template <class T>
  Reader &operator>>(T &x) {
    while (true) {
      buf.reserve(0x40);
      u8 c = buf.pop();
      if (std::is_signed_v<T> && c == '-') {
        x = -T(atoi.getu(0, buf.p));
        break;
      }
      if ('0' <= c && c <= '9') {
        x = atoi.getu(c, buf.p);
        break;
      }
    }
    return *this;
  }
};



#include <array>

struct ItoaHelper {
  std::vector<u32> pre;
  ItoaHelper() : pre(10000) {
    for (u32 i = 0; i < 10000; ++i) {
      u32 ti = i;
      for (u32 j = 0; j != 4; ++j) {
        pre[i] = pre[i] << 8 | ti % 10 | 0x30;
        ti /= 10;
      }
    }
  }
  void putu(u64 x, u8 *&p) {
    std::array<u8, 32> tmp;
    u8 *s0 = tmp.data() + 30, *s1 = s0;
    while (x >= 10000) {
      std::memcpy(s0 -= 4, &pre[x % 10000], 4);
      x /= 10000;
    }
    std::memcpy(s0 -= 4, &pre[x % 10000], 4);
    s0 += x < 100 ? (x < 10 ? 3 : 2) : (x < 1000 ? 1 : 0);
    p = std::copy(s0, s1, p);
  }
};

#include <cassert>

template <u8 endc = 0>
struct Writer {
  std::FILE *const f;
  std::vector<u8> buf;
  ItoaHelper itoa;
  u8 *p, *end;
  Writer(std::FILE *const f, usize size = 1 << 18) : f(f), buf(size) {
    assert(size >= 0x100);
    p = buf.data(), end = p + size;
  }
  ~Writer() {
    flush();
  }
  void flush() {
    std::fwrite(buf.data(), 1, p - buf.data(), f);
    p = buf.data();
  }
  void reserve(usize n) {
    if (end - p < i64(n))
      flush();
  }
  template <class T>
  Writer &operator<<(T x) {
    reserve(0x40);
    if (std::is_signed_v<T> && x < 0) {
      *p++ = '-';
      itoa.putu(-x, p);
    } else {
      itoa.putu(x, p);
    }
    if constexpr (endc != 0)
      *p++ = endc;
    return *this;
  }
  Writer &operator<<(char x) {
    *p++ = x;
    return *this;
  }
};


u32 countr_zero(u32 x) {
  return x == 0 ? 32 : __builtin_ctz(x);
}

u32 countr_one(u32 x) {
  return countr_zero(~x);
}

template <class U>
struct Mont {
  using S = std::make_signed_t<U>;
  using UU = std::conditional_t<std::is_same_v<U, u32>, u64, u128>;
  const U MOD, MOD2, R, IR, R2, ONE;
  explicit constexpr Mont(U mod)
      : MOD(mod), MOD2(mod * 2), R(getR(mod)), IR(-getNR(mod)), R2(UU(R) * R % MOD), ONE(trans(1)) {
  }
  constexpr static U getR(U mod) {
    return (UU(1) << (sizeof(U) * 8)) % mod;
  }
  constexpr static U getNR(U mod) {
    U x = 1;
    for (u32 i = 0; i != 6; ++i)
      x *= 2 - x * mod;
    return x;
  }
  constexpr U trans(U x) const {
    // return (u64(x) << 32) % MOD;
    return reduce(UU(x) * R2);
  }
  constexpr U reduce(UU x) const {
    return (x + UU(U(x) * IR) * MOD) >> (sizeof(U) * 8);
  }
  constexpr U norm(U v) const {
    U v2 = v - MOD;
    return S(v2) < 0 ? v : v2;
  }
  constexpr U add(U a, U b) const {
    U v1 = a + b, v2 = v1 - MOD2;
    return S(v2) < 0 ? v1 : v2;
  }
  constexpr U sub(U a, U b) const {
    U v1 = a - b, v2 = v1 + MOD2;
    return S(v1) >= 0 ? v1 : v2;
  }
  constexpr U mul(U a, U b) const {
    return reduce(UU(a) * b);
  }
  constexpr U qpow(U a, u64 n, U r) const {
    for (; n > 0; n /= 2) {
      if (n % 2 == 1)
        r = mul(r, a);
      a = mul(a, a);
    }
    return r;
  }
  constexpr U qpow(U a, u64 n) const {
    return qpow(a, n, ONE);
  }
  constexpr U inv(U x) const {
    return qpow(x, MOD - 2);
  }
  constexpr U div(U a, U b) const {
    return reduce(qpow(b, MOD - 2, a));
  }
  constexpr U get(U x) const {
    return norm(reduce(x));
  }
  constexpr U div2(U x) const {
    return (x % 2 == 1 ? x + MOD : x) >> 1;
  }
  constexpr bool cmp(U a, U b) const {
    return get(a) == get(b);
  }
  constexpr bool ncmp(U a, U b) const {
    return !cmp(a, b);
  }
  constexpr U neg(U x) const {
    return x != 0 ? MOD2 - x : 0;
  }
};
using Mont32 = Mont<u32>;
using Mont64 = Mont<u64>;
template <class ModT>
using ModU = ModT::U;
template <class ModT>
using ModUU = ModT::UU;

template <class U>
struct NTTOriginalRadix2 {
  const Mont<U> _M;
  std::array<U, 64> rt{}, irt{}, rate2{}, irate2{};
  NTTOriginalRadix2(Mont<U> M, TI<U> G) : _M(std::move(M)) {
    const u32 rank2 = std::countr_zero(M.MOD - 1);
    rt[rank2] = M.qpow(M.trans(G), (M.MOD - 1) >> rank2);
    irt[rank2] = M.inv(rt[rank2]);
    for (u32 i = rank2; i != 0; --i) {
      rt[i - 1] = M.mul(rt[i], rt[i]);
      irt[i - 1] = M.mul(irt[i], irt[i]);
    }
    U prod = M.ONE, iprod = M.ONE;
    for (u32 i = 0; i != rank2 - 1; ++i) {
      rate2[i] = M.mul(prod, rt[i + 2]);
      irate2[i] = M.mul(iprod, irt[i + 2]);
      prod = M.mul(prod, irt[i + 2]);
      iprod = M.mul(iprod, rt[i + 2]);
    }
  }
  void ntt(U *f, usize n) {
    const auto M = _M;
    for (u32 l = n / 2; l >= 1; l /= 2) {
      U *fx = f, *fy = fx + l;
      for (u32 j = 0; j != l; ++j) {
        U x = fx[j], y = fy[j];
        fx[j] = M.add(x, y);
        fy[j] = M.sub(x, y);
      }
      U r = rate2[0];
      for (u32 i = l * 2, k = 1; i != n; i += l * 2, ++k) {
        fx = f + i, fy = fx + l;
        for (u32 j = 0; j != l; ++j) {
          U x = fx[j], y = M.mul(fy[j], r);
          fx[j] = M.add(x, y);
          fy[j] = M.sub(x, y);
        }
        r = M.mul(r, rate2[std::countr_one(k)]);
      }
    }
  }
  void intt(U *f, usize n) {
    const auto M = _M;
    U ivn = M.trans(M.MOD - (M.MOD - 1) / n);
    for (u32 l = 1; l <= n / 2; l *= 2) {
      U *fx = f, *fy = fx + l;
      for (u32 j = 0; j != l; ++j) {
        U x = fx[j], y = fy[j];
        if (l == n / 2)
          x = M.mul(x, ivn), y = M.mul(y, ivn); // div n here !!!
        fx[j] = M.add(x, y);
        fy[j] = M.sub(x, y);
      }
      U r = irate2[0];
      for (u32 i = l * 2, k = 1; i != n; i += l * 2, ++k) {
        fx = f + i, fy = fx + l;
        for (u32 j = 0; j != l; ++j) {
          U x = fx[j], y = fy[j];
          fx[j] = M.add(x, y);
          fy[j] = M.mul(M.sub(x, y), r);
        }
        r = M.mul(r, irate2[std::countr_one(k)]);
      }
    }
  }
  void conv(U *f, U *g, u32 n) {
    const auto M = _M;
    ntt(f, n);
    if (f != g)
      ntt(g, n);
    for (u32 i = 0; i != n; ++i)
      f[i] = M.mul(f[i], g[i]);
    intt(f, n);
  }
};

u32 bit_ceil(u32 x) {
  u32 t = 1;
  while (t < x)
   t *= 2;
  return t;
}

i32 main() {
  Reader<FreadBuf> fin(stdin);
  Writer<' '> fout(stdout);
  u32 n, m;
  fin >> n >> m;
  n++, m++;
  const u32 L = bit_ceil(n + m - 1);
  const auto M = Mont32{998244353};
  NTTOriginalRadix2 ntt(M, 3);
  std::vector<u32> f(L), g(L);
  for (u32 i = 0; i != n; ++i)
    fin >> f[i];
  for (u32 i = 0; i != m; ++i)
    fin >> g[i];
  ntt.conv(f.data(), g.data(), L);
  for (u32 i = 0; i != n + m - 1; ++i)
    fout << f[i];
  return 0;
}

CompilationN/AN/ACompile ErrorScore: N/A


Judge Duck Online | 评测鸭在线
Server Time: 2025-07-19 14:36:02 | Loaded in 1 ms | Server Status
个人娱乐项目,仅供学习交流使用 | 捐赠