分治FFT
分治FFT
目的
解决这样一类式子:
\]
算法
看上去跟普通卷积式子挺像的,但是由于计算\(f\)的每一项时都在利用它前面的项来产生贡献,所以不能一次FFT搞完。用FFT爆算复杂度\(O(n^2logn)\),比直接枚举复杂度还高……
考虑优化这个算法,如果我们要计算区间\([l, r]\)内的\(f\)值,如果可以快速算出区间\([l, mid]\)内的\(f\)值对区间\([mid + 1, r]\)内的\(f\)值产生了怎样的影响,就可以采取CDQ分治,不断递归下去算。
考虑\(x \in [mid + 1, r]\),\([l, mid]\)给它的贡献是:
\]
为了方便,我们将范围扩充到\([1, x - 1]\)(假设此时\(f[mid + 1] ... f[r] = 0\)),因此有:
\]
为了便于FFT计算,将枚举改成从0开始。(把表达式中的\(i\)改成\(i + l\),因为原来的\(i\)等于现在的\(i + l\))
\]
为了表示成卷积形式,我们令:
\]
再在原式中用\(a[i], b[i]\)代替\(f[i], g[i]\).
\]
观察到后面刚好就是多项式乘法中某一项的系数,即
\]
在cdq分治的过程中用FFT/NTT计算即可。
代码
洛谷上的模板,因为要取模,所以用的NTT
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define p 998244353
#define AC 400100
#define LL long long
#define ld double
const int G = 3, Gi = 332748118;
int n, lim, len;
int f[AC], g[AC], a[AC], b[AC], rev[AC];
inline int read()
{
int x = 0;char c = getchar();
while(c > '9' || c < '0') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x;
}
inline void up(int &a, int b) {a += b; if(a < 0) a += p; if(a >= p) a -= p;}
inline int qpow(int x, int have)
{
int rnt = 1;
while(have)
{
if(have & 1) rnt = 1LL * rnt * x % p;
x = 1LL * x * x % p, have >>= 1;
}
return rnt;
}
void init(int length)//这里的length已经是2个数组加起来的长度了
{
lim = 1, len = 0;
while(lim <= length) lim <<= 1, ++ len;
for(R i = 0; i < lim; i ++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (len - 1)), a[i] = b[i] = 0;
}
void NTT(int *A, int opt)
{
for(R i = 0; i < lim; i ++)
if(i < rev[i]) swap(A[i], A[rev[i]]);
for(R i = 1; i < lim; i <<= 1)
{
LL W = qpow((opt > 0) ? G : Gi, (p - 1) / (i << 1));
for(R r = i << 1, j = 0; j < lim; j += r)
for(R k = 0, w = 1; k < i; k ++, w = 1LL * w * W % p)
{
int x = A[j + k], y = 1LL * w * A[j + k + i] % p;
A[j + k] = (x + y) % p, A[j + k + i] = (x - y) % p;
}
}
if(opt == -1)
{
int inv = qpow(lim, p - 2);
for(R i = 0; i < lim; i ++) A[i] = 1LL * A[i] * inv % p;
}
}
void pre()
{
n = read(), f[0] = 1;
for(R i = 1; i < n; i ++) g[i] = read();
}
void cal(int *A, int *B)
{
NTT(A, 1), NTT(B, 1);
for(R i = 0; i <= lim; i ++) A[i] = 1LL * A[i] * B[i] % p;
NTT(A, -1);
}
void cdq(int l, int r)
{
if(l == r) return ;
int mid = (l + r) >> 1, length = r - l + 1;
cdq(l, mid);
init(length);
for(R i = l; i <= mid; i ++) a[i - l] = f[i];
for(R i = 1; i < length; i ++) b[i - 1] = g[i];//这里要移动是为了凑x - l - 1
cal(a, b);
for(R i = mid + 1; i <= r; i ++) up(f[i], a[i - l - 1]);
cdq(mid + 1, r);
}
int main()
{
freopen("in.in", "r", stdin);
pre();
cdq(0, n - 1);
for(R i = 0; i < n; i ++) printf("%d ", ((f[i] % p) + p) % p);
printf("\n");
fclose(stdin);
return 0;
}
分治FFT的更多相关文章
- BNUOJ 51279[组队活动 Large](cdq分治+FFT)
传送门 大意:ACM校队一共有n名队员,从1到n标号,现在n名队员要组成若干支队伍,每支队伍至多有m名队员,求一共有多少种不同的组队方案.两个组队方案被视为不同的,当且仅当存在至少一名队员在两种方案中 ...
- hdu 5730 Shell Necklace [分治fft | 多项式求逆]
hdu 5730 Shell Necklace 题意:求递推式\(f_n = \sum_{i=1}^n a_i f_{n-i}\),模313 多么优秀的模板题 可以用分治fft,也可以多项式求逆 分治 ...
- BZOJ 4555: [Tjoi2016&Heoi2016]求和 [分治FFT 组合计数 | 多项式求逆]
4555: [Tjoi2016&Heoi2016]求和 题意:求\[ \sum_{i=0}^n \sum_{j=0}^i S(i,j)\cdot 2^j\cdot j! \\ S是第二类斯特林 ...
- 分治FFT的三种含义
分治FFT是几个算法的统称.它们之间并无关联. 分治多项式乘法 问题如求\(\prod_{i=1}^na_ix+b\). 若挨个乘复杂度为\(O(n^2\log n)\),可分治做这件事,复杂度为\( ...
- 【XSY2666】排列问题 DP 容斥原理 分治FFT
题目大意 有\(n\)种颜色的球,第\(i\)种有\(a_i\)个.设\(m=\sum a_i\).你要把这\(m\)个小球排成一排.有\(q\)个询问,每次给你一个\(x\),问你有多少种方案使得相 ...
- 【XSY2887】【GDOI2018】小学生图论题 分治FFT 多项式exp
题目描述 在一个 \(n\) 个点的有向图中,编号从 \(1\) 到 \(n\),任意两个点之间都有且仅有一条有向边.现在已知一些单向的简单路径(路径上任意两点各不相同),例如 \(2\to 4\to ...
- prime distance on a tree(点分治+fft)
最裸的点分治+fft,调了好久,太菜了.... #include<iostream> #include<cstring> #include<cstdio> #inc ...
- 【XSY2744】信仰圣光 分治FFT 多项式exp 容斥原理
题目描述 有一个\(n\)个元素的置换,你要选择\(k\)个元素,问有多少种方案满足:对于每个轮换,你都选择了其中的一个元素. 对\(998244353\)取模. \(k\leq n\leq 1525 ...
- 【BZOJ5119】【CTT2017】生成树计数 DP 分治FFT 斯特林数
CTT=清华集训 题目大意 有\(n\)个点,点权为\(a_i\),你要连接一条边,使该图变成一颗树. 对于一种连边方案\(T\),设第\(i\)个点的度数为\(d_i\),那么这棵树的价值为: \[ ...
- 【XSY2166】Hope 分治 FFT
题目描述 对于一个\(1\)到\(n\)的排列\(a_1,a_2,a_3,\ldots,a_n\),我们定义这个排列的\(P\)值和\(Q\)值: 对于每个\(a_i\),如果存在一个最小的\(j\) ...
随机推荐
- (三)SpringBoot2.0基础篇- 持久层,jdbcTemplate和JpaRespository
一.介绍 SpringBoot框架为使用SQL数据库提供了广泛的支持,从使用JdbcTemplate的直接JDBC访问到完整的“对象关系映射”技术(如Hibernate).Spring-data-jp ...
- pyhon3.0 day01 变量、输入、输出、循环
pyhon3.0 基础01 1 python解释器 Python的解释器很多,但使用最广泛的还是CPython.如果要和Java或.Net平台交互,最好的办法不是用Jython或IronPython, ...
- R小问题
步骤 > library(xlsx) > test<-read.csv("I:/山农大学大数据中心/柱状图/z7.csv") > data1=test[] ...
- Selenium2+python自动化-iframe
前言 本篇详细讲解iframe的相关切换操作. 一.frame和iframe区别 Frame与Iframe两者可以实现的功能基本相同,不过Iframe比Frame具有更多的灵活性. frame是整个页 ...
- selenium+Java,xpath定位方法详解(搬运留存)
用xpath绝对路径比较费事费力,还容易报错,下面几种模糊定位比较灵活好用 driver.findElement(By.xpath("//*[@id='J_login_form']/dl/d ...
- vue2.0做移动端开发用到的相关插件和经验总结1.0
最近在用vue2.0做微信公众号相关的前端开发,经过这次开发实践,现将项目中用到的相关比较实用的插件及遇到的相关问题进行整理,希望和大家共同交流...... cssrem:一个CSS值转REM的VSC ...
- phpldapadmin具体设置
一.需求 1.属性隐藏 只显示用户名,部门(因为是单OU设计为了做区分),登录密码 2.属性顺序显示 部门>用户名>登录密码 3.使用UID可以登陆 用户可以使用账户(自己的名字)登 ...
- LeetCode-124.二叉树中的最大路径和
给定一个非空二叉树,返回其最大路径和. 本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列.该路径至少包含一个节点,且不一定经过根节点. 示例 1: 输入: [1,2,3] 1 / \ 2 ...
- 使用ssh公钥登陆
记录一下使用的具体命令,具体参考: Centos设置禁止密码登录而只使用密钥登录SSH方法 优先参考这个. ssh使用公钥授权不通过的问题解决 Xshell配置ssh免密码登录-密钥公钥(Publi ...
- selenium Object Page 设计模式理解及实现!
Page Object模式是Selenium中的一种测试设计模式,主要是将每一个页面设计为一个Class,其中包含页面中需要测试的元素(按钮,输入框,标题 等),这样在Selenium测试页面中可以通 ...