首页 > 其他分享 >【模板】多项式乘法、乘法逆、除法、取模、常系数齐次线性递推

【模板】多项式乘法、乘法逆、除法、取模、常系数齐次线性递推

时间:2023-09-24 21:47:52浏览次数:28  
标签:取模 return int rhs vector modint const 递推 乘法

以下代码必须开 -O2

#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
typedef long long LL;
template <unsigned P> struct modint {
    unsigned v; modint() : v(0) {}
    template <class T> modint(T x) { x %= (int)P, v = x < 0 ? x + P : x; }
    modint operator+() const { return *this; }
    modint operator-() const { return modint(0) - *this; }
    modint inv() const { return assert(v), qpow(*this, P - 2); }
    friend int raw(const modint &self) { return self.v; }
    template <class T> friend modint qpow(modint a, T b) {
        modint r = 1;
        for (; b; b >>= 1, a *= a) if (b & 1) r *= a;
        return r;
    }
    modint &operator+=(const modint &rhs) { if (v += rhs.v, v >= P) v -= P; return *this; }
    modint &operator-=(const modint &rhs) { if (v -= rhs.v, v >= P) v += P; return *this; }
    modint &operator*=(const modint &rhs) { v = 1ull * v * rhs.v % P; return *this; }
    modint &operator/=(const modint &rhs) { return *this *= rhs.inv(); }
    friend modint operator+(modint lhs, const modint &rhs) { return lhs += rhs; }
    friend modint operator-(modint lhs, const modint &rhs) { return lhs -= rhs; }
    friend modint operator*(modint lhs, const modint &rhs) { return lhs *= rhs; }
    friend modint operator/(modint lhs, const modint &rhs) { return lhs /= rhs; }
    friend bool operator==(const modint &lhs, const modint &rhs) { return lhs.v == rhs.v; }
    friend bool operator!=(const modint &lhs, const modint &rhs) { return lhs.v != rhs.v; }
};
typedef modint<998244353> mint;
const int glim(const int &x){return 1 << (32 - __builtin_clz(x));}
const int bitctz(const int &x){return __builtin_ctz(x);}
const vector<mint> wns = []() -> vector<mint> {
    vector<mint> wns = {};
    for (int j = 1; j <= 23; j++)
        wns.push_back(qpow(mint(3), (998244353 - 1) >> j));
    return wns;
}();
void ntt(vector<mint> &a, const int &op) {
    const int n = a.size();
    for (int i = 1, r = 0; i < n; i++) {
        r ^= n - (1 << (bitctz(n) - bitctz(i) - 1));
        if (i < r) swap(a[i], a[r]);
    }
    vector<mint> w(n);
    for (int k = 1, len = 2; len <= n; k <<= 1, len <<= 1) {
        const mint wn = wns[bitctz(k)];
        for (int i = raw(w[0] = 1); i < k; i++) w[i] = w[i - 1] * wn;
        for (int i = 0; i < n; i += len) {
            for (int j = 0; j < k; j++) {
                const mint x = a[i + j], y = a[i + j + k] * w[j];
                a[i + j] = x + y, a[i + j + k] = x - y;
            }
        }
    }
    if (op == -1) {
        mint iz = mint(1) / n;
        for (int i = 0; i < n; i++) a[i] *= iz;
        reverse(a.begin() + 1, a.end());
    }
}
vector<mint> getInv(const vector<mint> &a, int lim) {
    vector<mint> b = {1 / a[0]};
    for (int len = 2; len <= glim(lim); len <<= 1) {
        vector<mint> c(a.begin(), a.begin() + min(len, (int)a.size()));
        b.resize(len << 1), ntt(b, 1);
        c.resize(len << 1), ntt(c, 1);
        for (int i = 0; i < len << 1; i++)
            b[i] = b[i] * (2 - c[i] * b[i]);
        ntt(b, -1), b.resize(len);
    }
    b.resize(lim);
    return b;
}
vector<mint> multiple(vector<mint> a, vector<mint> b) {
    int rLen = a.size() + b.size() - 1, len = glim(rLen);
    a.resize(len), ntt(a, 1);
    b.resize(len), ntt(b, 1);
    for (int i = 0; i < len; i++) a[i] *= b[i];
    ntt(a, -1), a.resize(rLen);
    return a;
}
vector<mint> divide(vector<mint> f, vector<mint> g) {
    if (f.size() < g.size()) return {};
    int rLen = f.size() - g.size() + 1;
    reverse(f.begin(), f.end());
    reverse(g.begin(), g.end());
    f = multiple(f, getInv(g, rLen));
    f.resize(rLen), reverse(f.begin(), f.end());
    return f;
}
vector<mint> modulo(vector<mint> f, vector<mint> g) {
    int rLen = g.size() - 1;
    vector<mint> q = multiple(g, divide(f, g));
    q.resize(rLen), f.resize(rLen);
    for (int i = 0; i < rLen; i++) f[i] -= q[i];
    return f;
}
vector<mint> qpow(vector<mint> a, int b, vector<mint> m) {
    vector<mint> r = {1};
    for (; b; b >>= 1, a = modulo(multiple(a, a), m)) {
        if (b & 1) r = modulo(multiple(r, a), m);
    }
    return r;
}
int main() {
    int n, k;
    scanf("%d%d", &n, &k);
    vector<mint> m(k + 1), a(k);
    m[k] = 1;
    for (int i = k - 1, x; i >= 0; i--) scanf("%d", &x), m[i] = -x;
    for (int i = 0, x; i < k; i++) scanf("%d", &x), a[i] = x;
    vector<mint> b = qpow({0, 1}, n, m);
    mint ans = 0;
    for (int i = 0; i < k; i++) ans += b[i] * a[i];
    printf("%d\n", raw(ans));
    return 0; 
}

标签:取模,return,int,rhs,vector,modint,const,递推,乘法
From: https://www.cnblogs.com/caijianhong/p/solution-p4723.html

相关文章

  • 高精度乘法
    1#include<iostream>2#include<vector>3usingnamespacestd;45vector<int>mul(vector<int>&A,int&b)6{7vector<int>C;8intt=0;9for(inti=0;i<A.size()||t;i++)10......
  • 数论——线性同余方程、乘法逆元 学习笔记
    数论——线性同余方程、乘法逆元众所周知:说明除非特殊说明,以下提到的exgcd函数均定义为://ax+by=gcd(a,b)llexgcd(lla,llb,ll&x,ll&y,lld=0){if(b==0)x=1,y=0,d=a;elsed=exgcd(b,a%b,y,x),y-=a/b*x;return......
  • 【模板】模意义下的乘法逆元
    由于老是搞混,故开此文。exgcd快速幂线性递推参考资料:当然是洛谷的题解啦!!!link.......
  • 最小二乘法求解线性回归模型
    ✅作者简介:热爱科研的算法开发者,Python、Matlab项目可交流、沟通、学习。......
  • 59-嵌套循环练习-九九乘法表-打印表格数据
        打印上半截,靠右对齐,目前没实现      ......
  • C#使用NPOI读取模板生成EXCEL
     C#使用NPOI读取模板生成EXCELstringcurrentDirectory=System.AppDomain.CurrentDomain.BaseDirectory;//读取Excel模板文件FileStreamfs=newFileStream(currentDirectory+"BoxPackinglist.xlsx",FileMode.Open,FileA......
  • 九九乘法表c语言
    intmain(){ inti=1; intj=0; for(i=1;i<=9;i++) { for(j=1;j<=i;j++) {  printf("%d*%d=%-2d",j,i,j*i);//%-2d表示控制宽度为两个字符,且右对齐 } printf("\n"); } return0;}......
  • 快速傅里叶变换计算多项式乘法
    前言OI中,多项式有着十分广泛的应用。其基础是多项式的基本运算,几乎所有多项式运算都是由多项式加法和乘法拼接成的。我们有显然的\(O(n)\)的办法计算多项式加法,而朴素的多项式乘法是很多情况下难以接受的\(O(n^2)\)的复杂度。快速傅里叶变换(FFT)可以高效(\(O(n\logn)\))计算多......
  • 关于取模、进制的问题
    先来定义一下取模(b不等于0)。\(r(a,b)=a-b\times\lfloor\frac{a}{b}\rfloor=t\)下面讨论一下t的取值范围。b>0\(k=\lfloor\frac{a}{b}\rfloor\),则\(r(a,b)=a-kb\)。因为\(k\le\frac{a}{b}<k+1\),\(a-b\times\frac{a}{b}=0\)。配凑一下,就是\(a-bk-b&l......
  • Verilog实现定点乘法器
    实验目的理解定点乘法的不同实现算法的原理,掌握基本实现算法。熟悉并运用Verilog语言进行电路设计。为后续设计CPU的实验打下基础。实验内容定点乘法器有多种实现,实验要求实现迭代乘法器,其结构如图所示。乘数每次右移一位,根据最低位,判断是加被乘数移位后的值还是加0,......