多项式板子(待补充)

已经实现的操作

  • 乘法NTT, mul
  • 求逆inverse
  • 积分integral,微分deriv
  • 对数ln
  • 指数exp
  • 快速幂power(常数项为\(1\))
  • 开根sqrt(常数项为\(1\))

说明

  • 所有操作都是原地操作,以后有空改(大量copy还是比较麻烦、耗时)
  • 常数还可以

Code

const int N = 262144, G = 3, iG = 332748118, p = 998244353, maxlen = N;
inline int add(int x, int y){return (x+y) % p;}
inline int sub(int x, int y){return (x-y+p) % p;}
inline int mul(int x, int y){return 1LL * x * y % p;}
int last, rev[N], w[N], invw[N], pinv[N];
inline int qp(int x, int y){
    int res = 1;
    for(; y; y>>=1, x = mul(x, x)) if(y & 1) res = mul(res, x);
    return res;
}

void pre(){
    w[1] = qp(G, (p-1) / maxlen);
    invw[1] = qp(iG, (p-1) / maxlen);
    w[0] = invw[0] = 1;
    for(int i=2; i<maxlen; i++) w[i] = mul(w[i-1], w[1]), invw[i] = mul(invw[i-1], invw[1]);
    pinv[1] = 1;
    for(int i=2; i<maxlen; i++) pinv[i] = mul(p - p / i, pinv[p % i]);
}

void init(int n){
    if(last == n) return ;
    last = n;
    int tp = n, lg = -1;
    while(tp != 1) tp >>= 1, ++lg;
    for(int i=0; i<n; i++)
        rev[i] = (rev[i>>1] >> 1) | ((i & 1) << lg);
}
void NTT(int *f, int n, int *w){
    init(n);
    for(int i=0; i<n; i++) if(rev[i] > i) swap(f[i], f[rev[i]]);
    for(int l=1; l<n; l<<=1){
        int step = maxlen / (l << 1);
        for(int i=0; i<n; i += (l << 1)){
            for(int j=i, Wj=0; j<i+l; j++, Wj += step){
                int x = f[j], y = mul(f[j+l], w[Wj]);
                f[j] = add(x, y); f[j+l] = sub(x, y);
            }
        }
    }
}
void mul(int *f, int *g, int n){ // will make g unavailable
    NTT(f, n, w); NTT(g, n, w);
    for(int i=0; i<n; i++) f[i] = mul(f[i], g[i]);
    NTT(f, n, invw);
    int in = qp(n, p-2);
    for(int i=0; i<n; i++) f[i] = mul(f[i], in);
}

void inverse(int *f, int n){ // n : pow2 length of f
    static int g[N], tp[N];
    g[0] = qp(f[0], p-2);
    for(int i=1; i<n; i<<=1){ // i : last length of g
        copy(f, f+(i<<1), tp);
        NTT(tp, i<<2, w); NTT(g, i<<2, w);
        for(int j=0; j<(i<<2); j++) g[j] = mul(g[j], sub(2, mul(tp[j], g[j])));
        NTT(g, i<<2, invw);
        int invLen = qp((i<<2), p-2);
        for(int j=0; j<(i<<2); j++) g[j] = mul(g[j], invLen);
        fill(g + (i << 1), g + (i << 2), 0);
    }
    copy(g, g+n, f);
    fill(g, g+n, 0);
    fill(tp, tp+(n<<1), 0);
}

void deriv(int *a, int n){
    for(int i=1; i<n; i++) a[i-1] = mul(a[i], i);
    a[n-1] = 0;
}
void integral(int *a, int n){
    for(int i=n-1; i>=0; i--) a[i] = mul(a[i-1], pinv[i]);
    a[0] = 0;
}
void ln(int *a, int n){
    static int tp[N];
    for(int i=0; i<n-1; i++) tp[i] = mul(a[i+1], i+1);
    tp[n-1] = 0;
    inverse(a, n);
    mul(a, tp, n<<1);
    fill(a+n, a+(n<<1), 0);
    integral(a, n);
    fill(tp, tp+(n<<1), 0);
}
void exp(int *a, int n){
    static int f[N], lnf[N], f0[N];
    f[0] = 1;
    for(int i=1; i<n; i<<=1){
        copy(f, f + i, lnf); copy(f, f + i, f0);
        ln(lnf, i << 1);
        for(int j=0; j<(i << 1); j++) f[j] = sub(a[j], lnf[j]);
        ++f[0];
        mul(f, f0, i << 2);
        fill(f + (i << 1), f + (i << 2), 0);
        fill(f0 + (i << 1), f0 + (i << 2), 0);
    }
    copy(f, f+n, a);
    fill(f, f + n, 0);
    fill(lnf, lnf + n, 0);
    fill(f0, f0 + n, 0);
}
void power(int *a, int n, int p){
    if(p == 1) return ;
    ln(a, n);
    for(int i=1; i<n; i++) a[i] = mul(a[i], p);
    exp(a, n);
}
void sqrt(int *a, int n){
    static int f[N], f0[N], invf[N], tp[N];
    f[0] = 1;
    for(int i=1; i<n; i<<=1){
        copy(a, a + (i << 1), tp);
        copy(f, f + i, invf);
        inverse(invf, i<<1);
        copy(f, f + i, f0);
        NTT(tp, i << 2, w);
        NTT(f, i << 2, w);
        NTT(invf, i << 2, w);
        for(int j=0; j<(i<<2); j++) f[j] = mul(sub(mul(f[j], f[j]), tp[j]), mul(pinv[2], invf[j]));
        NTT(f, i << 2, invw);
        int invLen = qp(i << 2, p - 2);
        for(int j=0; j<(i<<1); j++) f[j] = sub(f0[j], mul(f[j], invLen));
        fill(f + (i << 1), f + (i << 2), 0);
        fill(invf + (i << 1), invf + (i << 2), 0);
    }
    copy(f, f+n, a);
    fill(f, f + n, 0);
    fill(tp, tp + (n << 1), 0);
}

原文地址:https://www.cnblogs.com/RiverHamster/p/polynomial-template.html

时间: 2024-10-15 20:48:20

多项式板子(待补充)的相关文章

多项式板子

不包含MTT的板子, 这种有的话就弃疗了 /* 求逆迭代 B = 2B - AB^2 系数反转 F(1 / x) * x ^ n 除法迭代 已知 F(x) = Q(x) * G(x) + R(x) F(x),G(x) 求Q(x) R(x) F(x) = Q(x) * G(x) + R(x) mod x ^ {n + 1} F(1 / x) = Q(1 / x) * G(1 / x) + R(1 / x) mod x ^ {n + 1} Frev(x) = Qrev(x) * Grev(x) +

多项式板子&#183;新

之前写过一个vector的多项式汇总...不过常数特别大 最近事儿比较少,准备写一个int[]的 目前没写完,先打了发多项式求逆,蛙了好几发... 最后发现递归下去回来之后忘了清系数了... int[]版的主要是数组大小和高位系数比较恶心,还有数组清空啥的... 不过常数肯定比vector小很多,所以还是尝试写一下好了 #include <cstdio> #include <algorithm> using namespace std; const int p = 99824435

多项式快速插值

200+行的多项式板子题真爽啊 给定\(n\)个点的点值\((x_i,y_i)\),求这\(n\)个点确定的\(n-1\)次多项式 \(n\le 10^5\) 前置知识: 多项式多点求值 拉格朗日插值 微积分基础 首先我们有一个\(n^2\)的拉格朗日插值法 \[f(x)=\sum\limits_{i=1}^{n}y_i\prod\limits_{i\ne j}\frac{x-x_j}{x_i-x_j}\] 然后我们学习一个WC2017挑战就过了 考虑优化,我们知道这个形式它很死,把它变成重心插

多项式&amp;生成函数

多项式和生成函数 多项式 鸽掉了多项式开根(加强版). 这里放一份多项式板子合集 多项式乘法 背个板子就好了. FFT 泰勒展开与麦克劳林级数 若\(f(x)\)在\(x=x0\)处存在\(n\)阶导,那么: \[ \begin{align} f(x)&=f(x0)+\frac{f^1(x0)}{1!}(x-x0)+\frac{f^2(x0)}{2!}(x-x0)^2+...+\frac{f^n(x0)}{n!}(x-x0)^n+\xi\&=\sum_{i=0}^n\frac{f^i(x0

自选题口胡

上一个坑因为后来时间太紧,于是每天做做做,根本不想写题解了.这次我决定大概保持一天一题到两题的节奏,就不着急啦.(大概不会鸽啦 大概顺序是各处看看哪里有简单题,找找简单题做,无实力选手根本做不动题啊. 119:众数MAX 简单题,显然是卷积状物,不过贡献取决于较小的一项.按照套路根号分治下,大的之间的贡献暴力,小的部分枚举一个固定的值 x 从 1 到阈值,每次把所有 >=x 的拿出来卷积.发现卷积部分跑的很慢,最后大概优化到了 200ms 吧,阈值大概是 6,. 127:Ball cf 原题加强

【全家福】多项式的各种板子

写完帕秋莉的超级多项式于是正好贴个模板大汇总(带优化的那种...) //by Judge #include<bits/stdc++.h> #define Rg register #define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i<I;++i) #define fd(i,a,b) for(Rg int i=(a),I=(b)-1;i>I;--i) #define ll long long using namespace std; const in

UOJ #34 多项式乘法

题目链接:多项式乘法 保存一发FFT与NTT板子. 学习链接:从多项式乘法到快速傅里叶变换 FFT NTT 注意差值回来的时候不取反也是可以的,只不过需要把数组\(reverse\)一下(根据单位复数根的性质应该不难理解) 代码(FFT): #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<co

【uoj34】 多项式乘法

http://uoj.ac/problem/34 (题目链接) 题意 求两个多项式的乘积 Solution 挂个FFT板子.当然,是hzwer的板子→_→ 细节 FFT因为要满足n是2的幂,所以注意数组大小. 代码 // uoj34 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<complex> #include<cst

[学习笔记] 多项式与快速傅里叶变换(FFT)基础

引入 可能有不少OIer都知道FFT这个神奇的算法, 通过一系列玄学的变化就可以在 $O(nlog(n))$ 的总时间复杂度内计算出两个向量的卷积(或者多项式乘法/高精度乘法), 而代码量却非常小. 博主一年半前曾经因COGS的一道叫做"神秘的常数 $\pi$"的题目而去学习过FFT, 但是基本就是照着板子打打完并不知道自己在写些什么鬼畜的东西OwO 不过...博主这几天突然照着算法导论自己看了一遍发现自己似乎突然意识到了什么OwO然后就打了一道板子题还1A了OwO再加上午考试差点AK