题目: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. 赵雅智_android_frame动画

    在開始实例解说之前,先引用官方文档中的一段话: Frame动画是一系列图片依照一定的顺序展示的过程,和放电影的机制非常相似.我们称为逐帧动画.Frame动画能够被定义在XML文件里,也能够全然编码实现 ...

  2. AngularJS的控制器示例

    代码下载:https://files.cnblogs.com/files/xiandedanteng/angularjsCtrl.rar 代码: <!DOCTYPE HTML PUBLIC &q ...

  3. andrid对不能导入的类,知道类路径怎样使用该类

    andrid对不能导入的类,知道类路径怎样使用该类?使用java的反射机制. 下边是一个样例. MTK平台对Android源生的Telephone接口进行了扩展,加入了一个TelephonyManag ...

  4. Codeforces Beta Round #1 A. Theatre Square

    从今天開始.就要在Codeforces里有一个新的開始了,貌似任务非常重的说~~ Codeforces专题我将会记录全部通过的题目,事实上仅仅要通过的题目都是水题啊!. 题目大意: 依照要求计算须要多 ...

  5. h5调用手机照相机

    camera.html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> & ...

  6. SwitchyOmega 代理设置

    1.SwitchyOmega官网 https://www.switchyomega.com/ 2.下载插件 https://www.switchyomega.com/download.html 3.配 ...

  7. 华为P7电信4G版刷机包 EMUI2.3 官方B125 第3版 精简 ROOT

    ROM介绍 基于底包至 B125 SP03解包制作 增加自己订制的超美丽EMUI 2.3专用的全局主题 自调刷机脚本,全部权限完美百分百与官方原版相贴合. 加入Root权限并使用SuperSU 2.0 ...

  8. IDEA 适用技巧

    快速打印 sout - System.out.println(); serr - System.err.println(); //在控制台中是红色的 输入sout,按下enter键,生成System. ...

  9. 利用CH341A编程器刷新BIOS,恢复BIOS,妈妈再也不用担心BIOS刷坏了

    前几天,修电脑主析就捣鼓刷BIOS,结果刷完黑屏开不了机,立刻意识到完了,BIOS刷错了.就从网上查资料,各种方法试了个遍,什么用处都没有.终于功夫不负有心人,找到了编码器,知道了怎么用.下面看看具体 ...

  10. C# Winform 中webBrowser显示html内容时禁止错误提示的方法

    在winform中有一个控件可以显示html的内容,该控件就是webbrowser,设置它的DocumenText属性为HTML的内容即可. 在使用WebBrowser做UI的时候,我们有时不希望里面 ...