QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#200522#622. 多项式多点求值NOI_AK_ME0 0ms0kbC++2310.1kb2023-10-04 17:17:222023-10-04 17:17:23

Judging History

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

  • [2023-10-04 17:17:23]
  • 评测
  • 测评结果:0
  • 用时:0ms
  • 内存:0kb
  • [2023-10-04 17:17:22]
  • 提交

answer

// GENERATE FROM https://github.com/rogeryoungh/code-of-acm
// GENERATE DATE: 2021-12-06 12:04:38.144951

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using i128 = __int128_t;
using ull = unsigned long long;
using ld = long double;
using vi = vector<int>;
using pii = pair<int, int>;

#define _fore(i, a) for (ll i = head[(a)]; i; i = edge[i].nxt)
#define _dbg(...) 1
#define dbg(x) 1

ll rr() {
    ll s = 0, w = 1;
    char c = getchar();
    while (!isdigit(c))
        w = 1 - 2 * (c == '-'), c = getchar();
    while (isdigit(c))
        s = s * 10 + c - '0', c = getchar();
    return s * w;
}

// END OF HEADER

#include <vector>

#define ACM_MOD 998244353
const int P = ACM_MOD;


#ifdef ACM_MOD
int qpow(ll a, ll b = ACM_MOD - 2, ll m = ACM_MOD) {
#else
int qpow(ll a, ll b, ll m) {
#endif
    ll ret = m != 1;
    for (; b; b >>= 1) {
        if (b & 1)
            ret = ret * a % m;
        a = a * a % m;
    }
    return ret;
}


ll mo(ll n) {
    return (n + P) % P;
}

ll momo(ll n) {
    return ((n % P) + P) % P;
}

struct Mint {
    int v = 0;
    Mint(int _v = 0) {
        v = _v;
    }
    Mint &operator=(const int &m) {
        v = m;
        return *this;
    }
    Mint &operator+=(const Mint &m) {
        v += m.v;
        v = v < P ? v : v - P;
        return *this;
    }
    Mint &operator-=(const Mint &m) {
        v -= m.v;
        v = v < 0 ? v + P : v;
        return *this;
    }
    Mint operator-() const {
        if (v > 0)
            return P - v;
        return 0;
    }
    Mint &operator*=(const Mint &m) {
        v = ll(v) * m.v % P;
        return *this;
    }
    Mint operator+(const Mint &m) const {
        return Mint(*this) += m;
    }
    Mint operator-(const Mint &m) const {
        return Mint(*this) -= m;
    }
    Mint operator*(const Mint &m) const {
        return Mint(*this) *= m;
    }
    Mint inv() const {
        return qpow(v, P - 2);
    }
    Mint pow(int n) const {
        return qpow(v, n, P);
    }
    Mint sqrt() const {
#ifdef ACM_MATH_CIPOLLA_H
        return Cipolla(v, P).first;
#else
        return 1;
#endif
    }
};




struct Poly : std::vector<Mint> {
    using vector::vector;
    bool isNTT = false;
    Poly(Poly::const_iterator pi, int len) : Poly(pi, pi + len) {}
    Poly rev() const {
        return Poly(rbegin(), rend());
    }
    Poly cut(int m) const {
        m = min<int>(size(), m);
        return Poly(begin(), begin() + m);
    }
    Poly &resize(int m) {
        vector::resize(m);
        return *this;
    }
    friend Poly operator+(Poly f, Poly g);
    friend Poly operator-(Poly f, Poly g);
    friend Poly operator*(Poly f, Poly g);
    Poly& ntt(int m);
    Poly& nttD(int m);
    Poly& intt(int m);
    Poly& invD(Poly f2, Poly nx, int t);
    Poly inv() const;
    Poly div(Poly g) const;
    Poly deriv() const;
    Poly integr() const;
    Poly ln() const;
    Poly exp() const;
    Poly sqrt() const;
    Poly pow(int k) const;
    Poly mod() const;
};




Poly w{0}, Inv{1, 1}, fac{1}, ifac{1};


int get_lim(int sum) {
    int lim = 1, k = 0;
    while (lim < sum)
        lim <<= 1, k++;
    return lim;
}

void pre_w(int n) {
    static int lim = (w = {1, 1}, 2);
    n = get_lim(n);
    if (n <= lim)
        return;
    w.resize(n);
    for (int l = lim; l < n; l *= 2) {
        int p = qpow(3, (P - 1) / l / 2, P);
        for (int i = 0; i < l; i += 2) {
            w[(l + i)] = w[(l + i) / 2];
            w[l + i + 1] = w[l + i] * p;
        }
    }
    lim = n;
}


void pre_inv(int n) {
    static int LIM = (Inv = {1, 1}, 2);
    if (n <= LIM)
        return;
    Inv.resize(n);
    for (int i = LIM; i < n; i++) {
        Inv[i] = Inv[P % i] * (P - P / i);
    }
    LIM = n;
}


void ntt(Poly::iterator f, int deg) {
    pre_w(deg);
    for (int l = deg >> 1; l; l >>= 1)
        for (auto fi = f; fi - f < deg; fi += l * 2)
            for (int j = 0; j < l; j++) {
                Mint x = fi[j] + fi[j + l];
                fi[j + l] = w[j + l] * (fi[j] - fi[j + l]);
                fi[j] = x;
            }
}

void intt(Poly::iterator f, int deg) {
    for (int l = 1; l < deg; l <<= 1)
        for (auto fi = f; fi - f < deg; fi += l * 2)
            for (int j = 0; j < l; j++) {
                Mint x = fi[j], y = fi[j + l] * w[j + l];
                fi[j] = x + y, fi[j + l] = x - y;
            }
    const Mint deg_inv = P - (P - 1) / deg;
    for (int i = 0; i < deg; i++)
        f[i] *= deg_inv;
    std::reverse(f + 1, f + deg);
}

Poly &Poly::ntt(int n) {
    if (!isNTT) {
        resize(n);
        ::ntt(begin(), n);
        isNTT = true;
    }
    return *this;
}

Poly &Poly::intt(int m) {
    ::intt(begin(), m);
    isNTT = false;
    return *this;
}

void nttD(Poly::iterator f, int n) {
    std::copy_n(f, n, f + n);
    intt(f + n, n);
    for (int i = n; i < n * 2; i++)
        f[i] *= w[i];
    ntt(f + n, n);
}

Poly &Poly::nttD(int n) {
    resize(n * 2);
    ::nttD(begin(), n);
    return *this;
}


Poly& mul(Poly &f, Poly &g, int sz) {
    f.ntt(sz), g.ntt(sz);
    for (int i = 0; i < sz; i++)
        f[i] *= g[i];
    return f.intt(sz);
}

Poly operator*(Poly f, Poly g) {
    if (f.size() < g.size())
        swap(f, g);
    int u = f.size() + g.size() - 1;
    return mul(f, g, get_lim(u)).cut(u);
}

Poly operator+(Poly f, Poly g) {
    if (f.size() < g.size())
        std::swap(f, g);
    for (int i = 0; i < g.size(); i++)
        f[i] += g[i];
    return f;
}

Poly operator-(Poly f, Poly g) {
    for (auto &i : g)
        i = -i;
    return std::move(f) + g;
}

Mint mulAt(const Poly f, const Poly g, int u) {
    int n = f.size() - 1, m = g.size() - 1;
    int a = max(0, u - m), b = min(u, n);
    Mint ans = 0;
    for (int i = a; i <= b; i++)
        ans += f[i] * g[u - i];
    return ans;
}


//Poly Poly::inv() const { // 12E
//    int lim = get_lim(size());
//    Poly f = {qpow(front().v, P - 2)};
//    for (int t = 2; t <= lim; t <<= 1) {
//        Poly u = cut(t);
//        f.ntt(t * 2), u.ntt(t * 2); // 4E + 4E
//        for (int i = 0; i < t * 2; i++)
//            f[i] *= Mint(2) - f[i] * u[i];
//        f = f.intt(t * 2).cut(t); // 4E
//    }
//    return f.cut(size());
//}

//Poly Poly::div(Poly g) const { // 16E
//    return (*this * g.inv()).cut(size());
//}

Poly &Poly::invD(Poly f2, Poly nx, int t) {
    mul(f2, nx, t); // 6E
    fill_n(f2.begin(), t / 2, 0);
    mul(f2, nx, t); // 4E
    resize(t);
    for (int i = t / 2; i < t; i++)
        (*this)[i] = -f2[i];
    return *this;
}

Poly Poly::inv() const { // 10E
    Poly x = {front().inv()};
    if (size() == 1)
        return x;
    int lim = get_lim(size());
    for (int t = 2; t <= lim; t <<= 1) {
        x.invD(cut(t), x.cut(t), t);
    }
    return x.cut(size());
}

Poly Poly::div(Poly f2) const { // 13E
    if (size() == 1)
        return { front() * f2[0].inv() };
    int t = get_lim(size());
    Poly h = cut(t / 2), g = f2.cut(t / 2).inv(); // 10E

    Poly &x = mul(h, g, t), q = x.cut(t / 2); // 6E
    mul(q, f2, t); // 6E
    for (int i = t / 2; i < size(); i++)
        q[i] -= (*this)[i];
    fill_n(q.begin(), t / 2, 0);
    mul(q, g, t);  // 4E
    for (int i = t / 2; i < t; i++) x[i] = -q[i];
    return x.cut(size());
}



struct PolyEI {
    std::vector<Poly> p;
    int n, raw_n;
    PolyEI(Poly a) {
        raw_n = a.size(), n = get_lim(raw_n);
        dbg(raw_n), dbg(n);
        a.resize(n), p.resize(n * 2);
        for (int i = 0; i < n; i++)
            p[i + n] = {1, -a[i]};
        for (int i = n - 1; i > 0; i--) {
            int ls = i * 2, rs = i * 2 + 1;
            int len = get_lim(p[ls].size());
            p[ls].ntt(len), p[rs].ntt(len), p[i].resize(len);
            for (int j = 0; j < len; j++)
                p[i][j] = p[ls][j] * p[rs][j];
            p[i].intt(len);
            p[i].push_back(p[i][0] - 1), p[i][0] = 1;
        }
//        p[1].resize(n / 2);
    }
    // usage: PolyEI(x).eval(f)
    Poly eval(Poly f) const {
        int m = f.size();
        if (m == 1)
            return Poly(raw_n, f[0]);
        Poly q = f.rev().div(p[1].cut(n));
        q.resize(n), rotate(q.begin(), q.begin() + m, q.end());
        for (int k = n, o = 1; k > 1; k >>= 1)
            for (int i = 0; i < n; i += k, o++) {
                if (i >= raw_n)
                    continue;
                Poly foo(k), bar(k);
                auto qi = q.begin() + i;
                ntt(qi, k);
                for (int j = 0; j < k; j++) {
                    foo[j] = qi[j] * p[o * 2 + 1][j];
                    bar[j] = qi[j] * p[o * 2][j];
                }
                foo.intt(k), bar.intt(k);
                std::copy(foo.begin() + k / 2, foo.end(), qi);
                std::copy(bar.begin() + k / 2, bar.end(), qi + k / 2);
            }
        return q.cut(raw_n);
    }
    // usage: PolyEI(x).inter(y)
    Poly inter(const Poly &y) const {
        Poly q = p[1];
        q.resize(raw_n + 1);
        q = eval(q.rev().deriv());
        for (int i = 0; i < raw_n; i++)
            q[i] =  y[i] * q[i].inv();
        q.resize(n);
        for (int k = 1, h = n >> 1; k < n; k *= 2, h >>= 1)
            for (int i = 0, o = h; i < n; i += k * 2, o++) {
                if (i >= raw_n)
                    continue;
                auto qi = q.begin() + i;
                Poly foo(qi, qi + k), bar(qi + k, qi + k * 2);
                foo.ntt(k * 2), bar.ntt(k * 2);
                for (int j = 0; j < k * 2; j++) {
                    qi[j] = foo[j] * p[o * 2 + 1][j] + bar[j] * p[o * 2][j];
                }
                intt(qi, k * 2);
            }
        return q.cut(raw_n).rev();
    }
};



int main() {
    ll n = rr() + 1, m = rr();
    Poly f(n), x(m);
    for (int i = 0; i < n; i++)
        f[i] = rr();
    for (int i = 0; i < m; i++)
        x[i] = rr();
    auto g = PolyEI(x).eval(f);
    for (auto v : g)
        printf("%d\n", v.v);
    return 0;
}

详细

Test #1:

score: 0
Time Limit Exceeded

input:

100 94
575336069 33153864 90977269 80162592 25195235 334936051 108161572 14050526 356949084 797375084 805865808 286113858 995555121 938794582 458465004 379862532 563357556 293989886 273730531 13531923 113366106 126368162 405344025 443053020 475686818 734878619 338356543 661401660 834651229 527993675...

output:


result:


Test #2:

score: 0
Time Limit Exceeded

input:

5000 4999
410683245 925831211 726803342 144364185 955318244 291646122 334752751 893945905 484134283 203760731 533867267 813509277 491860093 413174124 584582617 594704162 976489328 978500071 196938934 628117769 169796671 858963950 562124570 582491326 647830593 238623335 20782490 674939336 656529076 2...

output:


result:


Test #3:

score: 0
Time Limit Exceeded

input:

30000 29995
536696866 881441742 356233606 594487396 991820796 695996817 7219464 149265950 843761437 329761701 260625152 80366362 598729314 133794090 12808683 67477659 320740422 878134577 879383179 940923483 660160621 18082378 886078389 524050341 35092018 137623841 988429688 258507355 138475726 75726...

output:


result:


Test #4:

score: 0
Time Limit Exceeded

input:

100000 99989
703908936 826436271 431732352 607460686 960390248 897906950 506352459 662618885 172508812 713410533 704313866 156459539 879660919 98030681 46358006 400134234 121190289 498201666 616888945 210891377 39623412 687350951 269444705 980768130 381802923 553892268 644461704 287608268 554761733 ...

output:


result:


Test #5:

score: 0
Time Limit Exceeded

input:

1000000 999998
326289172 459965021 432610030 381274775 890620650 133203219 755508578 820410129 100497878 978894337 34545975 484258543 341383383 556328539 705716773 985485996 201697555 806763870 456757110 445252781 501965590 655584951 516373423 475444481 554722275 106826011 433893131 385018453 687541...

output:


result: