QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#109389#6513. Expression 3FFTilted#TL 3837ms42416kbC++2019.0kb2023-05-28 21:14:402023-05-28 21:14:45

Judging History

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

  • [2024-02-14 13:23:19]
  • hack成功,自动添加数据
  • (/hack/531)
  • [2023-08-10 23:21:45]
  • System Update: QOJ starts to keep a history of the judgings of all the submissions.
  • [2023-05-28 21:14:45]
  • 评测
  • 测评结果:TL
  • 用时:3837ms
  • 内存:42416kb
  • [2023-05-28 21:14:40]
  • 提交

answer

#include "bits/stdc++.h"

#define rep(i, n) for (int i = 0; i < (n); ++i)
#define rep1(i, n) for (int i = 1; i < (n); ++i)
#define rep1n(i, n) for (int i = 1; i <= (n); ++i)
#define repr(i, n) for (int i = (n) - 1; i >= 0; --i)
#define pb push_back
#define eb emplace_back
#define all(a) (a).begin(), (a).end()
#define rall(a) (a).rbegin(), (a).rend()
#define each(x, a) for (auto &x : a)
#define ar array
#define vec vector
#define range(i, n) rep(i, n)

using namespace std;

using ll = long long;
using ull = unsigned long long;
using ld = long double;
using str = string;
using pi = pair<int, int>;
using pl = pair<ll, ll>;

using vi = vector<int>;
using vl = vector<ll>;
using vpi = vector<pair<int, int>>;
using vvi = vector<vi>;

int Bit(int mask, int b) { return (mask >> b) & 1; }

template<class T>
bool ckmin(T &a, const T &b) {
    if (b < a) {
        a = b;
        return true;
    }
    return false;
}

template<class T>
bool ckmax(T &a, const T &b) {
    if (b > a) {
        a = b;
        return true;
    }
    return false;
}

const int INFi = 1e9;
const ll INF = 3e18;
const int LG = 20;

template<typename T>
int normalize(T value, int mod) {
    if (value < -mod || value >= 2 * mod)
        value %= mod;

    if (value < 0)
        value += mod;

    if (value >= mod)
        value -= mod;

    return value;
}

template<int mod>
struct static_modular_int {
    using mint = static_modular_int<mod>;

    int value;

    static_modular_int() : value(0) {}

    static_modular_int(const mint &x) : value(x.value) {}

    template<typename T, typename U = std::enable_if_t<std::is_integral<T>::value>>
    static_modular_int(T value) : value(normalize(value, mod)) {}

    template<typename T>
    mint power(T degree) const {
        degree = normalize(degree, mod - 1);
        mint prod = 1;
        mint a = *this;

        for (; degree > 0; degree >>= 1, a *= a)
            if (degree & 1)
                prod *= a;

        return prod;
    }

    mint inv() const {
        return power(-1);
    }

    mint &operator=(const mint &x) {
        value = x.value;
        return *this;
    }

    mint &operator+=(const mint &x) {
        value += x.value;
        if (value >= mod)
            value -= mod;

        return *this;
    }

    mint &operator-=(const mint &x) {
        value -= x.value;
        if (value < 0)
            value += mod;

        return *this;
    }

    mint &operator*=(const mint &x) {
        value = (long long) value * x.value % mod;
        return *this;
    }

    mint &operator/=(const mint &x) {
        return *this *= x.inv();
    }

    friend mint operator+(const mint &x, const mint &y) {
        return mint(x) += y;
    }

    friend mint operator-(const mint &x, const mint &y) {
        return mint(x) -= y;
    }

    friend mint operator*(const mint &x, const mint &y) {
        return mint(x) *= y;
    }

    friend mint operator/(const mint &x, const mint &y) {
        return mint(x) /= y;
    }

    mint &operator++() {
        ++value;
        if (value == mod)
            value = 0;

        return *this;
    }

    mint &operator--() {
        --value;
        if (value == -1)
            value = mod - 1;

        return *this;
    }

    mint operator++(int) {
        mint prev = *this;
        value++;
        if (value == mod)
            value = 0;

        return prev;
    }

    mint operator--(int) {
        mint prev = *this;
        value--;
        if (value == -1)
            value = mod - 1;

        return prev;
    }

    mint operator-() const {
        return mint(0) - *this;
    }

    bool operator==(const mint &x) const {
        return value == x.value;
    }

    bool operator!=(const mint &x) const {
        return value != x.value;
    }

    bool operator<(const mint &x) const {
        return value < x.value;
    }

    template<typename T>
    explicit operator T() {
        return value;
    }

    friend std::istream &operator>>(std::istream &in, mint &x) {
        std::string s;
        in >> s;
        x = 0;
        for (const auto c: s)
            x = x * 10 + (c - '0');

        return in;
    }

    friend std::ostream &operator<<(std::ostream &out, const mint &x) {
        return out << x.value;
    }

    static int primitive_root() {
        if constexpr (mod == 1'000'000'007)
            return 5;

        if constexpr (mod == 998'244'353)
            return 3;

        if constexpr (mod == 786433)
            return 10;

        static int root = -1;
        if (root != -1)
            return root;

        std::vector<int> primes;
        int value = mod - 1;
        for (int i = 2; i * i <= value; i++)
            if (value % i == 0) {
                primes.push_back(i);
                while (value % i == 0)
                    value /= i;
            }

        if (value != 1)
            primes.push_back(value);

        for (int r = 2;; r++) {
            bool ok = true;
            for (auto p: primes)
                if ((mint(r).power((mod - 1) / p)).value == 1) {
                    ok = false;
                    break;
                }

            if (ok)
                return root = r;
        }
    }
};

// constexpr int MOD = 1'000'000'007;
constexpr int MOD = 998'244'353;
using mint = static_modular_int<MOD>;

namespace FFT {
    template<typename T>
    void normilize(T &poly) {
        while (!poly.empty() && poly.back() == 0)
            poly.pop_back();
    }

    template<int mod>
    void fft(std::vector<static_modular_int<mod>> &a) {
        using mint = static_modular_int<mod>;

        if (a.empty())
            return;

        static mint primitive_root = mint::primitive_root();
        int n = int(a.size());
        assert((n & (n - 1)) == 0);
        int lg = std::__lg(n);

        static std::vector<int> reversed_mask;
        if (int(reversed_mask.size()) != n) {
            reversed_mask.resize(n);
            for (int mask = 1; mask < n; mask++)
                reversed_mask[mask] = (reversed_mask[mask >> 1] >> 1) + ((mask & 1) << (lg - 1));
        }

        static std::vector<mint> roots;
        if (int(roots.size()) != lg) {
            roots.resize(lg);
            for (int i = 0; i < lg; i++)
                roots[i] = primitive_root.power((mod - 1) / (2 << i));
        }

        for (int i = 0; i < n; i++)
            if (reversed_mask[i] < i)
                std::swap(a[i], a[reversed_mask[i]]);

        for (int len = 1; len < n; len <<= 1) {
            mint root = roots[std::__lg(len)];
            for (int i = 0; i < n; i += (len << 1)) {
                mint current = 1;
                for (int j = 0; j < len; j++, current *= root) {
                    mint value = a[i + j + len] * current;
                    a[i + j + len] = a[i + j] - value;
                    a[i + j] = a[i + j] + value;
                }
            }
        }
    }

    template<int mod, typename T>
    std::vector<static_modular_int<mod>> multiply(T a_begin, T a_end, T b_begin, T b_end) {
        using mint = static_modular_int<mod>;

        std::vector<mint> a(a_begin, a_end);
        std::vector<mint> b(b_begin, b_end);
        if (a_begin == a_end || b_begin == b_end)
            return {};

        if (std::min(a.size(), b.size()) <= 20 || std::max(a.size(), b.size()) <= 64) {
            std::vector<mint> prod(int(a.size() + b.size()) - 1);
            for (int i = 0; i < int(a.size()); i++)
                for (int j = 0; j < int(b.size()); j++)
                    prod[i + j] += a[i] * b[j];

            return prod;
        }

        int real_size = int(a.size() + b.size()) - 1;
        int n = 1;
        while (n < real_size)
            n <<= 1;

        a.resize(n);
        b.resize(n);
        fft(a), fft(b);

        for (int i = 0; i < n; i++)
            a[i] *= b[i];

        fft(a);
        std::reverse(a.begin() + 1, a.end());

        mint inv_n = mint(n).inv();
        a.resize(real_size);
        for (auto &x: a)
            x *= inv_n;

        return a;
    }

    template<int mod>
    void fft_2d(std::vector<std::vector<static_modular_int<mod>>> &a, bool invert) {
        using mint = static_modular_int<mod>;

        for (int rot: {0, 1}) {
            for (auto &v: a) {
                fft(v);
                if (invert) {
                    std::reverse(v.begin() + 1, v.end());
                    mint inv_n = mint(v.size()).inv();
                    for (auto &x: v)
                        x *= inv_n;
                }
            }

            for (int i = 0; i < int(a.size()); i++)
                for (int j = 0; j < i; j++)
                    std::swap(a[i][j], a[j][i]);
        }
    }

    template<int mod, typename T>
    std::vector<std::vector<static_modular_int<mod>>> multiply_2d(T a_begin, T a_end, T b_begin, T b_end) {
        using mint = static_modular_int<mod>;

        if (a_begin == a_end || b_begin == b_end || (*a_begin).empty() || (*b_begin).empty())
            return {};

        int real_size_x = std::distance(a_begin, a_end) + std::distance(b_begin, b_end) - 1;
        int real_size_y = int((*a_begin).size() + (*b_begin).size()) - 1;
        int base = 2;
        while (base < std::max(real_size_x, real_size_y))
            base <<= 1;

        auto get = [&](T a_begin, T a_end) {
            std::vector<std::vector<mint>> a(base, std::vector<mint>(base));
            for (int i = 0; a_begin != a_end; i++, a_begin++)
                for (int j = 0; j < int((*a_begin).size()); j++)
                    a[i][j] = (*a_begin)[j];

            return a;
        };

        auto a = get(a_begin, a_end), b = get(b_begin, b_end);
        fft_2d(a, false);
        fft_2d(b, false);

        for (int i = 0; i < base; i++)
            for (int j = 0; j < base; j++)
                a[i][j] *= b[i][j];

        fft_2d(a, true);
        a.resize(real_size_x);
        for (auto &v: a)
            v.resize(real_size_y);

        return a;
    }

    // returns p^-1 modulo x^degree
    template<int mod, typename T>
    std::vector<static_modular_int<mod>> inverse(T begin, T end, int degree) {
        using mint = static_modular_int<mod>;

        int size = std::distance(begin, end);
        assert(size > 0 && *(begin) != 0);

        std::vector<mint> inv(std::min(degree, 128)), have(inv.size());
        mint start_inv = 1 / *begin;
        for (int i = 0; i < int(inv.size()); i++) {
            inv[i] = ((i == 0 ? 1 : 0) - have[i]) * start_inv;
            int steps = std::min(size, int(have.size()) - i);
            for (int j = 0; j < steps; j++)
                have[i + j] += inv[i] * *(begin + j);
        }

        for (int power = inv.size(); power < degree; power <<= 1) {
            auto product = multiply<mod>(inv.begin(), inv.end(), begin, begin + std::min(size, 2 * power));
            for (int i = 0; i < std::min<int>(product.size(), 2 * power); i++)
                product[i] = (i == 0 ? 2 : 0) - product[i];

            inv = multiply<mod>(inv.begin(), inv.end(),
                                product.begin(), product.begin() + std::min<int>(product.size(), 2 * power));
            inv.resize(2 * power);
        }
        inv.resize(degree);
        return inv;
    }

    // returns (quotient, remainder)
    template<int mod, typename T>
    std::pair<std::vector<static_modular_int<mod>>, std::vector<static_modular_int<mod>>>
    divide(T a_begin, T a_end, T b_begin, T b_end) {
        using mint = static_modular_int<mod>;

        std::vector<mint> a(a_begin, a_end), b(b_begin, b_end);
        normilize(a), normilize(b);
        assert(!b.empty());
        int n = int(a.size()), m = int(b.size());
        if (n < m)
            return {{}, a};

        if (n <= 128 || m <= 64) {
            std::vector<mint> quotient(n - m + 1);
            mint inv_b = 1 / b.back();
            for (int i = n - 1; i >= m - 1; i--) {
                int pos = i - m + 1;
                quotient[pos] = a[i] * inv_b;
                for (int j = 0; j < m; j++)
                    a[pos + j] -= b[j] * quotient[pos];
            }
            normilize(a);
            return {quotient, a};
        }

        std::reverse(a.begin(), a.end());
        std::reverse(b.begin(), b.end());
        auto inv_b = inverse<mod>(b.begin(), b.end(), n - m + 1);
        auto quotient = multiply<mod>(a.begin(), a.end(), inv_b.begin(), inv_b.end());
        quotient.resize(n - m + 1);
        std::reverse(quotient.begin(), quotient.end());
        normilize(quotient);

        std::reverse(a.begin(), a.end());
        std::reverse(b.begin(), b.end());
        auto product = multiply<mod>(quotient.begin(), quotient.end(), b.begin(), b.end());
        assert(int(product.size()) == int(a.size()));

        std::vector<mint> remainder(m);
        for (int i = 0; i < m; i++)
            remainder[i] = a[i] - product[i];

        normilize(remainder);
        return {quotient, remainder};
    }

    template<int mod, typename T>
    std::vector<static_modular_int<mod>> multipoint_evaluation(T p_begin, T p_end, T x_begin, T x_end) {
        using mint = static_modular_int<mod>;

        int n = std::distance(x_begin, x_end);
        if (n == 0)
            return {};

        static constexpr int N = 32;
        const int tree_size = (n + N - 1) / N;
        std::vector<std::vector<mint>> tree(tree_size << 1);
        for (int v = 0; v < tree_size; v++) {
            int from = v * N, to = std::min(n, from + N);
            tree[tree_size + v].resize(to - from + 1);
            tree[tree_size + v][0] = 1;
            for (int i = from; i < to; i++) {
                for (int j = i - from; j >= 0; j--) {
                    tree[tree_size + v][j + 1] += tree[tree_size + v][j];
                    tree[tree_size + v][j] *= -*(x_begin + i);
                }
            }
        }

        for (int v = tree_size - 1; v > 0; v--)
            tree[v] = FFT::multiply<MOD>(tree[v << 1].begin(), tree[v << 1].end(),
                                         tree[v << 1 | 1].begin(), tree[v << 1 | 1].end());

        tree[1] = divide<MOD>(p_begin, p_end, tree[1].begin(), tree[1].end()).second;
        for (int v = 2; v < 2 * tree_size; v++)
            tree[v] = divide<MOD>(tree[v >> 1].begin(), tree[v >> 1].end(),
                                  tree[v].begin(), tree[v].end()).second;

        std::vector<mint> eval(n);
        for (int v = 0; v < tree_size; v++) {
            int from = v * N, to = std::min(n, from + N);
            for (int i = from; i < to; i++) {
                mint cur_power = 1;
                for (int j = 0; j < int(tree[tree_size + v].size()); j++, cur_power *= *(x_begin + i))
                    eval[i] += cur_power * tree[tree_size + v][j];
            }
        }
        return eval;
    }

    // returns log(p) modulo x^degree
    template<int mod, typename T>
    std::vector<static_modular_int<mod>> log(T begin, T end, int degree) {
        using mint = static_modular_int<mod>;

        std::vector<mint> p(begin, end), pp = p;
        assert(!p.empty() && p[0] == 1);
        for (int i = 0; i + 1 < int(pp.size()); i++)
            pp[i] = pp[i + 1] * (i + 1);

        pp.pop_back();
        std::vector<mint> inv_p = inverse<mod>(p.begin(), p.end(), degree);
        std::vector<mint> prod = multiply<mod>(pp.begin(), pp.end(), inv_p.begin(), inv_p.end());
        prod.resize(degree);
        for (int i = degree - 1; i > 0; i--)
            prod[i] = prod[i - 1] / i;

        prod[0] = 0;
        return prod;
    }

    // returns exp(p) modulo x^degree
    template<int mod, typename T>
    std::vector<static_modular_int<mod>> exp(T begin, T end, int degree) {
        using mint = static_modular_int<mod>;

        std::vector<mint> p(begin, end), exp{1};
        while (int(exp.size()) < degree) {
            std::vector<mint> lg = log<mod>(exp.begin(), exp.end(), 2 * exp.size());
            std::vector<mint> cur(2 * exp.size());
            cur[0] = 1;
            for (int i = 0; i < int(2 * exp.size()); i++) {
                cur[i] -= lg[i];
                if (i < int(p.size()))
                    cur[i] += p[i];
            }
            std::vector<mint> new_exp = multiply<mod>(exp.begin(), exp.end(), cur.begin(), cur.end());
            new_exp.resize(2 * exp.size());
            exp.swap(new_exp);
        }
        exp.resize(degree);
        return exp;
    }
} // namespace FFT


void solve() {
    int n;
    cin >> n;
    vector<mint> a(n);
    rep(i, n) {
        int x;
        cin >> x;
        a[i] = x % MOD;
    }
    string s;
    cin >> s;
    vector<mint> val(n - 1);
    vector<mint> dp(n - 1);
    rep(i, n - 1) {
        if (s[i] == '+') dp[i] = 1;
        else dp[i] = (MOD - 1);
        val[i] = dp[i];
    }
    int sz = 0;
    vector<vector<mint>> tree;
    vector<vector<mint>> tmp;
    vector<int> pos;
    vi pred;
    function<int(int, int)> build = [&](int l, int r) {
        if (l + 1 == r) {
            tree.emplace_back();
            tree[sz] = {-l, 1};
            pred.push_back(-1);
            pos.push_back(sz);
            return sz++;
        }
        int v = sz++;
        pred.push_back(-1);
        tree.emplace_back();
        int L = build(l, (l + r) >> 1);
        int R = build((l + r) >> 1, r);
        pred[L] = pred[R] = v;
        tree[v] = FFT::multiply<MOD>(all(tree[L]), all(tree[R]));
        return v;
    };
    build(0, n - 1);
    tmp.resize(sz);

    sz = 0;
    function<vector<mint>(int, int)> rec = [&](int l, int r) {
        if (l + 1 == r) {
            sz++;
            return vector<mint>{val[l] - l, 1};
        }
        int v = sz++;
        int mid = (l + r) >> 1;
        int Lv = sz;
        auto L = rec(l, mid);
        int Rv = sz;
        auto R = rec(mid, r);
        tmp[Rv] = FFT::divide<MOD>(all(L), all(tree[Rv])).second;
        for (int i = Rv + 1; i < sz; ++i) tmp[i] = FFT::divide<MOD>(all(tmp[pred[i]]), all(tree[i])).second;

        for (int i = mid; i < r; ++i) {
            if (tmp[pos[i]].empty()) {
                dp[i] *= 0;
                continue;
            }
            assert(tmp[pos[i]].size() >= 1);
            dp[i] *= tmp[pos[i]][0];
        }
        return FFT::multiply<MOD>(all(L), all(R));
    };
    rec(0, n - 1);
//    rep(i, n - 1) cout << dp[i] << ' ';
//    cout << '\n';
    mint ans = 0;
    mint fact = 1;
    for (int i = n - 1; i >= 1; --i) {
        dp[i - 1] *= fact;
        fact *= i;
    }
    rep(i, n) {
        if (i == 0) ans += a[i] * fact;
        else ans += dp[i - 1] * a[i];
    }
    cout << ans << '\n';
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout << setprecision(12) << fixed;
    int t = 1;
//    cin >> t;
    rep(i, t) {
        solve();
    }
    return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

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

input:

4
9 1 4 1
-+-

output:

46

result:

ok 1 number(s): "46"

Test #2:

score: 0
Accepted
time: 2ms
memory: 3456kb

input:

5
1 2 3 4 5
+-+-

output:

998244313

result:

ok 1 number(s): "998244313"

Test #3:

score: 0
Accepted
time: 3837ms
memory: 42416kb

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:

178167352

result:

ok 1 number(s): "178167352"

Test #4:

score: -100
Time Limit Exceeded

input:

200000
109044620 745578941 396599814 756923982 940933214 875346257 378089839 792684563 491924893 782192923 208569108 421583135 814903710 690275542 15773609 364566266 12890134 661702679 640270667 615999192 13352194 325560419 385152885 265008089 570536451 282429805 331946208 255056541 813809151 150995...

output:


result: