QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#284837#6513. Expression 3jrjyyWA 311ms158848kbC++2020.7kb2023-12-16 15:13:182023-12-16 15:13:20

Judging History

你现在查看的是最新测评结果

  • [2024-02-14 13:23:19]
  • hack成功,自动添加数据
  • (/hack/531)
  • [2023-12-16 15:13:20]
  • 评测
  • 测评结果:WA
  • 用时:311ms
  • 内存:158848kb
  • [2023-12-16 15:13:18]
  • 提交

answer

#include <bits/stdc++.h>

using i64 = long long;

template <typename T>
constexpr T power(T a, i64 b) {
    T c{1};
    while (b) {
        if (b % 2) {
            c *= a;
        }
        a *= a;
        b /= 2;
    }
    return c;
}

template <int P>
struct MInt {
    int x;
    constexpr MInt() : x{} {}
    constexpr MInt(i64 x_) : x{up(x_ % getMod())} {}

    static int Mod;
    constexpr static int getMod() {
        return P > 0 ? P : Mod;
    }
    constexpr static void setMod(int Mod_) {
        Mod = Mod_;
    }

    constexpr int up(int x) const {
        if (x < 0) {
            x += getMod();
        }
        return x;
    }
    constexpr int down(int x) const {
        if (x >= getMod()) {
            x -= getMod();
        }
        return x;
    }
    constexpr int norm(int x) const {
        return up(down(x));
    }

    constexpr int val() const {
        return x;
    }
    explicit constexpr operator int() const {
        return x;
    }
    constexpr MInt operator-() const {
        MInt res;
        res.x = norm(getMod() - x);
        return res;
    }
    constexpr MInt inv() const {
        assert(x != 0);
        return power(*this, getMod() - 2);
    }
    constexpr MInt &operator+=(MInt rhs) {
        x = down(x + rhs.x);
        return *this;
    }
    constexpr MInt &operator-=(MInt rhs) {
        x = up(x - rhs.x);
        return *this;
    }
    constexpr MInt &operator*=(MInt rhs) {
        x = 1ll * x * rhs.x % getMod();
        return *this;
    }
    constexpr MInt &operator/=(MInt rhs) {
        return *this *= rhs.inv();
    }
    friend constexpr MInt operator+(MInt lhs, MInt rhs) {
        return lhs += rhs;
    }
    friend constexpr MInt operator-(MInt lhs, MInt rhs) {
        return lhs -= rhs;
    }
    friend constexpr MInt operator*(MInt lhs, MInt rhs) {
        return lhs *= rhs;
    }
    friend constexpr MInt operator/(MInt lhs, MInt rhs) {
        return lhs /= rhs;
    }
    friend constexpr bool operator==(MInt lhs, MInt rhs) {
        return lhs.val() == rhs.val();
    }
    friend constexpr bool operator!=(MInt lhs, MInt rhs) {
        return lhs.val() != rhs.val();
    }
    friend constexpr std::istream &operator>>(std::istream &is, MInt &a) {
        i64 x = 0;
        is >> x;
        a = MInt(x);
        return is;
    }
    friend constexpr std::ostream &operator<<(std::ostream &os, const MInt &a) {
        return os << a.val();
    }
};

template <int P>
int MInt<P>::Mod = P;
template <>
int MInt<0>::Mod = 998244353;

template <int V, int P>
constexpr MInt<P> CInv = MInt<P>(V).inv();

template <int P>
struct IComb {
    using Z = MInt<P>;
    int n;
    std::vector<Z> fac_, ifac_, inv_;

    IComb() : n(0), fac_{1}, ifac_{1}, inv_{0} {}
    IComb(int n) : IComb{} {
        init(n);
    }
    void init(int m) {
        if (m <= n) {
            return;
        }
        assert(m < Z::getMod());
        fac_.resize(m + 1);
        ifac_.resize(m + 1);
        inv_.resize(m + 1);

        for (int i = n + 1; i <= m; ++i) {
            fac_[i] = fac_[i - 1] * i;
        }
        ifac_[m] = fac_[m].inv();
        for (int i = m; i > n + 1; --i) {
            ifac_[i - 1] = ifac_[i] * i;
        }
        for (int i = m; i > n; --i) {
            inv_[i] = ifac_[i] * fac_[i - 1];
        }
        n = m;
    }

    Z fac(int m) {
        if (n < m) {
            init(2 * m);
        }
        return fac_[m];
    }
    Z ifac(int m) {
        if (n < m) {
            init(2 * m);
        }
        return ifac_[m];
    }
    Z inv(int m) {
        if (n < m) {
            init(2 * m);
        }
        return inv_[m];
    }
    Z binom(int n, int m) {
        if (n < m || m < 0) {
            return Z{};
        }
        return fac(n) * ifac(m) * ifac(n - m);
    }
};

template <int P>
IComb<P> icomb;

template <int P>
struct IComplexZ {
    using Z = MInt<P>;
    static Z i2;
    Z a, b;
    IComplexZ(Z a_ = 1) : IComplexZ(a_, 0) {}
    IComplexZ(Z a_, Z b_) : a(a_), b(b_) {}
    IComplexZ &operator*=(const IComplexZ &y) {
        *this = IComplexZ(a * y.a + i2 * b * y.b, a * y.b + b * y.a);
        return *this;
    }
};
template <int P>
typename IComplexZ<P>::Z IComplexZ<P>::i2;

template <int P>
std::vector<MInt<P>> sqrtMod(MInt<P> n) {
    static std::mt19937 rnd(std::random_device{}());
    if (n == 0) {
        return {0};
    }
    if (P == 2) {
        return {1};
    }
    if (power(n, (P - 1) / 2) != 1) {
        return {};
    }
    MInt<P> a;
    do {
        a = rnd() % (P - 1) + 1;
    } while (power(a * a - n, (P - 1) / 2) == 1);
    IComplexZ<P>::i2 = a * a - n;
    MInt<P> x = power(IComplexZ<P>(a, 1), (P + 1) / 2).a, y = P - x;
    if (x.val() > y.val()) {
        std::swap(x, y);
    }
    if (x == y) {
        return {x};
    }
    return {x, y};
}

namespace Polynomial {
constexpr int bitceil(int x) {
    assert(x >= 0);
    return x <= 1 ? 1 : 2 << std::__lg(x - 1);
}

template <int P>
std::vector<MInt<P>> roots{1};

template <int P>
constexpr MInt<P> findPrimitiveRoot() {
    for (MInt<P> i = 2;; i += 1) {
        if (power(i, (P - 1) / 2) != 1) {
            return power(i, (P - 1) >> std::__lg(P - 1));
        }
    }
}

template <int P>
constexpr MInt<P> primitiveRoot = findPrimitiveRoot<P>();

template <int P>
void initRoots(int n) {
    assert((n & -n) == n && ((P - 1) & (n - 1)) == 0);
    if (int(roots<P>.size()) >= n) {
        return;
    }
    roots<P>.reserve(n);
    while (int(roots<P>.size()) < n) {
        int l = int(roots<P>.size());
        roots<P>.resize(2 * l);
        auto w = roots<P>.begin() + l;
        w[0] = 1;
        MInt<P> x = power(primitiveRoot<P>, (P - 1) / l / 2);
        for (int i = 1; i < l; ++i) {
            w[i] = w[i - 1] * x;
        }
    }
}

template <int P>
inline void applyDft(int &x, int &y, int w) {
    int t = x - y;
    x = x + y;
    if (x >= P) {
        x -= P;
    }
    y = 1ll * t * w % P;
    if (y < 0) {
        y += P;
    }
}
template <int P>
inline void applyIdft(int &x, int &y, int w) {
    int t = 1ll * y * w % P;
    y = x - t;
    if (y < 0) {
        y += P;
    }
    x = x + t;
    if (x >= P) {
        x -= P;
    }
}
template <int P, void F(int &x, int &y, int w)>
inline void applyTrans(std::vector<MInt<P>> &a, int l) {
    for (auto p = a.begin(), q = p + 2 * l; p != a.end(); p = q, q += 2 * l) {
        for (auto i = p, j = p + l, w = roots<P>.begin() + l; j != q; ++i, ++j, ++w) {
            F(i->x, j->x, w->x);
        }
    }
}

template <int P>
void dft(std::vector<MInt<P>> &a) {
    const int n = int(a.size());
    initRoots<P>(n);
    for (int l = n / 2; l; l /= 2) {
        applyTrans<P, applyDft<P>>(a, l);
    }
}
template <int P>
void idft(std::vector<MInt<P>> &a) {
    const int n = int(a.size());
    initRoots<P>(n);
    for (int l = 1; l < n; l *= 2) {
        applyTrans<P, applyIdft<P>>(a, l);
    }
    std::reverse(std::next(a.begin()), a.end());
    MInt<P> c = (1 - P) / n;
    for (auto &x : a) {
        x *= c;
    }
}

template <int P>
struct IPoly : public std::vector<MInt<P>> {
    using Z = MInt<P>;

    IPoly() = default;
    explicit IPoly(std::size_t n) : std::vector<Z>(n) {}
    explicit IPoly(const std::vector<Z> &a) : std::vector<Z>{a} {}
    IPoly(std::initializer_list<Z> a) : std::vector<Z>{a} {}
    template <typename InputIt, typename = std::_RequireInputIter<InputIt>>
    explicit IPoly(InputIt first, InputIt last) : std::vector<Z>(first, last) {}
    template <typename F>
    explicit IPoly(std::size_t n, F &&f) : IPoly(n) {
        std::generate(this->begin(), this->end(), [&, i = 0]() mutable {
            return f(i++);
        });
    }

    IPoly shift(int k) const {
        if (k >= 0) {
            auto f = *this;
            f.insert(f.begin(), k, 0);
            return f;
        } else if (int(this->size()) <= -k) {
            return IPoly{};
        } else {
            return IPoly(this->begin() + -k, this->end());
        }
    }
    IPoly trunc(int k) const {
        if (k < int(this->size())) {
            return IPoly(this->begin(), this->begin() + k);
        } else {
            auto f = *this;
            f.resize(k);
            return f;
        }
    }
    Z get(int p) const {
        if (p < 0 || int(this->size()) <= p) {
            return 0;
        }
        return (*this)[p];
    }

    friend IPoly operator+(const IPoly &a, const IPoly &b) {
        IPoly c(std::max(a.size(), b.size()));
        for (int i = 0; i < int(c.size()); ++i) {
            c[i] = a.get(i) + b.get(i);
        }
        return c;
    }
    friend IPoly operator-(const IPoly &a, const IPoly &b) {
        IPoly c(std::max(a.size(), b.size()));
        for (int i = 0; i < int(c.size()); ++i) {
            c[i] = a.get(i) - b.get(i);
        }
        return c;
    }
    friend IPoly operator-(const IPoly &a) {
        IPoly c(a.size());
        for (int i = 0; i < int(a.size()); ++i) {
            c[i] = -a[i];
        }
        return c;
    }
    friend IPoly operator*(const IPoly &f, const IPoly &g) {
        static IPoly a, b;
        if (f.empty() || g.empty()) {
            return IPoly{};
        }
        int n = int(f.size()) + int(g.size()) - 1, len = bitceil(n);
        if (n <= 128) {
            IPoly c(n);
            for (int i = 0; i < int(f.size()); ++i) {
                for (int j = 0; j < int(g.size()); ++j) {
                    c[i + j] += f[i] * g[j];
                }
            }
            return c;
        }
        bool eq = f == g;
        a.resize(len);
        std::copy(f.begin(), f.end(), a.begin());
        std::fill(a.begin() + f.size(), a.end(), 0);
        if (!eq) {
            b.resize(len);
            std::copy(g.begin(), g.end(), b.begin());
            std::fill(b.begin() + g.size(), b.end(), 0);
        }
        assert(((P - 1) & (len - 1)) == 0);
        dft(a);
        if (eq) {
            for (int i = 0; i < len; ++i) {
                a[i] *= a[i];
            }
        } else {
            dft(b);
            for (int i = 0; i < len; ++i) {
                a[i] *= b[i];
            }
        }
        idft(a), a.resize(n);
        return a;
    }
    friend IPoly operator*(IPoly a, Z b) {
        for (int i = 0; i < int(a.size()); ++i) {
            a[i] *= b;
        }
        return a;
    }
    friend IPoly operator*(Z a, const IPoly &b) {
        return b * a;
    }
    friend IPoly operator/(IPoly a, Z b) {
        return a * b.inv();
    }
    IPoly &operator+=(const IPoly &b) {
        return *this = *this + b;
    }
    IPoly &operator-=(const IPoly &b) {
        return *this = *this - b;
    }
    IPoly &operator*=(const IPoly &b) {
        return *this = *this * b;
    }
    IPoly &operator*=(Z b) {
        return *this = *this * b;
    }
    IPoly &operator/=(Z b) {
        return *this = *this / b;
    }

    IPoly deriv() const {
        if (this->empty()) {
            return IPoly{};
        }
        IPoly f(this->size() - 1);
        for (int i = 1; i < int(this->size()); ++i) {
            f[i - 1] = (*this)[i] * i;
        }
        return f;
    }
    IPoly integr() const {
        IPoly f(this->size() + 1);
        icomb<P>.init(int(this->size()));
        for (int i = 0; i < int(this->size()); ++i) {
            f[i + 1] = (*this)[i] * icomb<P>.inv_[i + 1];
        }
        return f;
    }
    IPoly inv() const {
        static IPoly a, b;
        assert(!this->empty());
        int len = bitceil(int(this->size()));
        IPoly res{this->front().inv()};
        res.resize(len);
        a.reserve(len), b.reserve(len);
        for (int l = 2; l <= len; l *= 2) {
            a.resize(l);
            std::copy(this->begin(), this->begin() + std::min(l, int(this->size())), a.begin());
            dft(a);
            b.resize(l);
            std::copy(res.begin(), res.begin() + l, b.begin());
            dft(b);
            for (int i = 0; i < l; ++i) {
                a[i] *= b[i];
            }
            idft(a);
            std::fill(a.begin(), a.begin() + l / 2, 0);
            dft(a);
            for (int i = 0; i < l; ++i) {
                a[i] *= -b[i];
            }
            idft(a);
            std::copy(a.begin() + l / 2, a.end(), res.begin() + l / 2);
        }
        return res.trunc(int(this->size()));
    }
    IPoly log() const {
        assert(!this->empty() && this->front() == 1);
        return (deriv() * inv()).trunc(int(this->size()) - 1).integr();
    }
    template <typename F>
    IPoly semiRelaxedConv(F &&relax) const {
        static constexpr int Block = 64;
        static IPoly a;
        assert((Block & (Block - 1)) == 0);
        int len = bitceil(int(this->size()));
        IPoly res(len);
        std::vector<IPoly> d(std::__lg(len));
        a.reserve(len);
        auto next = [&](int m) {
            int l = m & -m;
            if (l < Block) {
                for (int i = m & -Block; i < m; ++i) {
                    res[m] += res[i] * (*this)[m - i];
                }
            } else {
                a.resize(2 * l);
                std::copy(res.begin() + m - l, res.begin() + m, a.begin());
                std::fill(a.begin() + l, a.end(), 0);
                dft(a);
                auto &b = d[std::__lg(l)];
                if (b.empty()) {
                    b = trunc(2 * l);
                    dft(b);
                }
                for (int i = 0; i < 2 * l; ++i) {
                    a[i] *= b[i];
                }
                idft(a);
                for (int i = m; i < m + l; ++i) {
                    res[i] += a[i - m + l];
                }
            }
            res[m] = relax(m, res[m]);
        };
        for (int i = 0; i < int(this->size()); ++i) {
            next(i);
        }
        return res.trunc(int(this->size()));
    }
    IPoly exp() const {
        assert(!this->empty() && this->front() == 0);
        icomb<P>.init(int(this->size()));
        return deriv().shift(1).semiRelaxedConv([&inv = icomb<P>.inv_](int p, Z x) {
            return p == 0 ? 1 : x * inv[p];
        });
    }
    IPoly pow(i64 k) const {
        if (k == 0) {
            return IPoly{1}.trunc(int(this->size()));
        }
        int i = std::find_if(this->begin(), this->end(), [](Z x) {
            return x != 0;
        }) - this->begin();
        if (i >= (int(this->size()) - 1) / k + 1) {
            return IPoly(int(this->size()));
        }
        Z x = (*this)[i];
        auto f = shift(-i).trunc(int(this->size()) - i * k) / x;
        return (f.log() * k).exp().shift(i * k) * power(x, k);
    }
    IPoly sqrt() const {
        int i = std::find_if(this->begin(), this->end(), [](Z x) {
            return x != 0;
        }) - this->begin();
        if (i == int(this->size())) {
            return IPoly(this->size());
        }
        if (i % 2) {
            return IPoly{};
        }
        auto f = shift(-i);
        auto sq = sqrtMod(f.front());
        if (sq.empty()) {
            return IPoly{};
        }
        IPoly g{sq.front()};
        int k = 1;
        while (k < int(this->size())) {
            k *= 2;
            g = (g + (f.trunc(k) * g.trunc(k).inv()).trunc(k)) * CInv<2, P>;
        }
        return g.trunc(int(this->size()) - i / 2).shift(i / 2);
    }
    std::vector<Z> eval(std::vector<Z> x) const {
        if (this->empty()) {
            return std::vector<Z>(x.size());
        }

        std::vector<Z> ans(x.size());
        const int n = int(std::max(x.size(), this->size()));
        std::vector<IPoly> s(n << 2);

        auto init = [&](auto self, int u, int l, int r) -> void {
            s[u].reserve(bitceil(r - l));
            if (r - l == 1) {
                return;
            }
            int m = (l + r) / 2;
            self(self, u << 1, l, m);
            self(self, u << 1 | 1, m, r);
        };
        init(init, 1, 0, n);

        x.resize(n);
        auto build = [&](auto self, int u, int l, int r) -> void {
            if (r - l == 1) {
                s[u] = IPoly{1, -x[l]};
                return;
            }
            int m = (l + r) / 2;
            self(self, u << 1, l, m);
            self(self, u << 1 | 1, m, r);
            s[u] = s[u << 1] * s[u << 1 | 1];
        };
        build(build, 1, 0, n);

        auto mulT = [&](const IPoly &a, IPoly b) {
            if (b.empty()) {
                return IPoly{};
            }
            int n = int(b.size());
            std::reverse(b.begin(), b.end());
            b.resize(a.size());
            dft(b);
            for (int i = 0; i < int(a.size()); ++i) {
                b[i] *= a[i];
            }
            idft(b);
            return b.shift(-(n - 1));
        };
        auto work = [&](auto self, int u, int l, int r, IPoly v) -> void {
            v.resize(r - l);
            if (r - l == 1) {
                if (l < int(ans.size())) {
                    ans[l] = v[0];
                }
                return;
            }
            int m = (l + r) / 2;
            v.resize(bitceil(v.size()));
            dft(v);
            self(self, u << 1, l, m, mulT(v, s[u << 1 | 1]));
            self(self, u << 1 | 1, m, r, mulT(v, s[u << 1]));
        };
        auto d = *this;
        d.resize(bitceil(d.size() + n + 1));
        dft(d);
        work(work, 1, 0, n, mulT(d, s[1].inv()));

        return ans;
    }
};
} // namespace Polynomial

using Polynomial::IPoly;

namespace MTT {
constexpr int M[3] = {167772161, 469762049, 998244353};
constexpr i64 M01 = 1ll * M[0] * M[1];
constexpr MInt<M[1]> inv0_1 = MInt<M[1]>(M[0]).inv();
constexpr MInt<M[2]> inv1_2 = MInt<M[2]>(M01).inv();

using Poly = std::vector<int>;

inline int CRT(int a, int b, int c, const int P) {
    i64 d = 1ll * ((b - a) * inv0_1).val() * M[0] + a;
    return (1ll * ((c - d) * inv1_2).val() * (M01 % P) % P + d) % P;
}
Poly convolution(const Poly &f, const Poly &g, const int P) {
    auto res0 = IPoly<M[0]>(f.begin(), f.end()) * IPoly<M[0]>(g.begin(), g.end());
    auto res1 = IPoly<M[1]>(f.begin(), f.end()) * IPoly<M[1]>(g.begin(), g.end());
    auto res2 = IPoly<M[2]>(f.begin(), f.end()) * IPoly<M[2]>(g.begin(), g.end());
    Poly res(f.size() + g.size() - 1);
    for (int i = 0; i < int(res.size()); ++i) {
        res[i] = CRT(res0[i].val(), res1[i].val(), res2[i].val(), P);
    }
    return res;
}
} // namespace MTT

constexpr int P = 998244353;
using Z = MInt<P>;
using Comb = IComb<P>;
using Poly = IPoly<P>;
#define comb icomb<P>

constexpr Z G = Polynomial::primitiveRoot<P>;

std::vector<int> mnp, pri;
void sieve(int n) {
    mnp.assign(n + 1, 0);
    pri.clear();
    for (int i = 2; i <= n; ++i) {
        if (mnp[i] == 0) {
            mnp[i] = i;
            pri.push_back(i);
        }
        for (auto p : pri) {
            if (i * p > n) {
                break;
            }
            mnp[i * p] = p;
            if (p == mnp[i]) {
                break;
            }
        }
    }
}

std::vector<int> getLog(int n) {
    sieve(n);
    const int B = std::sqrt(P / (pri.size() + 1)) * 7;
    static std::unordered_map<int, int> mp;
    static std::bitset<P> vis;
    Z x = 1, coef = power(G, B);
    for (int i = 0; i <= P / B + 1; ++i) {
        mp[x.val()] = i * B;
        vis.set(x.val());
        x *= coef;
    }

    std::vector<int> lg(n + 1);
    for (auto a : pri) {
        Z x = a, coef = CInv<G.val(), P>;
        for (int i = 0; i <= B; ++i) {
            if (vis[x.val()]) {
                lg[a] = i + mp[x.val()];
                break;
            }
            x *= coef;
        }
    }
    for (int i = 2; i <= n; ++i) {
        if (mnp[i] != i) {
            lg[i] = lg[mnp[i]] + lg[i / mnp[i]];
        }
    }

    return lg;
}

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);

    int n;
    std::cin >> n;

    std::vector<Z> a(n);
    for (int i = 0; i < n; ++i) {
        std::cin >> a[i];
    }

    std::string s;
    std::cin >> s;

    auto lg = getLog(n - 1);
    std::vector<int> cnt(n + 2);
    for (int i = 0; i < n; ++i) {
        cnt[i + 1 - (s[i] == '+' ? 1 : -1)] += 1;
    }
    auto f = MTT::convolution(lg, cnt, P - 1);

    Z ans = 0;
    for (int i = 1; i < n; ++i) {
        Z res = a[i] * comb.ifac(i) * (s[i - 1] == '+' ? 1 : -1) * power(G, f[i]);
        if (i >= 2 && s[i - 2] != '+') {
            res = 0;
        }
        ans += res;
    }
    ans = (ans + a[0]) * comb.fac(n - 1);

    std::cout << ans << "\n";

    return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 0ms
memory: 31352kb

input:

4
9 1 4 1
-+-

output:

46

result:

ok 1 number(s): "46"

Test #2:

score: 0
Accepted
time: 13ms
memory: 31276kb

input:

5
1 2 3 4 5
+-+-

output:

998244313

result:

ok 1 number(s): "998244313"

Test #3:

score: -100
Wrong Answer
time: 311ms
memory: 158848kb

input:

100000
664815434 205025136 871445392 797947979 379688564 336946672 231295524 401655676 526374414 670533644 156882283 372427821 700299596 166140732 677498490 44858761 185182210 559696133 813911251 842364231 681916958 114039865 222372111 784286397 437994571 152137641 650875922 613727135 209302742 5321...

output:

71806189

result:

wrong answer 1st numbers differ - expected: '178167352', found: '71806189'