分治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\) ...
随机推荐
- bzoj1854 [Scoi2010]游戏 ([SCOI2010]连续攻击游戏)
bzoj1854 [Scoi2010]游戏 ([SCOI2010]连续攻击游戏) 据说正解是并查集???我不会 这不是一道匈♂牙利好题吗??? 一个装备的两个属性都向它连边,然后跑一遍匈♂牙利 注意: ...
- win2012r2 关闭中英文悬浮小方框显示
因为那是微软输入法自带的 2012下关不掉 所以切换成美式键盘就没有了
- Python接口测试实战1(下)- 接口测试工具的使用
如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...
- 生成dataset的几种方式
1.常用的方式通过sparksession读取外部文件或者数据生成dataset(这里就不讲了) 注: 生成Row对象的方法提一下:RowFactory.create(x,y,z),取Row中的数据 ...
- nginx main函数
源代码: int ngx_cdecl main(int argc, char *const *argv) { ngx_int_t i; ngx_log_t *log; ngx_cycle_t *cyc ...
- SVN部署与简单使用
原文发表于cu:2016-05-24 参考文档: http://www.tuicool.com/articles/Yv2iyu7 http://www.centoscn.com/CentosServe ...
- 完美的【去重留一】SQL
DELETE consum_record FROM consum_record, ( SELECT min(id) id, user_id, monetary, consume_time FROM c ...
- 【视频编解码·学习笔记】4. H.264的码流封装格式 & 提取NAL有效数据
一.码流封装格式简单介绍: H.264的语法元素进行编码后,生成的输出数据都封装为NAL Unit进行传递,多个NAL Unit的数据组合在一起形成总的输出码流.对于不同的应用场景,NAL规定了一种通 ...
- 寒假MOOC学习计划
我选择的是西北工业大学的课程,理由如下: 首先,选择这门课的网友还蛮多的,特意看了一下评价,也不错: 其次,这个课程的排版与我从图书馆借来的一本书内容排版比较符合,可以结合起来一起看,说不定会有更多收 ...
- mysql hql异常
org.springframework.dao.InvalidDataAccessResourceUsageException: could not execute query; nested ex ...