题目:https://www.luogu.org/problemnew/show/P4245

用三模数NTT做,需要注意时间和细节;

注意各种地方要取模!传入 upt() 里面的数一定要不超过2倍 mod!

乘法会爆 long long 时用快速乘!

两次合并的模数,第一次是 (ll) p1*p2,第二次直接对题目的模数取模即可!

注意局部开 (ll)!

合并时用到的逆元每次都一样,所以要先处理好而不是现场快速幂算!!

然而为什么时间还是 Narh 的两倍!

一晚上的心血...

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const xn=(<<);
int n,m,lim,rev[xn],a[][xn],b[][xn],p[]={,,,};
ll mod;
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 upt(ll x,int md){while(x>=md)x-=md; while(x<)x+=md; return x;}
ll mul(ll a,ll b,int md)
{
ll ret=; a=a%md; b=b%md;
if(a<)a+=md; if(b<)b+=md;//
for(;b;b>>=1ll,a=(a+a)%md)if(b&)ret=(ret+a)%md;
return ret;
}
ll pw(ll a,int b,int md)
{
ll ret=; a=a%md;
for(;b;b>>=,a=mul(a,a,md))if(b&)ret=mul(ret,a,md);//mul!!
return ret;
}
void ntt(int *a,int tp,int md)
{
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(,(md-)/(mid<<),md);
if(tp==-)wn=pw(wn,md-,md);
for(int j=,len=(mid<<);j<lim;j+=len)
{
int w=;
for(int k=;k<mid;k++,w=(ll)w*wn%md)
{
int x=a[j+k],y=(ll)w*a[j+mid+k]%md;
a[j+k]=upt(x+y,md); a[j+mid+k]=upt(x-y,md);
}
}
}
if(tp==)return; int inv=pw(lim,md-,md);
for(int i=;i<lim;i++)a[i]=(ll)a[i]*inv%md;
}
ll uni(ll r1,ll r2,ll m1,int m2,int tp,int inv)
{
ll k=mul(r2-r1,inv,m2);
if(!tp)return (r1+k*m1)%(m1*m2);
return upt((r1+mul(k,m1,mod))%mod,mod);//%mod!!
}
int main()
{
n=rd(); m=rd(); mod=rd();
for(int i=;i<=n;i++)a[][i]=a[][i]=a[][i]=rd();
for(int i=;i<=m;i++)b[][i]=b[][i]=b[][i]=rd();
lim=; int l=;
while(lim<=n+m+)lim<<=,l++;//+2!
for(int i=;i<lim;i++)
rev[i]=((rev[i>>]>>)|((i&)<<(l-)));
for(int i=;i<=;i++)
{
ntt(a[i],,p[i]); ntt(b[i],,p[i]);
for(int j=;j<lim;j++)a[i][j]=(ll)a[i][j]*b[i][j]%p[i];
ntt(a[i],-,p[i]);
}
int inv1=pw(p[],p[]-,p[]);
int inv2=pw((ll)p[]*p[],p[]-,p[]);//inv!!
for(int i=;i<=n+m;i++)
{
ll ans=uni(a[][i],a[][i],p[],p[],,inv1);
ans=uni(ans,a[][i],(ll)p[]*p[],p[],,inv2);//(ll)!!!
printf("%lld ",ans);
}
puts("");
return ;
}

关于拆系数FFT,这篇博客说得十分清晰:https://blog.csdn.net/lvzelong2014/article/details/80156989

而且代码也十分简洁优美,所以就模仿着写了;

注意:

1. 读入的初始数组要先取模;

2. 对 (x<<30) 开 (ll) 要写在括号里面而非外面;

3. IDFT中最后要 /lim,平常都之写 a[i].x/lim,但这里因为用到了 y,所以必须加上 a[i].y/lim!!

4. 卡精度,要开 long double

(注意数组范围,如果要用到 a[lim] 的话,再稍微把数组开大一点)

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
typedef long double db;//
int const xn=(<<)+;//a[lim]
db const Pi=acos(-1.0);
int n,m,lim,rev[xn],P,f[xn],g[xn],ans[xn];
struct com{db x,y;}a[xn],b[xn],Da[xn],Db[xn],Dc[xn],Dd[xn];
com operator + (com a,com b){return (com){a.x+b.x,a.y+b.y};}
com operator - (com a,com b){return (com){a.x-b.x,a.y-b.y};}
com operator * (com a,com b){return (com){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};}
com conj(com a){return (com){a.x,-a.y};}
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;
}
void init()
{
lim=; int l=;
while(lim<=n+m)lim<<=,l++;
for(int i=;i<lim;i++)rev[i]=((rev[i>>]>>)|((i&)<<(l-)));
}
int upt(int x){while(x>=P)x-=P; while(x<)x+=P; return x;}
void fft(com *a,int tp)
{
for(int i=;i<lim;i++)
if(i<rev[i])swap(a[i],a[rev[i]]);
for(int mid=;mid<lim;mid<<=)
{
com wn=(com){cos(Pi/mid),tp*sin(Pi/mid)};
for(int j=,len=(mid<<);j<lim;j+=len)
{
com w=(com){,};
for(int k=;k<mid;k++,w=w*wn)
{
com x=a[j+k],y=w*a[j+mid+k];
a[j+k]=x+y; a[j+mid+k]=x-y;
}
}
}
if(tp==)return;
for(int i=;i<lim;i++)a[i].x/=lim,a[i].y/=lim;//y!! for use y
}
void mul(int *A,int *B,int *C)
{
for(int i=;i<lim;i++)A[i]=upt(A[i]%P),B[i]=upt(B[i]%P);//
int M=(<<)-;
for(int i=;i<lim;i++)a[i]=(com){A[i]&M,A[i]>>};
for(int i=;i<lim;i++)b[i]=(com){B[i]&M,B[i]>>};
fft(a,); fft(b,);
a[lim]=a[]; b[lim]=b[];//
for(int i=,j=lim;i<lim;i++,j--)
{
com da,db,dc,dd;
da=(a[i]+conj(a[j]))*(com){0.5,};
db=(a[i]-conj(a[j]))*(com){,-0.5};
dc=(b[i]+conj(b[j]))*(com){0.5,};
dd=(b[i]-conj(b[j]))*(com){,-0.5};
Da[i]=da*dc; Db[i]=da*dd; Dc[i]=db*dc; Dd[i]=db*dd;
}
a[lim]=b[lim]=(com){,};
for(int i=;i<lim;i++)a[i]=Da[i]+Db[i]*(com){,};
for(int i=;i<lim;i++)b[i]=Dc[i]+Dd[i]*(com){,};
fft(a,-); fft(b,-);
for(int i=;i<=n+m;i++)
{
int da=(ll)(a[i].x+0.5)%P;
int db=(ll)(a[i].y+0.5)%P;
int dc=(ll)(b[i].x+0.5)%P;
int dd=(ll)(b[i].y+0.5)%P;
C[i]=(da+((ll)(db+dc)<<)+((ll)dd<<))%P;//(ll)
}
}
int main()
{
n=rd(); m=rd(); P=rd(); init();
for(int i=;i<=n;i++)f[i]=rd();
for(int i=;i<=m;i++)g[i]=rd();
mul(f,g,ans);
for(int i=;i<=n+m;i++)printf("%d ",upt(ans[i])); puts("");
return ;
}

洛谷 P4245 [模板]任意模数NTT —— 三模数NTT / 拆系数FFT(MTT)的更多相关文章

  1. 洛谷.4245.[模板]任意模数NTT(MTT/三模数NTT)

    题目链接 三模数\(NTT\): 就是多模数\(NTT\)最后\(CRT\)一下...下面两篇讲的都挺明白的. https://blog.csdn.net/kscla/article/details/ ...

  2. 洛谷 4245 【模板】任意模数NTT——三模数NTT / 拆系数FFT

    题目:https://www.luogu.org/problemnew/show/P4245 三模数NTT: 大概是用3个模数分别做一遍,用中国剩余定理合并. 前两个合并起来变成一个 long lon ...

  3. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  4. 【洛谷5月月赛】玩游戏(NTT,生成函数)

    [洛谷5月月赛]玩游戏(NTT,生成函数) 题面 Luogu 题解 看一下要求的是什么东西 \((a_x+b_y)^i\)的期望.期望显然是所有答案和的平均数. 所以求出所有的答案就在乘一个逆元就好了 ...

  5. 拆系数FFT(任意模数FFT)

    拆系数FFT 对于任意模数 \(mod\) 设\(m=\sqrt {mod}\) 把多项式\(A(x)\)和\(B(x)\)的系数都拆成\(a\times m+b\)的形式,时\(a, b\)都小于\ ...

  6. [洛谷P4245]【模板】任意模数NTT

    题目大意:给你两个多项式$f(x)$和$g(x)$以及一个模数$p(p\leqslant10^9)$,求$f*g\pmod p$ 题解:任意模数$NTT$,最大的数为$p^2\times\max\{n ...

  7. 洛谷P4245 【模板】MTT(任意模数NTT)

    题目背景 模板题,无背景 题目描述 给定 22 个多项式 F(x), G(x)F(x),G(x) ,请求出 F(x) * G(x)F(x)∗G(x) . 系数对 pp 取模,且不保证 pp 可以分解成 ...

  8. 【洛谷P4245】 【模板】任意模数NTT

    三模数 NTT,感觉不是很难写 $?$ 代码借鉴的 https://www.cnblogs.com/Mychael/p/9297652.html code: #include <bits/std ...

  9. [题解] Luogu P4245 [模板]任意模数NTT

    三模NTT 不会... 都0202年了,还有人写三模NTT啊... 讲一个好写点的做法吧: 首先取一个阀值\(w\),然后把多项式的每个系数写成\(aw + c(c < w)\)的形式,换句话说 ...

随机推荐

  1. 【Scala类型系统】自身类型(self type)引用

    定义 特质能够要求混入它的类扩展自还有一个类型,可是当使用自身类型(self type)的声明来定义特质时(this: ClassName =>).这种特质仅仅能被混入给定类型的子类其中. 如果 ...

  2. Allegro16.6和17.0和17.2中将板框导出DXF文件

    Allegro16.6和17.0和17.2中将板框导出DXF文件 转载 https://blog.csdn.net/pieces_thinking/article/details/69817600 标 ...

  3. Tomcat服务器改主页 & jeesite框架改首页

    Tomcat服务器改主页: 方法一: 把原来的 ROOT 目录清空: 发布你自己的项目到 ROOT 目录下: 发布程序 /webapps/ROOT/WEB-INF/web.xml 中需要有默认首页定义 ...

  4. MySQL windows集群(转)

    http://blog.csdn.net/zhangking/article/details/5670070    MySQL 群集是 MySQL 适合于分布式计算环境的高可用.高冗余版本.它采用了 ...

  5. ubuntu 14.04 下利用apt-get方式安装opencv

    转载,请注明出处:http://blog.csdn.net/tina_ttl 目录(?)[+] 标签(空格分隔): Linux学习 OpenCV ubuntu 1404 下利用apt-get方式安装O ...

  6. mysql导入数据库_仅仅用frm向mysql导入表结构

    网上一个连接mysql的jsp代码段,给了数据库的备份文件.可是仅仅有frm, mysql的每张表有三个文件.各自是,*.frm是描写叙述了表的结构.*.MYD保存了表的数据记录.*.MYI则是表的索 ...

  7. html抽取文本信息-java版(适合lucene建立索引)

    import org.htmlparser.NodeFilter; import org.htmlparser.Parser; import org.htmlparser.beans.StringBe ...

  8. 安卓版本6.0打开uiautomator报错

    可能是appium打开了,被占用:或者是找不到手机

  9. 【BZOJ3218】a + b Problem 可持久化线段树优化建图

    [BZOJ3218]a + b Problem 题解:思路很简单,直接最小割.S->i,容量为Bi:i->T,容量为Wi:所有符合条件的j->new,容量inf:new->i, ...

  10. 九度OJ 1132:与7无关的数 (数字特性)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:1619 解决:1037 题目描述: 一个正整数,如果它能被7整除,或者它的十进制表示法中某个位数上的数字为7, 则称其为与7相关的数.现求所 ...