分治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\) ...
随机推荐
- Nginx入门篇(四)之常用配置解析
1.Nginx状态信息功能 Nginx的模块当中有一个ngx_http_stub_status_module模块,这个模块主要记录Nginx的基本访问信息,要使用该模块,需要在编译的时候增加http_ ...
- 使用github高级搜索
想瞅瞅github上面有哪些中国开发者最活跃,followers最多.可以按照下面的步骤: 打开github的搜索页面 输入 location:china .点search 然后选择不同的排序方式. ...
- 搞懂.NET Framework 历史版本(2017年)
最近被.NET平台各种名词.以及各种版本弄得有些疑惑,开发和部署,对于开发平台版本选择是个基本问题,因此,花了些时间,学习汇总了有关.NET版本演进的历史. .NET简介 这个平台相信我们都知道,不过 ...
- XAF-物料管理信息工作日志
前段时间已经开始了第一阶段验收了,客户方并未把重点放在业务流程上面,一直在调整一些界面问题.有点小纠结. 今天要调一下菜单位置. 没修改时,是这样的: 到了列表界面,会多一个全文检索出来. 后来,客户 ...
- python3 - 元组、集合
元组(tuple) 有序集合,不可变 a(1,2,3) a[0]获取第一个值 集合(set)增删改 >>> b = set('abc') >>> bset(['a' ...
- PHP:Iterator(迭代器)接口和生成器
迭代器 可在内部迭代自己的外部迭代器或类的接口.详情:http://php.net/manual/zh/class.iterator.php 接口摘要 Iterator extends Travers ...
- Shiro 修改权限,刷新权限
shiro 访问鉴权:Realm AuthorizingRealm->doGetAuthorizationInfo doGetAuthorizationInfo protected abstra ...
- RabbitMQ各协议异同详解
一.官网介绍 Which protocols does RabbitMQ support? RabbitMQ supports several messaging protocols, directl ...
- SQL语句--连接查询
一.连接查询有以下几种 1.内连接查询 select * from t1 inner join t2 on t1.x = t2.x; 返回有关联的行 2.外链接查询 以下写法都省略了 中间的 out ...
- 算法笔记(c++)--01背包问题
算法笔记(c++)--经典01背包问题 算法解释起来太抽象了.也不是很好理解,最好的办法就是一步步写出来. 背包问题的核心在于m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+ ...