首页 > 其他分享 >P4721 【模板】分治 FFT

P4721 【模板】分治 FFT

时间:2024-02-07 21:45:14浏览次数:30  
标签:limits int FFT rev len ++ long P4721 模板

最具经济性的写法:\(\mathcal O(n^2)\) 暴力拿下 \(80\) 分,遂跑路。

一题多解了,分两部分:分治多项式求逆

分治

考虑 cdq 分治,每次把 \(f_{l \dots mid}\) 和 \(g_{1 \dots n - 1}\) 卷起来,贡献直接加到 \(f_{mid + 1 \dots r}\) 里,要注意一下顺序,先递归左区间,再算当前区间,最后递归右区间,否则不能确保正确性。

时间复杂度 \(T(n) = 2T(\dfrac n2) + \mathcal O(n \log n) = \mathcal O(n \log n)\)。常数较大。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

constexpr int N = 1 << 17, MOD = 998244353;

int n, f[N], g[N], tf[N], tg[N];
int len, bits, rev[N], G[2][17];

ll qp(ll base, int e) {
    ll res = 1;
    while (e) {
        if (e & 1) res = res * base % MOD;
        base = base * base % MOD;
        e >>= 1;
    }
    return res;
}

void NTT(int *A, bool I = 0) {
    for (int i = 0; i < len; i++) if (i < rev[i]) swap(A[i], A[rev[i]]);
    for (int i = 1; i < len; i <<= 1) {
        ll wn = G[I][__builtin_ctz(i)];
        for (int j = 0; j < len; j += (i << 1)) {
            ll w = 1;
            for (int k = j; k < j + i; k++) {
                int t = w * A[k + i] % MOD;
                A[k + i] = (A[k] - t + MOD) % MOD, A[k] = (A[k] + t) % MOD;
                w = w * wn % MOD;
            }
        }
    }
    if (I) {
        ll invlen = qp(len, MOD - 2);
        for (int i = 0; i < len; i++) A[i] = A[i] * invlen % MOD;
    }
}

void cdq(int l, int r) {
    if (l == r) return;
    int mid = (l + r) >> 1; cdq(l, mid);
    len = 1, bits = -1; while (len <= r - l) len <<= 1, bits++;
    for (int i = 0; i < len; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << bits);
    memset(tf, 0, len << 2), memcpy(tf, f + l, (mid - l + 1) << 2), memcpy(tg, g, (r - l + 1) << 2);
    NTT(tf), NTT(tg); for (int i = 0; i < len; i++) tf[i] = (ll)tf[i] * tg[i] % MOD; NTT(tf, 1);
    for (int i = mid + 1; i <= r; i++) f[i] = (f[i] + tf[i - l]) % MOD;
    cdq(mid + 1, r);
}

int main() {
    ios_base::sync_with_stdio(0); cin.tie(nullptr), cout.tie(nullptr);
    cin >> n;
    for (int i = 1; i < n; i++) cin >> g[i];
    for (int i = 0; i < 17; i++) G[0][i] = qp(3, (MOD - 1) / (1 << (i + 1))), G[1][i] = qp(G[0][i], MOD - 2);
    f[0] = 1, cdq(0, n - 1);
    for (int i = 0; i < n; i++) cout << f[i] << ' ';
    return 0;
}

多项式求逆

设 \(F(x) = \sum\limits_{i = 0}^\infin f_ix^i, G(x) = \sum\limits_{i = 0}^\infin g_ix^i, g_0 = 0\)。

\[F(x) * G(x) = \sum\limits_{i = 0}^{\infin}\sum\limits_{j = 0}^if_{i - j}g_jx^i = F(x) - f_0 = F(x) - 1 \]

\[F(x) * [1 - G(x)] \equiv 1 \pmod{x^n} \]

剩下的就是多项式乘法逆板子了。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

constexpr int N = 1 << 18, MOD = 998244353;

int n, f[N], g[N], fg[N];
int len, bits, rev[N], G[2][18];

ll qp(ll base, int e) {
    ll res = 1;
    while (e) {
        if (e & 1) res = res * base % MOD;
        base = base * base % MOD;
        e >>= 1;
    }
    return res;
}

void NTT(int *A, bool I = 0) {
    for (int i = 0; i < len; i++) if (i < rev[i]) swap(A[i], A[rev[i]]);
    for (int i = 1; i < len; i <<= 1) {
        ll wn = G[I][__builtin_ctz(i)];
        for (int j = 0; j < len; j += (i << 1)) {
            ll w = 1;
            for (int k = j; k < j + i; k++) {
                int t = w * A[k + i] % MOD;
                A[k + i] = (A[k] - t + MOD) % MOD, A[k] = (A[k] + t) % MOD;
                w = w * wn % MOD;
            }
        }
    }
    if (I) {
        ll invlen = qp(len, MOD - 2);
        for (int i = 0; i < len; i++) A[i] = A[i] * invlen % MOD;
    }
}

void solve(int e) {
    if (e == 1) return;
    solve((e + 1) >> 1);
    bits = -1, len = 1; while (len < (e << 1) - 1) len <<= 1, bits++;
    for (int i = 0; i < len; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << bits);
    memcpy(fg, f, e << 2), fill(fg + e, fg + len, 0); NTT(fg), NTT(g);
    for (int i = 0; i < len; i++) fg[i] = (ll)fg[i] * g[i] % MOD;
    for (int i = 0; i < len; i++) g[i] = (ll)g[i] * (2 - fg[i] + MOD) % MOD;
    NTT(g, 1); fill(g + e, g + len, 0);
}

int main() {
    ios_base::sync_with_stdio(0); cin.tie(nullptr), cout.tie(nullptr);
    cin >> n; for (int i = 1; i < n; i++) cin >> f[i], f[i] = MOD - f[i];
    for (int i = 0; i < 18; i++) G[0][i] = qp(3, (MOD - 1) / (1 << (i + 1))), G[1][i] = qp(G[0][i], MOD - 2);
    g[0] = qp(f[0] = 1, MOD - 2); solve(n);
    for (int i = 0; i < n; i++) cout << g[i] << ' ';
    return 0;
}

标签:limits,int,FFT,rev,len,++,long,P4721,模板
From: https://www.cnblogs.com/chy12321/p/18011331

相关文章

  • TitanIDE v2.8.0正式发布,模板市场来袭!
    TitanIDEv2.8.0版本正式发布,模板市场中内置40+模版!什么是TitanIDETitanIDE,云端IDE,作为数字化时代研发体系不可或缺的一环,和企业建设好的云服务具有很高的互操作性。秉承“安全、高效、体验”的原则,连接研发体系的各个信息孤岛。Jira、GitLab、Jetbrains全家桶、AndroidStudio、V......
  • 浅蓝色小清新说说文章类个人网站模板代码
    浅蓝色小清新说说文章类织梦dedecms个人博客模板采用DIV+CSS自适应语言制作的文章信息网站模板。整个网站版面宽度为1000px宽度,页面主色调为蓝色,整体大气简洁。浅蓝色小清新说说文章博客模板适用于经典说说、伤感说说、个性说说、搞笑说说、爱情说说等各种QQ说说心情短......
  • 浅蓝色小清新说说文章类个人网站模板代码
    浅蓝色小清新说说文章类织梦dedecms个人博客模板采用DIV+CSS自适应语言制作的文章信息网站模板。整个网站版面宽度为1000px宽度,页面主色调为蓝色,整体大气简洁。浅蓝色小清新说说文章博客模板适用于经典说说、伤感说说、个性说说、搞笑说说、爱情说说等各种QQ说说心情短语......
  • C++编程练习||1.类模板2.整数集合类3.复数集合类,模板结合
    1.类模板 类模板的作用  使用类模板使用户可以为类声明一种模式,使得类中的某些数据成员、某些成员函数的参数、某些成员函数的返回值,能取任意类型(包括基本类型的和用户自定义类型)。  类模板的声明  类模板template<模板参数表>class类名{类成员声明};  ......
  • 蒟蒻的模板
    蒟蒻Rainbow_Automaton的模板\(\text{2023-10}\)备战\(\text{csp-s}\)只是目前会的然而目前啥也不会...代码注意事项不要使用usingnamespacestd;min和max都可以直接std::minstd::max吧关同步#definefastreadstd::ios_sync_with_stdio(false);cin.ti......
  • C++编程练习||1.排序函数模板2.函数模板3.重载printArray函数模板
    1.排序函数模板已知主函数如程序后缀代码所示,请为其编写适当的模板函数,使主函数的bubbleSort函数可以对一个整型数组和一个浮点数数组进行输入、排序、输出操作。#include<iostream>#include<iomanip>usingnamespacestd;template<typenameT>voidbubbleSort(T*arr,......
  • [职场] 插画师简历模板
    一份简历,应该包含求职意向、联系方式、教育背景、实践经历等信息,这些信息能够让用人单位更还得了解到求职者是一个什么样的人,能否胜任这个岗位,那一份用人单位满意的简历应该怎么写,这里就分享一份插画师的简历模板。供大家参考阅读。基本信息院校:蓝山美术学院专业:......
  • 有关各种数据结构模板
    FHQ-Treap模板题-普通平衡树#include<bits/stdc++.h>#definelstr[u].l#definerstr[u].rusingnamespacestd;constintN=3e5+10;structNode{intl,r;intkey,v;intsize;}tr[N];introot,idx;intn,m;voidpushup(intu){tr[u].size......
  • 一套模板搞定二叉树算法题--二叉树算法讲解004
    1、二叉树经典习题模拟忘记知识点和技巧时,遇到一个新的二叉树习题,该如何处理思考和写代码解题?1.1、leetcode965题目和题意:题解1成员变量self.ans:题解2递归回传:1.2、leetcode257该题是个经典二叉树题目题目和题意:题解:分析,所有路径,每一个叶子节点都需要到达。到......
  • hdu 2553 N皇后问题(DFS模板)
    Problem-2553(hdu.edu.cn)#include<iostream>#include<cstring>usingnamespacestd;intn,tot=0;intcol[12];boolcheck(intc,intr){for(inti=0;i<r;i++){if(col[i]==c||(abs(col[i]-c)==abs(i-r)))returnfalse;}r......