zoukankan      html  css  js  c++  java
  • Luogu 4512 【模板】多项式除法

    高级操作,感觉非常神仙。

    题目中的字母太难懂了,重新定义一下。

    $$A(x) = B(x) * C(x) + D(x)$$

    其中,$A(x)$的次数是$n$,$B(x)$的次数是$m$,$A, B$都已知,要求$C$的次数是$n - m$,$D$的次数小于$m$。

    定义一种操作:

    如果$A$的次数为$n$,那么

    $$A_R(x) = x^nA(frac{1}{x})$$

    其实就是把一个多项式各项系数翻转过来。

    比如$A(x) = x^3 + 2x^2 + 3x + 5$,有

    $$A_R(x) = 5x^3 + 3x^2 + 2x + 1$$

    有了这个操作之后就可以变魔术了。

    发现这个$D(x)$很难受,想办法把它搞掉。

    $$A(x) = B(x) * C(x) + D(x)$$

    $$A(frac{1}{x}) = B(frac{1}{x})C(frac{1}{x}) + D(frac{1}{x})$$

    两边乘上$x^n$,

    $$x^nA(frac{1}{x}) = x^mB(frac{1}{x})x^{n - m}C(frac{1}{x}) + x^{n - m + 1} * x^{m - 1}D(frac{1}{x})$$

    $$A_R(x) = B_R(x)C_R(x) + x^{n - m + 1} D_R(x)$$

    两边模上$x^{n - m + 1}$,

    $$A_R(x) equiv B_R(x)C_R(x) (mod x^{n - m + 1}) $$

    其实就是求逆了呀。

    求出$C(x)$之后只要重新算一遍多项式乘法减掉就可以算出$D(x)$了。

    时间复杂度$O(nlogn)$。

    Code:

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    typedef vector <ll> poly;
    
    const int N = 1e5 + 5;
    
    namespace Poly {
        const int L = 1 << 18;
        const ll P = 998244353LL;
        
        int lim, pos[L];
        
        inline void deb(poly c) {
            for (int i = 0; i < (int)c.size(); i++)
                printf("%lld%c", c[i], " 
    "[i == (int)c.size() - 1]);
        }
        
        template <typename T>
        inline void inc(T &x, T y) {
            x += y;
            if (x >= P) x -= P;
        }
        
        template <typename T>
        inline void sub(T &x, T y) {
            x -= y;
            if (x < 0) x += P;
        }
        
        inline ll fpow(ll x, ll y) {
            ll res = 1;
            for (; y > 0; y >>= 1) {
                if (y & 1) res = res * x % P;
                x = x * x % P;
            }
            return res;
        }
        
        inline void prework(int len) {
            int l = 0;
            for (lim = 1; lim < len; lim <<= 1, ++l);
            for (int i = 0; i < lim; i++)
                pos[i] = (pos[i >> 1] >> 1) | ((i & 1) << (l - 1));
        }
        
        inline void ntt(poly &c, int opt) {
            c.resize(lim, 0);
            for (int i = 0; i < lim; i++)
                if (i < pos[i]) swap(c[i], c[pos[i]]);
            for (int i = 1; i < lim; i <<= 1)  {
                ll wn = fpow(3, (P - 1) / (i << 1));
                if (opt == -1) wn = fpow(wn, P - 2);
                for (int len = i << 1, j = 0; j < lim; j += len) {
                    ll w = 1;
                    for (int k = 0; k < i; k++, w = w * wn % P) {
                        ll x = c[j + k], y = w * c[j + k + i] % P;
                        c[j + k] = (x + y) % P, c[j + k + i] = (x - y + P) % P; 
                    }
                }
            }
            
            if (opt == -1) {
                ll inv = fpow(lim, P - 2);
                for (int i = 0; i < lim; i++) c[i] = c[i] * inv % P;
            }
        }
        
        inline poly mul(const poly x, const poly y) {
            poly u = x, v = y, res;
            prework(x.size() + y.size() - 1);
            ntt(u, 1), ntt(v, 1);
            for (int i = 0; i < lim; i++) res.push_back(u[i] * v[i] % P);
            ntt(res, -1);
            res.resize(x.size() + y.size() - 1);
            return res;
        }
        
        poly getInv(poly x, int len) {
            x.resize(len, 0);
            if (len == 1) {
                poly res;
                res.push_back(fpow(x[0], P - 2));
                return res;
            }
            
            poly y = getInv(x, (len + 1) >> 1);
            
            prework(len << 1);
            poly u = x, v = y, res;
            ntt(u, 1), ntt(v, 1);
            for (int i = 0; i < lim; i++) res.push_back(v[i] * ((2LL - u[i] * v[i] % P + P) % P) % P);
            ntt(res, -1);
            
            res.resize(len, 0);
            return res;
        }
        
        inline poly getDiv(poly x, poly y) {
            poly u = x, v = y, res;
            
            reverse(u.begin(), u.end());
            reverse(v.begin(), v.end());    
    //        deb(u), deb(v);
            
            int len = x.size() - y.size() + 1;
            u.resize(len, 0), v.resize(len, 0);
            
    //        deb(u), deb(v);
            
            res = getInv(v, len);
            
    //        deb(res);
            
            res = mul(u, res);
            res.resize(len);
    //        deb(u);
            
            reverse(res.begin(), res.end());
            
            return res;
        }
        
        inline poly getRest(poly x, poly y) {
            poly u = x, v = y, res = getDiv(x, y);
            
            v = mul(v, res);
            res = u;
            int len = max(u.size(), v.size());
            res.resize(len, 0), v.resize(len, 0);
            for (int i = 0; i < len; i++) res[i] = (res[i] - v[i] + P) % P;
            
            for (; !res.empty() && !res[res.size() - 1]; res.pop_back());
            return res;
        }
        
    }
    
    using Poly :: getDiv;
    using Poly :: getRest;
    
    template <typename T>
    inline void read(T &X) {
        X = 0; char ch = 0; T op = 1;
        for (; ch > '9'|| ch < '0'; ch = getchar())
            if (ch == '-') op = -1;
        for (; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    int main() {
        int n, m;
        read(n), read(m);
        ++n, ++m;
        
        poly x, y;
        x.resize(n, 0), y.resize(m, 0);
        for (int i = 0; i < n; i++) read(x[i]);
        for (int i = 0; i < m; i++) read(y[i]);
        
        poly u = getDiv(x, y), v = getRest(x, y);
        for (int i = 0; i < (int)u.size(); i++)
            printf("%lld%c", u[i], " 
    "[i == (int)u.size() - 1]);
        for (int i = 0; i < (int)v.size(); i++) 
            printf("%lld%c", v[i], " 
    "[i == (int)v.size() - 1]);
        
        return 0;
    }
    View Code
  • 相关阅读:
    Vue $nextTick的一个使用场景
    Vue 使用v-for对Object进行遍历
    JavaScript 回调函数的简单示例
    VSCode 自定义Vue snippets, 快速生成Vue模板
    git将一个分支完全覆盖另外一个分支如:dev分支代码完全覆盖某一个开发分支
    解决bootstrap时间输入框总被浏览器记住的记录遮挡住的问题
    Fiddler 屏蔽JS、抓WebSocket协议、查看接口响应时间、模拟并发请求
    细说MySQL的时间戳(Timestamp)类型
    网站建设之域名注册和域名备案
    日常项目测试用例检查点(来自一线测试人员的吐血总结)
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/10322908.html
Copyright © 2011-2022 走看看