QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#848998#9945. Circular ConvolutionToboWA 2ms4804kbC++2010.6kb2025-01-09 11:11:532025-01-09 11:12:02

Judging History

This is the latest submission verdict.

  • [2025-01-09 11:12:02]
  • Judged
  • Verdict: WA
  • Time: 2ms
  • Memory: 4804kb
  • [2025-01-09 11:11:53]
  • Submitted

answer

#include <bits/stdc++.h>
using namespace std;

const int N = 2e5, P = 998244353;
using i64 = long long;
using Poly = vector<int>;
/*---------------------------------------------------------------------------*/
#define MUL(a, b) (i64(a) * (b) % P)
#define ADD(a, b) (((a) += (b)) >= P ? (a) -= P : 0) // (a += b) %= P
#define SUB(a, b) (((a) -= (b)) < 0 ? (a) += P : 0)  // ((a -= b) += P) %= P
Poly getInv(int L)
{
    Poly inv(L);
    inv[1] = 1;
    for (int i = 2; i < L; i++)
        inv[i] = MUL((P - P / i), inv[P % i]);
    return inv;
}
int POW(i64 a, int b = P - 2, i64 x = 1)
{
    for (; b; b >>= 1, a = a * a % P)
        if (b & 1)
            x = x * a % P;
    return x;
}
auto inv = getInv(N);

struct Complex
{
    double x = 0.0;
    double y = 0.0;

    Complex() {}
    Complex(double x, double y) : x(x), y(y) {}
    Complex operator+(const Complex &rhs) const { return Complex(x + rhs.x, y + rhs.y); }
    Complex operator-(const Complex &rhs) const { return Complex(x - rhs.x, y - rhs.y); }
    Complex operator*(const Complex &rhs) const { return Complex(x * rhs.x - y * rhs.y, x * rhs.y + y * rhs.x); }
    Complex conj() const { return Complex(x, -y); }
};

namespace NTT
{
    const int g = 3;
    Poly Omega(int L)
    {
        int wn = POW(g, P / L);
        Poly w(L);
        w[L >> 1] = 1;
        for (int i = L / 2 + 1; i < L; i++)
            w[i] = MUL(w[i - 1], wn);
        for (int i = L / 2 - 1; i >= 1; i--)
            w[i] = w[i << 1];
        return w;
    }
    auto W = Omega(1 << 18); // Length
    void DIF(int *a, int n)
    {
        for (int k = n >> 1; k; k >>= 1)
            for (int i = 0, y; i < n; i += k << 1)
                for (int j = 0; j < k; ++j)
                    y = a[i + j + k], a[i + j + k] = MUL(a[i + j] - y + P, W[k + j]), ADD(a[i + j], y);
    }
    void IDIT(int *a, int n)
    {
        for (int k = 1; k < n; k <<= 1)
            for (int i = 0, x, y; i < n; i += k << 1)
                for (int j = 0; j < k; ++j)
                    x = a[i + j], y = MUL(a[i + j + k], W[k + j]),
                    a[i + j + k] = x - y < 0 ? x - y + P : x - y, ADD(a[i + j], y);
        int Inv = P - (P - 1) / n;
        for (int i = 0; i < n; i++)
            a[i] = MUL(a[i], Inv);
        reverse(a + 1, a + n);
    }
}
/*---------------------------------------------------------------------------*/
namespace Polynomial
{
    // basic operator
    int norm(int n) { return 1 << (__lg(n - 1) + 1); }
    void norm(Poly &a)
    {
        if (!a.empty())
            a.resize(norm(a.size()), 0);
        else
            a = {0};
    }
    void DFT(Poly &a) { NTT::DIF(a.data(), a.size()); }
    void IDFT(Poly &a) { NTT::IDIT(a.data(), a.size()); }
    Poly &dot(Poly &a, Poly &b)
    {
        for (int i = 0; i < a.size(); i++)
            a[i] = MUL(a[i], b[i]);
        return a;
    }

    // mul / div int
    Poly &operator*=(Poly &a, int b)
    {
        for (auto &x : a)
            x = MUL(x, b);
        return a;
    }
    Poly operator*(Poly a, int b) { return a *= b; }
    Poly operator*(int a, Poly b) { return b * a; }
    Poly &operator/=(Poly &a, int b) { return a *= POW(b); }
    Poly operator/(Poly a, int b) { return a /= b; }

    // Poly add / sub
    Poly &operator+=(Poly &a, Poly b)
    {
        a.resize(max(a.size(), b.size()));
        for (int i = 0; i < b.size(); i++)
            ADD(a[i], b[i]);
        return a;
    }
    Poly operator+(Poly a, Poly b) { return a += b; }
    Poly &operator-=(Poly &a, Poly b)
    {
        a.resize(max(a.size(), b.size()));
        for (int i = 0; i < b.size(); i++)
            SUB(a[i], b[i]);
        return a;
    }
    Poly operator-(Poly a, Poly b) { return a -= b; }

    // Poly mul
    Poly operator*(Poly a, Poly b)
    {
        int n = a.size() + b.size() - 1, L = norm(n);
        if (a.size() <= 8 || b.size() <= 8)
        {
            Poly c(n);
            for (int i = 0; i < a.size(); i++)
                for (int j = 0; j < b.size(); j++)
                    c[i + j] = (c[i + j] + (i64)a[i] * b[j]) % P;
            return c;
        }
        a.resize(L), b.resize(L);
        DFT(a), DFT(b), dot(a, b), IDFT(a);
        return a.resize(n), a;
    }

    // Poly inv
    Poly Inv2k(Poly a)
    { // |a| = 2 ^ k
        int n = a.size(), m = n >> 1;
        if (n == 1)
            return {POW(a[0])};
        Poly b = Inv2k(Poly(a.begin(), a.begin() + m)), c = b;
        b.resize(n), DFT(a), DFT(b), dot(a, b), IDFT(a);
        for (int i = 0; i < n; i++)
            a[i] = i < m ? 0 : P - a[i];
        DFT(a), dot(a, b), IDFT(a);
        return move(c.begin(), c.end(), a.begin()), a;
    }
    Poly Inv(Poly a)
    {
        int n = a.size();
        norm(a), a = Inv2k(a);
        return a.resize(n), a;
    }

    // Poly calculus
    Poly deriv(Poly a)
    {
        for (int i = 1; i < a.size(); i++)
            a[i - 1] = MUL(i, a[i]);
        return a.pop_back(), a;
    }
    Poly integ(Poly a)
    {
        a.push_back(0);
        for (int i = 1; i < a.size(); i++)
            a[i] = MUL(inv[i], a[i - 1]);
        return a[0] = 0, a;
    }

    // Poly ln
    Poly Ln(Poly a)
    {
        int n = a.size();
        a = deriv(a) * Inv(a);
        return a.resize(n - 1), integ(a);
    }

    // Poly exp
    Poly Exp(Poly a)
    {
        int n = a.size(), k = norm(n);
        Poly b = {1}, c, d;
        a.resize(k);
        for (int L = 2; L <= k; L <<= 1)
        {
            d = b, b.resize(L), c = Ln(b), c.resize(L);
            for (int i = 0; i < L; i++)
                c[i] = a[i] - c[i] + (a[i] < c[i] ? P : 0);
            ADD(c[0], 1), DFT(b), DFT(c), dot(b, c), IDFT(b);
            move(d.begin(), d.end(), b.begin());
        }
        return b.resize(n), b;
    }

    // Poly pow
    Poly Pow(Poly a, int b)
    {
        // a0 > 1 : f^k(x) = (f(x) * inv(a0))^k * a0^k
        // a0 = 0 : 右移至第一个系数不为0的项,设为x^d,则设g(x) = f(x) / x^d
        // 转化为问题一,然后乘上(x^d)^k
        int n = a.size(), d = 0, k, a0;
        while (d < n && !a[d])
            ++d;
        if ((i64)d * b >= n)
            return Poly(n);
        a.erase(a.begin(), a.begin() + d); // f(x) / x^d
        a0 = a[0];
        k = POW(a0), norm(a *= k); // f(x) * inv(a0)
        a = Exp(Ln(a) * b) * POW(a0, b);
        a.resize(n), d *= b;
        for (int i = n - 1; i >= 0; i--)
            a[i] = i >= d ? a[i - d] : 0; // 乘上(x^d)^k
        return a;
    }
    Poly Pow(Poly a, string str)
    {
        i64 k = 0, t = 0;
        for (int i = 0; i < str.size(); i++)
        {
            k = (k * 10 + str[i] - '0') % P;
            if (t <= P)
                t = (t * 10 + str[i] - '0');
        }
        if (k < P && t >= P)
            k += P;
        return Pow(a, k);
    }

    pair<Poly, Poly> div(Poly f, Poly g)
    { // F(x) = G(x) * Q(x) + R(x)
        int n = f.size() - 1, m = g.size() - 1;
        if (n < m)
            return pair<Poly, Poly>{Poly{0}, f};
        Poly finv = f, ginv = g;
        reverse(finv.begin(), finv.end());
        reverse(ginv.begin(), ginv.end());
        ginv.resize(n - m + 1);
        Poly q = finv * Inv(ginv);
        q.resize(n - m + 1);
        reverse(q.begin(), q.end());
        Poly r(m), tmp = g * q;
        for (int i = 0; i < m; i++)
            r[i] = (f[i] - tmp[i] + P) % P;
        return pair<Poly, Poly>{q, r};
    }

    Poly LinearRecurrence(i64 n, Poly tmp)
    {
        Poly f{1}, g{0, 1};
        while (n)
        {
            if (n & 1)
                f = div(f * g, tmp).second;
            g = div(g * g, tmp).second;
            n >>= 1;
        }
        return f;
    }

    constexpr double PI = 3.14159265358979323846;
    int binary_upper_bound_in_bits(int w)
    {
        if (w <= 0)
            return 1;
        const int highbit = 31 - __builtin_clz(w);
        return highbit + 1;
    }
    void fft(vector<Complex> &a, int L, int flag)
    {
        // flag == 1 : forward; flag == -1 : inverse.
        // L should be a power of 2.
        int k = binary_upper_bound_in_bits(L - 1);
        vector<Complex> w(L);
        vector<int> rev(L);
        for (int i = 0; i < L; ++i)
        {
            w[i] = Complex(cos(2 * PI / L * i), flag * sin(2 * PI / L * i));
            rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (k - 1));
            if (i < rev[i])
                swap(a[i], a[rev[i]]);
        }
        for (int l = 2; l <= L; l <<= 1)
        {
            int m = l >> 1;
            for (int i = 0; i < L; i += l)
            {
                for (int k = 0; k < m; ++k)
                {
                    Complex t = w[L / l * k] * a[i + k + m];
                    a[i + k + m] = a[i + k] - t;
                    a[i + k] = a[i + k] + t;
                }
            }
        }
        if (flag == -1)
            for (int i = 0; i < L; ++i)
                a[i].x /= L;
    }
    Poly multiply_mod_any(Poly f, Poly g)
    {
        int L = norm((int)f.size() + (int)g.size() - 1);
        vector<Complex> a(L), b(L), c(L), d(L);
        for (int i = 0; i < f.size(); ++i)
        {
            a[i].x = int(f[i]) >> 15;
            b[i].x = int(f[i]) & 32767;
        }
        for (int i = 0; i < g.size(); ++i)
        {
            c[i].x = int(g[i]) >> 15;
            d[i].x = int(g[i]) & 32767;
        }
        fft(a, L, 1);
        fft(b, L, 1);
        fft(c, L, 1);
        fft(d, L, 1);
        for (int i = 0; i < L; ++i)
        {
            Complex ta = a[i], tb = b[i], tc = c[i], td = d[i];
            a[i] = ta * tc;
            b[i] = ta * td + tb * tc;
            c[i] = tb * td;
        }
        fft(a, L, -1);
        fft(b, L, -1);
        fft(c, L, -1);
        Poly z((int)f.size() + (int)g.size() - 1);
        for (int i = 0; i < z.size(); ++i)
        {
            z[i] = (((i64)(a[i].x + .5) << 30) +
                    ((i64)(b[i].x + .5) << 15) +
                    (i64)(c[i].x + .5));
        }
        return z;
    }
}
using namespace Polynomial;

void solve()
{
    int n;
    cin >> n;
    Poly a(n), b(n);
    for (int &i : a)
        cin >> i;
    for (int &i : b)
        cin >> i;
    auto ans = multiply_mod_any(a, b);
    for (int i = n; i < ans.size(); i++)
        ans[i - n] += ans[i];
    for (int i = 0; i < n; i++)
        cout << ans[i] << ' ';
}
signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int t = 1;
    // cin >> t;
    while (t--)
        solve();
}

詳細信息

Test #1:

score: 100
Accepted
time: 2ms
memory: 4800kb

input:

3
1 1 4
5 1 4

output:

13 22 25 

result:

ok 3 number(s): "13 22 25"

Test #2:

score: -100
Wrong Answer
time: 0ms
memory: 4804kb

input:

3
1 2 3
-1 2 0

output:

32773 32768 32769 

result:

wrong answer 1st numbers differ - expected: '5', found: '32773'