洛谷 4721 【模板】分治 FFT——分治FFT / 多项式求逆
题目:https://www.luogu.org/problemnew/show/P4721
分治FFT:https://www.cnblogs.com/bztMinamoto/p/9749557.html
https://blog.csdn.net/VictoryCzt/article/details/82939586
不知为何自己的总是很慢。
觉得是 n 和 m 表示次数的话,len<=n+m;n 和 m 表示项数的话,len<n+m;应该是这样?
这里是 mid-L+1 项和 R-L+1 项的两个多项式相乘,所以 len < (mid-L+1)+(R-L+1);
但这样很慢;发现那个 g[0] = 0 每次浪费了一个位置;所以把 g 的标号都减小1,位置 i 对应的位置标号自然也减小了1;微妙地快了一点。
发现用到的最高次项也只是 R-L-1 次;所以 len<= R-L-1 即可!快了一倍。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1e5+,M=N<<,mod=;
int len,r[M],f[M],g[M],a[M],b[M];
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='') ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
void upd(int &x){x>=mod?x-=mod:;}
int pw(int x,int k)
{int ret=;while(k){if(k&)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=;}return ret;}
void ntt(int *a,bool fx)
{
for(int i=;i<len;i++)
if(i<r[i])swap(a[i],a[r[i]]);
for(int R=;R<=len;R<<=)
{
int Wn=pw( ,(mod-)/R );
if(fx)Wn=pw( Wn,mod- );
for(int i=,m=R>>;i<len;i+=R)
for(int j=,w=;j<m;j++,w=(ll)w*Wn%mod)
{
int x=a[i+j], y=(ll)w*a[i+m+j]%mod;
a[i+j]=x+y; upd(a[i+j]);
a[i+m+j]=x+mod-y; upd(a[i+m+j]);
}
}
if(!fx)return; int inv=pw( len,mod- );
for(int i=;i<len;i++)a[i]=(ll)a[i]*inv%mod;
}
void solve(int L,int R)
{
if(L==R)return;
int mid=L+R>>;
solve(L,mid);
int d=R-L-,i,j;
for(i=,j=L;j<=mid;i++,j++)a[i]=f[j];// d+=i-1;
for(i=,j=R-L;i<j;i++)b[i]=g[i+];// d+=i-1;//+1
for(len=;len<=d;len<<=);
for(i=;i<len;i++)r[i]=(r[i>>]>>)+((i&)?len>>:);
for(i=mid-L+;i<len;i++)a[i]=; for(i=R-L+;i<len;i++)b[i]=;
ntt(a,); ntt(b,);
for(i=;i<len;i++)a[i]=(ll)a[i]*b[i]%mod;
ntt(a,);
for(i=mid+,j=i-L-;i<=R;i++,j++)f[i]+=a[j],upd(f[i]);////j=i-L -1
solve(mid+,R);
}
int main()
{
int n;n=rdn();for(int i=;i<n;i++)g[i]=rdn();
f[]=;
solve(,n-);
for(int i=;i<n;i++)printf("%d ",f[i]);puts("");
return ;
}
多项式做法可参见洛谷自带的题解。
F(x) - f[0] = F(x)*G(x)
F(x) = 1/ ( f[0]-G(x) )
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1e5+,M=N<<,mod=;
int a[M],b[M],A[M],len,r[M];
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='') ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
void upd(int &x){x>=mod?x-=mod:;}
int pw(int x,int k)
{int ret=;while(k){if(k&)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=;}return ret;}
void ntt(int *a,bool fx)
{
for(int i=;i<len;i++)
if(i<r[i])swap(a[i],a[r[i]]);
for(int R=;R<=len;R<<=)
{
int Wn=pw( ,fx?(mod-)-(mod-)/R:(mod-)/R );
for(int i=,m=R>>;i<len;i+=R)
for(int j=,w=;j<m;j++,w=(ll)w*Wn%mod)
{
int x=a[i+j], y=(ll)w*a[i+m+j]%mod;
a[i+j]=x+y; upd(a[i+j]);
a[i+m+j]=x+mod-y; upd(a[i+m+j]);
}
}
if(!fx)return; int inv=pw(len,mod-);
for(int i=;i<len;i++)a[i]=(ll)a[i]*inv%mod;
}
void inv(int n)
{
if(n==){b[]=pw(a[],mod-);return;}
inv(n+>>);
for(len=;len<n<<;len<<=);
for(int i=;i<len;i++)r[i]=(r[i>>]>>)+((i&)?len>>:);
for(int i=;i<n;i++)A[i]=a[i]; for(int i=n;i<len;i++)A[i]=;
ntt(A,); ntt(b,);
for(int i=;i<len;i++)b[i]=((b[i]<<)-(ll)A[i]*b[i]%mod*b[i])%mod+mod,upd(b[i]);
ntt(b,);
for(int i=n;i<len;i++)b[i]=;
}
int main()
{
int n; n=rdn(); for(int i=;i<n;i++)a[i]=mod-rdn(); a[]=;
inv(n);
for(int i=;i<n;i++)printf("%d ",b[i]);puts("");
return ;
}
洛谷 4721 【模板】分治 FFT——分治FFT / 多项式求逆的更多相关文章
- 洛谷P3711 仓鼠的数学题(伯努利数+多项式求逆)
题面 传送门 题解 如果您不知道伯努利数是什么可以去看看这篇文章 首先我们把自然数幂和化成伯努利数的形式 \[\sum_{i=1}^{n-1}i^k={1\over k+1}\sum_{i=0}^k{ ...
- 洛谷.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 ...
- 洛谷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是第二类斯特林 ...
- 解题:洛谷4721 [模板]分治FFT
题面 这是CDQ入门题,不要被题目名骗了,这核心根本不在不在FFT上啊=.= 因为后面的项的计算依赖于前面的项,不能直接FFT.所以用CDQ的思想,算出前面然后考虑给后面的贡献 #include< ...
- NOIP 2013 洛谷P1966 火柴排队 (树状数组求逆序对)
对于a[],b[]两个数组,我们应选取其中一个为基准,再运用树状数组求逆序对的方法就行了. 大佬博客:https://www.cnblogs.com/luckyblock/p/11482130.htm ...
- 多项式求逆元详解+模板 【洛谷P4238】多项式求逆
概述 多项式求逆元是一个非常重要的知识点,许多多项式操作都需要用到该算法,包括多项式取模,除法,开跟,求ln,求exp,快速幂.用快速傅里叶变换和倍增法可以在$O(n log n)$的时间复杂度下求出 ...
- 【洛谷4721】【模板】分治FFT(CDQ分治_NTT)
题目: 洛谷 4721 分析: 我觉得这个 "分治 FFT " 不能算一种特殊的 FFT ,只是 CDQ 分治里套了个用 FFT (或 NTT)计算的过程,二者是并列关系而不是偏正 ...
- 洛谷 P4721 [模板]分治FFT —— 分治FFT / 多项式求逆
题目:https://www.luogu.org/problemnew/show/P4721 分治做法,考虑左边对右边的贡献即可: 注意最大用到的 a 的项也不过是 a[r-l] ,所以 NTT 可以 ...
- [洛谷P3806] [模板] 点分治1
洛谷 P3806 传送门 这个点分治都不用减掉子树里的了,直接搞就行了. 注意第63行 if(qu[k]>=buf[j]) 不能不写,也不能写成>. 因为这个WA了半天...... 如果m ...
随机推荐
- What's the difference between UTF-8 and UTF-8 without BOM?
https://stackoverflow.com/questions/2223882/whats-the-difference-between-utf-8-and-utf-8-without-bom ...
- EF Code-First 学习之旅 EntityTypeConfiguration<TEntity>
之前我们配置的实体都都在OnModelCreating方法中,如果有很多实体的话,OnModelCreating方法管理很麻烦 我们可以用单独的类来管理配置,继承EntityTypeConfigura ...
- 5分钟理解Centos7防火墙firewalld
版权声明:本内容为原创内容,转载请声明出处. 原文地址:http://www.excelib.com/article/287/show firewalld简介 Centos7中默认将原来的防火墙ipt ...
- HUE中Oozie执行Sqoop
Oozie执行Sqoop,传入参数(注意,在使用--query时,参数中一定不要带有空格,否则出错)1. 新建一个workflow 2. 拖入一个sqoop 3. sqoop抽取命令如下(建议先在命令 ...
- Java集合Collection&Map
Map<K,V>是键值对,K - 此映射所维护的键的类型,V - 映射值的类型.键值是一一对应的关系: Collection是只有键,底层也是由键值对,但是值的类型被隐藏起来. Colle ...
- Android DDMS ADB启动失败错误解决!
ADB server didn't ACK && make sure the plugin is properly configured! adb启动失败一般是端口被占用! 解决方法和 ...
- BCCoventUtils全角与半角互相转换
public class BCConvert { /** * ASCII表中可见字符从!开始,偏移位值为33(Decimal) */ static final char DBC_CHAR_START ...
- MailUtils 测试邮件是否发送
import java.util.Properties; import javax.mail.Message; import javax.mail.Session; import javax.mail ...
- linux的find命令详解
find命令是用来在给定的目录下查找符合给定条件的文件 find [OPTIONS] [查找起始路径] [查找条件] [处理动作] 一.OPTIONS参数 -P.-L.-H:控制软连接的对待方式, ...
- 前端之CSS续集
CSS:语法形式上由选择器+以及一条或多条声明组成:选择器查找到指定的html标签后,使用css属性设置html标签的样式: 一.css 语法形式: 二.使用步骤 1.引入css规则 2.使用cs ...