洛谷 P4721 [模板]分治FFT —— 分治FFT / 多项式求逆
题目:https://www.luogu.org/problemnew/show/P4721
分治做法,考虑左边对右边的贡献即可;
注意最大用到的 a 的项也不过是 a[r-l] ,所以 NTT 可以只做到 2*(r-l),能快一倍。
代码如下:
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- typedef long long ll;
- int const xn=(<<),mod=;
- int n,f[xn],g[xn],a[xn],b[xn],rev[xn];
- int rd()
- {
- int ret=,f=; char ch=getchar();
- while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
- while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
- return f?ret:-ret;
- }
- ll pw(ll a,int b)
- {
- ll ret=;
- for(;b;b>>=,a=(a*a)%mod)if(b&)ret=(ret*a)%mod;
- return ret;
- }
- int upt(int x){while(x>=mod)x-=mod; while(x<)x+=mod; return x;}
- void ntt(int *a,int tp,int lim)
- {
- for(int i=;i<lim;i++)
- if(i<rev[i])swap(a[i],a[rev[i]]);
- for(int mid=;mid<lim;mid<<=)
- {
- int wn=pw(,tp==?(mod-)/(mid<<):(mod-)-(mod-)/(mid<<));
- for(int j=,len=(mid<<);j<lim;j+=len)
- for(int k=,w=;k<mid;k++,w=(ll)w*wn%mod)
- {
- int x=a[j+k],y=(ll)w*a[j+mid+k]%mod;
- a[j+k]=upt(x+y); a[j+mid+k]=upt(x-y);
- }
- }
- if(tp==)return; int inv=pw(lim,mod-);
- for(int i=;i<lim;i++)a[i]=(ll)a[i]*inv%mod;
- }
- void work(int l,int r)
- {
- if(l==r)return;
- int len=r-l+,mid=((l+r)>>);
- work(l,mid); int lim=,L=;
- while(lim<=(r-l))lim<<=,L++;//max:r-l
- for(int i=;i<lim;i++)rev[i]=((rev[i>>]>>)|((i&)<<(L-)));
- for(int i=;i<lim;i++)a[i]=b[i]=;//
- for(int i=l;i<=mid;i++)a[i-l]=f[i];
- for(int i=;i<len;i++)b[i]=g[i];
- ntt(a,,lim); ntt(b,,lim);
- for(int i=;i<lim;i++)a[i]=(ll)a[i]*b[i]%mod;
- ntt(a,-,lim);
- for(int i=mid+;i<=r;i++)f[i]=upt(f[i]+a[i-l]);
- work(mid+,r);
- }
- int main()
- {
- n=rd(); f[]=;
- for(int i=;i<n;i++)g[i]=rd();
- work(,n-);
- for(int i=;i<n;i++)printf("%d ",f[i]); puts("");
- return ;
- }
多项式求逆做法感觉很妙:
设 \( F(x) = \sum f_{i}*x_{i} \),\( G(x) = \sum g_{i}*x_{i} \)
则 \( F(x) * G(x) = \sum x_{i} * \sum\limits_{j=0}^{i} f_{j}*g_{i-j} \)
即 \( F(x) * G(x) = F(x) - f_{0}*x_{0} \)
所以 \( F(x) = (1-G(x))^{-1} \)
多项式求逆即可。
代码如下:
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- typedef long long ll;
- int const xn=(<<),mod=;
- int n,f[xn],g[xn],c[xn],rev[xn];
- int rd()
- {
- int ret=,f=; char ch=getchar();
- while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
- while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
- return f?ret:-ret;
- }
- ll pw(ll a,int b)
- {
- ll ret=;
- for(;b;b>>=,a=(a*a)%mod)if(b&)ret=(ret*a)%mod;
- return ret;
- }
- int upt(int x){while(x>=mod)x-=mod; while(x<)x+=mod; return x;}
- void ntt(int *a,int tp,int lim)
- {
- for(int i=;i<lim;i++)
- if(i<rev[i])swap(a[i],a[rev[i]]);
- for(int mid=;mid<lim;mid<<=)
- {
- int p=mod-,len=(mid<<),wn=pw(,tp==?p/len:p-p/len);
- for(int j=;j<lim;j+=len)
- for(int k=,w=;k<mid;k++,w=(ll)w*wn%mod)
- {
- int x=a[j+k],y=(ll)w*a[j+mid+k]%mod;
- a[j+k]=upt(x+y); a[j+mid+k]=upt(x-y);
- }
- }
- if(tp==)return; int inv=pw(lim,mod-);
- for(int i=;i<lim;i++)a[i]=(ll)a[i]*inv%mod;
- }
- void inv(int *a,int *b,int n)
- {
- if(n==){b[]=pw(a[],mod-); return;}
- inv(a,b,(n+)>>);
- int lim=,l=;
- while(lim<n+n)lim<<=,l++;
- for(int i=;i<lim;i++)rev[i]=((rev[i>>]>>)|((i&)<<(l-)));
- for(int i=;i<n;i++)c[i]=a[i];
- for(int i=n;i<lim;i++)c[i]=;
- ntt(c,,lim); ntt(b,,lim);
- for(int i=;i<lim;i++)b[i]=((ll)-(ll)c[i]*b[i])%mod*b[i]%mod;
- ntt(b,-,lim);
- for(int i=n;i<lim;i++)b[i]=;
- }
- int main()
- {
- n=rd(); f[]=; g[]=;
- for(int i=;i<n;i++)g[i]=-rd();
- inv(g,f,n);
- for(int i=;i<n;i++)printf("%d ",f[i]); puts("");
- return ;
- }
洛谷 P4721 [模板]分治FFT —— 分治FFT / 多项式求逆的更多相关文章
- 洛谷P3711 仓鼠的数学题(伯努利数+多项式求逆)
题面 传送门 题解 如果您不知道伯努利数是什么可以去看看这篇文章 首先我们把自然数幂和化成伯努利数的形式 \[\sum_{i=1}^{n-1}i^k={1\over k+1}\sum_{i=0}^k{ ...
- 洛谷P4721 【模板】分治 FFT(生成函数+多项式求逆)
传送门 我是用多项式求逆做的因为分治FFT看不懂…… upd:分治FFT的看这里 话说这个万恶的生成函数到底是什么东西…… 我们令$F(x)=\sum_{i=0}^\infty f_ix^i,G(x) ...
- 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是第二类斯特林 ...
- NOIP 2013 洛谷P1966 火柴排队 (树状数组求逆序对)
对于a[],b[]两个数组,我们应选取其中一个为基准,再运用树状数组求逆序对的方法就行了. 大佬博客:https://www.cnblogs.com/luckyblock/p/11482130.htm ...
- 多项式求逆元详解+模板 【洛谷P4238】多项式求逆
概述 多项式求逆元是一个非常重要的知识点,许多多项式操作都需要用到该算法,包括多项式取模,除法,开跟,求ln,求exp,快速幂.用快速傅里叶变换和倍增法可以在$O(n log n)$的时间复杂度下求出 ...
- 洛谷 P4721 【模板】分治 FFT 解题报告
P4721 [模板]分治 FFT 题目背景 也可用多项式求逆解决. 题目描述 给定长度为 \(n−1\) 的数组 \(g[1],g[2],\dots,g[n-1]\),求 \(f[0],f[1],\d ...
- 洛谷P4721 【模板】分治 FFT(分治FFT)
传送门 多项式求逆的解法看这里 我们考虑用分治 假设现在已经求出了$[l,mid]$的答案,要计算他们对$[mid+1,r]$的答案的影响 那么对右边部分的点$f_x$的影响就是$f_x+=\sum_ ...
- 洛谷.4721.[模板]分治FFT(NTT)
题目链接 换一下形式:\[f_i=\sum_{j=0}^{i-1}f_jg_{i-j}\] 然后就是分治FFT模板了\[f_{i,i\in[mid+1,r]}=\sum_{j=l}^{mid}f_jg ...
- [洛谷P3806] [模板] 点分治1
洛谷 P3806 传送门 这个点分治都不用减掉子树里的了,直接搞就行了. 注意第63行 if(qu[k]>=buf[j]) 不能不写,也不能写成>. 因为这个WA了半天...... 如果m ...
随机推荐
- 【Selenium + Python】路径报错之OSError: [Errno 22] Invalid argument: './t/report/2018-03-23_11:03:12_report.html'
现象: 此问题真的是太痛苦了,查了好多资料是说路径的问题,结果还是报错,后来一点点的排查才发现原来是!!!!!! 废话不多说上原来代码: if __name__ == '__main__': star ...
- OpenCV 入门示例之五:一个复杂点的变换
前言 前文介绍了一个简单的变换.需要注意的是,很多时候,输出和输入图像的格式是不同的( 大小,深度,通道 ).在本文将展示的程序中,对图像进行了缩放( 使用cvPyrDown 函数 ),这种情况下需要 ...
- 目标检测之hog(梯度方向直方图)---hog简介0
梯度直方图特征(HOG) 是一种对图像局部重叠区域的密集型描述符, 它通过计算局部区域的梯度方向直方图来构成特征.Hog特征结合SVM分类器已经被广泛应用于图像识别中,尤其在行人检测中获得了极大的成功 ...
- js jquery 插件
$(function(){ (function($, document, undefiend){ $.fn.pagination = function(options){ var $this = $( ...
- Jmeter文章索引贴
一.基础部分: 使用Jmeter进行http接口测试 Jmeter之Http Cookie Manager Jmeter之HTTP Request Defaults Jmeter之逻辑控制器(Logi ...
- 【BZOJ1604】[Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 Treap+并查集
[BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 Description 了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000) ...
- EasyPlayerPro windows播放器在播放RTMP视频显示重复异常问题解决
问题来源 2017.12.18 今日有杭州某教育领域客户反馈EasyPlayerPro在播放一个rtmp源时,画面显示异常的问题.截图如下: 问题复现 一番思考, 将显示格式改为D3D显示, 正常, ...
- 流畅python学习笔记第十八章:使用asyncio包处理并发(一)
首先是线程与协程的对比.在文中作者通过一个实例分别采用线程实现和asynchio包实现来比较两者的差别.在多线程的样例中,会用到join的方法,下面来介绍下join方法的使用. 知识点一:当一个进程启 ...
- 爬虫-Selenium -抱错ElementNotVisibleException: Message: element not visible
1.当使用Selenium IDE 完成了脚本的录制和回放通过后,想要将脚本转换为其他语言如java.Python等,首次使用时打开Options->Format发现没有可以转换的语言,如下: ...
- 用JavaScript判断一个对象是否数组?
Q:如何判断一个对象是否为数组? A1:判断对象的constructor是否指向Array, 接着判断对应的特殊属性,如length,splice之类.这个很容易冒充. A2:使用instanceof ...