编程语言
首页 > 编程语言> > 狂恋多项式算法(FFT,NTT,生成函数,插值,求逆...)

狂恋多项式算法(FFT,NTT,生成函数,插值,求逆...)

作者:互联网

咕咕咕~~

P3803 【模板】多项式乘法(FFT)(MODULE + FFT)

#include <bits/stdc++.h>
using namespace std;
static constexpr int N = 4000010;
static constexpr double eps = 1e-6;
struct cp {
	double r, i;
	cp(double _r = 0, double _i = 0) : r(_r), i(_i) { }
	cp operator+(const cp x) { return cp(r + x.r, i + x.i); }
	cp operator-(const cp x) { return cp(r - x.r, i - x.i); }
	cp operator*(const cp x) { return cp(r * x.r - i * x.i, r * x.i + i * x.r); }
};
static const double pi = acos(-1.0);
void FFT(cp a[], int n, int t = 1) {
    for (int i = 1, j = 0; i < n - 1; ++i) {
        for (int s = n; j ^= s >>= 1, ~j & s; );
        if (i < j) swap(a[i], a[j]);
    }
    for (int d = 0; (1 << d) < n; ++d) {
        int m = 1 << d, m2 = m << 1;
        double o = pi / m * t;
        cp _w(cos(o), sin(o));
        for (int i = 0; i < n; i += m2) {
            cp w(1, 0);
            for (int j = 0; j < m; ++j) {
                cp&A = a[i + j + m], &B = a[i + j], t = w * A;
                A = B - t; B = B + t; w = w * _w;
            }
        }
    }
    if (t == -1) for (int i = 0; i < n; ++i) a[i].r /= n;
}
cp a[N << 1], b[N];
int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 0; i <= n; ++i) cin >> a[i].r;
    for (int i = 0; i <= m; ++i) cin >> b[i].r;

    int siz = 1;
    while ((siz <<= 1) <= n + m);

    FFT(a, siz), FFT(b, siz);
    for (int i = 0; i <= siz; ++i) a[i] = a[i] * b[i];
    FFT(a, siz, -1);

    for (int i = 0; i <= n + m; ++i) {
        printf("%.0f ", a[i].r + eps);
    }
    return 0;
}

P1919 【模板】A*B Problem升级版(FFT快速傅里叶)(MODULE + FFT + 高精度乘法)

#include <bits/stdc++.h>
using namespace std;
static constexpr int N = 4000010;
static constexpr double eps = 0.5;
// (模板略)
int ans[N], stk[N], top = 1;
cp _a[N << 1], _b[N];
int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    string a, b;
    cin >> a >> b;
    int n1 = a.length(), n2 = b.length();
    for (int i = 0; i < n1; ++i) _a[i].r = a[n1 - i - 1] - '0';
    for (int i = 0; i < n2; ++i) _b[i].r = b[n2 - i - 1] - '0';
    int n = 1;
    while ((n <<= 1) <= n1 + n2);// n <<= 1;
    
    FFT(_a, n), FFT(_b, n);
    for (int i = 0; i <= n; ++i) _a[i] = _a[i] * _b[i];
    FFT(_a, n, -1);
    
    for (int i = 0; i <= n1 + n2; ++i) {
        ans[i] += int(_a[i].r + eps);
        ans[i + 1] += ans[i] / 10;
        ans[i] %= 10;
        stk[++top] = ans[i];
    }
    while (!stk[top]) top--;
    while (top != 1) {
        cout << stk[top];
        top --;
    }
    return 0;
}

P2553 [AHOI2001]多项式乘法(字符串操作 + FFT)

#include <bits/stdc++.h>
using namespace std;
static constexpr int N = 1000010;
static constexpr double eps = 1e-6;
// (模板略)
char poly[N];
cp a1[N], a2[N], ans[N];
int len, i = 1, ind; // ind 表示 index --> 当前已经输入的多项式的度 deg 之和
void setpoly(cp a[]) {
    while (poly[i] != ')' && i < len) {
        int x = 0, z = 0;
        while (!isdigit(poly[i]))
            i++;
        x = poly[i] - '0';
        if (isdigit(poly[i + 1])) {
            i++;
            x = x * 10 + poly[i] - '0';
        }
        i++;
        if (poly[i] == 'a') {
            i++;
            i++;
            z = poly[i] - '0';
            if (isdigit(poly[i+1])) {
                i++;
                z = z * 10 + poly[i] - '0';
            }
            i++;
        }
        ind ++;
        a[z].r += x;
    }
}
int main() {
    while (gets(poly), poly[0]) {
        len = strlen(poly);
        memset(a1, 0, sizeof(a1));
        memset(a2, 0, sizeof(a2));
        memset(ans, 0, sizeof(ans));
        i = 1, ind = 0;
        setpoly(a1);
        i++;
        setpoly(a2);

        int siz = 1;
        while ((siz <<= 1) <= ind);
        
        FFT(a1, siz), FFT(a2, siz);
        for (int i = 0; i <= siz; ++i) ans[i] = a1[i] * a2[i];
        FFT(ans, siz, -1);

        bool first = false;
        for (int j = siz; j >= 0; j--) {
            if (int(ans[j].r + eps) == 0)
                continue;
            if (first)
                putchar('+');
            else
                first = true;
            if (j > 0)
                printf("%.0fa^%d", ans[j].r + eps, j);
            else
                printf("%.0f", ans[j].r + eps);
        }
        putchar(10);
        memset(poly, 0, sizeof(poly));
    }
    return 0;
}

BZOJ3771. Triple(生成函数+容斥原理+FFT)

排列计数常使用构造指数型生成函数解决。

n 排 列 数 n排列数 n排列数的生成函数表示为 n n n个生成函数的积。

A ( x ) + A 2 ( x ) − B ( x ) 2 ! + A 3 ( x ) − 3 A ( x ) B ( x ) + 2 C ( x ) 3 ! A(x) + \dfrac{A^2(x) - B(x)}{2!} +\dfrac{A^3(x) - 3A(x)B(x)+2C(x)}{3!} A(x)+2!A2(x)−B(x)​+3!A3(x)−3A(x)B(x)+2C(x)​

// (模板中 struct cp 里加一句) cp operator/(const double&x) { return cp(r / x, i / x); }
cp A[N], B[N], C[N];
inline void work() {
    int n; in(n);
    int M = INT_MIN; 
    forn(i,1,n) {
        int t; in(t);
        A[t].r ++, B[t << 1].r ++, C[t * 3].r ++;
        M = max(M, t * 3);
    }
    int siz = 1;
    while ((siz <<= 1) <= M << 1);
    FFT(A, siz), FFT(B, siz), FFT(C, siz);
    forn(i, 0, siz) {
        A[i] = A[i] + (A[i] * A[i] - B[i]) / 2 + (A [i] * A[i] * A[i] - cp(3., 0) * A[i] * B[i] + cp(2., 0) * C[i]) / 6.;
    }
    FFT(A, siz, -1);
    forn (i, 1, M << 1) {
        LL ans = LL(A[i].r + .5);
        if (ans) {
            out(i), putchar(32), out(ans), putchar(10);
        }
    }
}

BZOJ3513 [MUTC2013]idiots(反向思考 + 生成函数 + FFT)

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false), cin.tie(nullptr)
#define forn(i, s, e) for (int i = s; i <= int(e); ++i)
#define forr(i, e, s) for (int i = e; i >= int(s); --i)
using namespace std;
using LL = long long;
static constexpr int N = 1000010;

// (模板略)

LL f[N << 1], g[N];
cp a[N];
void solve() {
    double ans;
    LL M = LLONG_MIN, siz = 1, tot, n;
    in(n);
    forn(i, 1, n) {
        LL t; in(t);
        a[t].r ++;
        M = max(M, t);
        f[t << 1] --; // 对于 t + t 的情况,是多余的,需要去重
    }
    forr(i, M, 1) g[i] = g[i + 1] + LL(a[i].r);
    
    while ((siz <<= 1) <= M << 1);
    FFT(a, siz);
    forn(i, 0, siz) a[i] = a[i] * a[i];
    FFT(a, siz, -1);

    forn(i, 0, siz) {
        f[i] += (LL)(a[i].r + .5);
        f[i] >>= 1;
        // 考虑到 i = j + k, (j, k)cyc 于是 i = k + j 也成立, 应去重
    }
    ans = tot = (n) * (n - 1) / 2 * (n - 2) / 3;
    // 2 | ( n × (n - 1) ) 并且有 3 | ( n × (n - 1) × (n - 2) ) 避免溢出
    // (虽然 n ^ 3 < LLONG_MAX ), 但是很秀(bushi)
    
    forn (i, 0, M) ans -= f[i] * g[i];
    // 统计不合法的情况
    
    printf("%.7f\n", 1. * ans / tot);
    // .f 而不是 .lf 老生常谈了
    
    fill_n(f, siz << 1, 0), fill_n(g, siz, 0), fill_n(a, siz, 0);
    // 用多少清多少, 而不是 memset
}
inline void work() {
    int tt; in(tt); while (tt --) solve();
}

P3321 [SDOI2015]序列统计

P3338 [ZJOI2014]力

P3702 [SDOI2017]序列计数

P3723 [AH2017/HNOI2017]礼物

P3763 [TJOI2017]DNA

P3784 [SDOI2017] 遗忘的集合

P3789 Azuki loves coloring

P4002 [清华集训2017]生成树计数

P4091 [HEOI2016/TJOI2016]求和

P4157 [SCOI2006]整数划分

P4173 残缺的字符串

P4191 [CTSC2010]性能优化

P4199 万径人踪灭

P4221 [WC2018]州区划分

P4233 射命丸文的笔记

P4238 【模板】多项式乘法逆

P4239 任意模数多项式乘法逆

P4245 【模板】任意模数多项式乘法

P4389 付公主的背包

P4461 [CQOI2018]九连环

P4566 [CTSC2018]青蕈领主

P4705 玩游戏

P4717 【模板】快速莫比乌斯/沃尔什变换 (FMT/FWT)

P4721 【模板】分治 FFT

P4725 【模板】多项式对数函数(多项式 ln)

P4726 【模板】多项式指数函数(多项式 exp)

P4841 [集训队作业2013]城市规划

P4986 逃离

P5050 【模板】多项式多点求值

P5075 [JSOI2012] 分零食

P5158 【模板】多项式快速插值

P5162 WD与积木

P5277 【模板】多项式开根(加强版)

P5282 【模板】快速阶乘算法

P5293 [HNOI2019]白兔之舞

P5373 【模板】多项式复合函数

P5383 普通多项式转下降幂多项式

P5393 下降幂多项式转普通多项式

P5394 【模板】下降幂多项式乘法

P5432 A/B Problem (高精度除法)

P5488 差分与前缀和

P5519 [MtOI2019]埋骨于弘川

P5641 【CSGRound2】开拓者的卓识

P5667 拉格朗日插值2

P5702 调和级数求和

P5748 集合划分计数

P5808 【模板】常系数非齐次线性递推

标签:...,求逆,cn,luogu,www,狂恋,https,problem,com
来源: https://blog.csdn.net/m0_53680064/article/details/118879219