题目链接


三模数\(NTT\):

就是多模数\(NTT\)最后\(CRT\)一下...下面两篇讲的都挺明白的。
https://blog.csdn.net/kscla/article/details/79547242
https://blog.csdn.net/zhouyuheng2003/article/details/85561887

模数不是\(NTT\)模数,考虑用多个\(NTT\)模数分别卷积,最后\(CRT\)合并(由中国剩余定理,同余方程组在模\(M=\prod m_i\)的情况下解是唯一的)。
卷积后\(a_i\)的最大值是\((10^9)^2\times10^5=10^{23}\),所以需要选几个乘积\(>10^{23}\)的质数,比如\(m_1=998244353=2^{23}*119+1,\quad m_2=1004535809=2^{21}*479+1,\quad m_3=469762049=2^{26}*7+1\)。它们的原根都是\(3\)。
最后我们能求出三个同余方程:\[x\equiv c_1\ (\mathbb{mod}\ m_1)\\x\equiv c_2\ (\mathbb{mod}\ m_2)\\x\equiv c_3\ (\mathbb{mod}\ m_3)\]

我们可以用\(CRT\)合并两个,就有\(x\equiv c_4\ (\mathbb{mod}\ m_1m_2)\)。
设\(x=am_1m_2+c_4\equiv c_3\ (\mathbb{mod}\ m_3)\),就可以算出\(a\equiv\frac{c_3-c_4}{m_1m_2}\ (\mathbb{mod}\ m_3)\),有了\(a\)代回去就算出\(x\)啦(虽然是模\(m_3\)意义下求的\(a\),但是设\(a=km_3+b\),代回到\(x\)里模\(m_1m_2m_3\)就把\(km_3\)那项消掉啦,只剩下\(b\))(当然前两个式子也可以这么合并)。
这样一共需要\(9\)次\(DFT\),常数巨大。


拆系数\(FFT\)(\(MTT\))

\(FFT\)的问题在于精度,我们可以压缩值域。
令\(m=\lceil\sqrt p\rceil,\ A_i=a\times m+b,\ B_i=c\times m+d\),那么\(h_{i+j}=\sum(a_im+b_i)(c_jm+d_j)=\sum a_ic_jm^2+(a_id_j+b_ic_j)m+b_id_j\),分别求出四项(中间两项放一块算),就只需要\(7\)次\(DFT\)。
为了方便可以令\(m=2^{15}=32768\)。
这样\(FFT\)后的最大结果是\(10^5\times2^{30}=10^{14}\),注意取模。

注意std::sin的精度比sin高!因为值域依旧很大所以必须要注意这个,还要开long double
还有个挺重要的优化是预处理单位根,预处理\(lim\)次单位根的\(0\sim lim-1\)次方,用\(\omega_i^k\)时就是\(\omega_{lim}^{k\times\frac{lim}{i}}\)(怎么都预处理的\(2lim\)次单位根啊...)。
注意预处理的时候不要像\(FFT\)里那样每次w=w*Wn,而是对每个单位根直接用欧拉公式算,这样精度误差会小非常多,就可以把long double替换成double了...(然后就可以快很多很多)
(嗯...误差问题都出在求单位根上了...)

现在\(7\)次\(DFT\)已经挺快了...还可以优化,可以看毛啸的论文,或者这里以及这里。我咕了。


三模数\(NTT\):

//3786ms    8.95MB
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define G 3
#define MOD(x,mod) x>=mod&&(x-=mod)
#define ADD(x,v,mod) (x+=v)>=mod&&(x-=mod)
#define gc() getchar()
#define MAXIN 500000
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=(1<<18)+3,Mod[]={998244353,469762049,1004535809};int tA[N],tB[N],A[N],B[N],Ans[3][N],rev[N];
char IN[MAXIN],*SS=IN,*TT=IN;inline int read()
{int now=0;register char c=gc();for(;!isdigit(c);c=gc());for(;isdigit(c);now=now*10+c-48,c=gc());return now;
}
inline int FP(int x,int k,const int mod)
{int t=1;for(; k; k>>=1,x=1ll*x*x%mod)if(k&1) t=1ll*t*x%mod;return t;
}
inline LL Mult(LL a,LL b,LL p)
{LL t=a*b-(LL)((long double)a/p*b+1e-8)*p;return t<0?t+p:t;
}
void NTT(int *a,int lim,int opt,const int mod)
{const int invG=FP(G,mod-2,mod);for(int i=1; i<lim; ++i) if(i<rev[i]) std::swap(a[i],a[rev[i]]);//&&for(int i=2; i<=lim; i<<=1){int mid=i>>1,Wn=FP(~opt?G:invG,(mod-1)/i,mod);for(int j=0; j<lim; j+=i)for(int t,w=1,k=j; k<j+mid; ++k,w=1ll*w*Wn%mod)a[k+mid]=a[k]+mod-(t=1ll*a[k+mid]*w%mod), MOD(a[k+mid],mod),ADD(a[k],t,mod);}if(opt==-1) for(int i=0,inv=FP(lim,mod-2,mod); i<lim; ++i) a[i]=1ll*a[i]*inv%mod;
}
void Solve(const int lim,int *ans,const int mod)
{memcpy(A,tA,lim<<2), memcpy(B,tB,lim<<2);//不能只赋值到n!(清空后面的)NTT(A,lim,1,mod), NTT(B,lim,1,mod);for(int i=0; i<lim; ++i) A[i]=1ll*A[i]*B[i]%mod;NTT(A,lim,-1,mod);for(int i=0; i<lim; ++i) ans[i]=A[i];
}int main()
{const int n=read(),m=read(),P=read();for(int i=0; i<=n; ++i) tA[i]=read(),tA[i]>=P&&(tA[i]%=P);for(int i=0; i<=m; ++i) tB[i]=read(),tB[i]>=P&&(tB[i]%=P);int lim=1,l=-1; while(lim<=n+m) lim<<=1,++l;for(int i=1; i<lim; ++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<l);for(int i=0; i<3; ++i) Solve(lim,Ans[i],Mod[i]);#define m1 998244353ll#define m2 469762049ll#define m3 1004535809llconst LL M12=m1*m2,inv2=FP(m2,m1-2,m1),inv1=FP(m1,m2-2,m2),mul2=m2*inv2%M12,mul1=m1*inv1%M12,inv=FP(M12%m3,m3-2,m3),m12=M12%P;for(int i=0,t=n+m; i<=t; ++i){LL c1=Ans[0][i],c2=Ans[1][i],c3=Ans[2][i],c4=Mult(c1,mul2,M12)+Mult(c2,mul1,M12);MOD(c4,M12);LL a=((c3-c4)%m3+m3)/*%m3*/*inv%m3;printf("%d ",(int)((a*m12+c4)%P));}return 0;
}

\(MTT\):

//1094ms    26.14MB
#include <cmath>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define MAXIN 300000
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
typedef long double ld;
//#define double long double
const int N=(1<<18)+3;
const double PI=acos(-1);int rev[N];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Complex
{double x,y;Complex(double x=0,double y=0):x(x),y(y) {}inline Complex operator +(const Complex &a)const {return Complex(x+a.x, y+a.y);}inline Complex operator -(const Complex &a)const {return Complex(x-a.x, y-a.y);}inline Complex operator *(const Complex &a)const {return Complex(x*a.x-y*a.y, y*a.x+x*a.y);}
}A[N],B[N],C[N],D[N],W[N];inline int read()
{int now=0; register char c=gc();for(;!isdigit(c);c=gc());for(;isdigit(c);now=now*10+c-'0',c=gc());return now;
}
void FFT(Complex *a,const int lim,const int opt)
{static Complex w[N];for(int i=1; i<lim; ++i) if(i<rev[i]) std::swap(a[i],a[rev[i]]);for(int i=2; i<=lim; i<<=1){int mid=i>>1;if(~opt) for(int k=0,t=lim/i; k<mid; ++k) w[k]=W[k*t];else for(int k=0,t=lim/i; k<mid; ++k) w[k]=Complex(W[k*t].x,-W[k*t].y);for(int j=0; j<lim; j+=i){Complex t;for(int k=j; k<j+mid; ++k)a[k+mid]=a[k]-(t=w[k-j]*a[k+mid]), a[k]=a[k]+t;}}if(opt==-1) for(int i=0; i<lim; ++i) a[i].x/=lim;
}int main()
{const int n=read(),m=read(),P=read();for(int i=0,t; i<=n; ++i) t=read(),A[i].x=t>>15,B[i].x=t&32767;for(int i=0,t; i<=m; ++i) t=read(),C[i].x=t>>15,D[i].x=t&32767;int lim=1,l=-1; while(lim<=n+m) lim<<=1,++l;for(int i=0; i<lim; ++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<l);for(int i=0,t=lim>>1; i<lim; ++i) W[i]=Complex(std::cos(i*PI/t),std::sin(i*PI/t));
//  const Complex Wn(std::cos(2.0*PI/lim),std::sin(2.0*PI/lim)); Complex w(1,0);
//  for(int i=0; i<lim; ++i) W[i]=w, w=w*Wn;//精度巨差 FFT(A,lim,1), FFT(B,lim,1), FFT(C,lim,1), FFT(D,lim,1);for(int i=0; i<lim; ++i){const Complex a=A[i],b=B[i],c=C[i],d=D[i];A[i]=a*c, B[i]=a*d+b*c, D[i]=b*d;}FFT(A,lim,-1), FFT(B,lim,-1), FFT(D,lim,-1);for(int i=0,t=n+m; i<=t; ++i){LL res=((LL(A[i].x+0.5))%P<<30)+((LL(B[i].x+0.5))%P<<15)+(LL(D[i].x+0.5));printf("%d ",(int)(res%P));}return 0;
}

转载于:https://www.cnblogs.com/SovietPower/p/10546764.html

洛谷.4245.[模板]任意模数NTT(MTT/三模数NTT)相关推荐

  1. 任意模数ntt_【模板篇】NTT和三模数NTT

    之前写过FFT的笔记. 我们知道FFT是在复数域上进行的变换. 而且经过数学家的证明, DFT是复数域上唯一满足循环卷积性质的变换. 而我们在OI中, 经常遇到对xxxx取模的题目, 这就启发我们可不 ...

  2. 专题·树链剖分【including 洛谷·【模板】树链剖分

    初见安~~~终于学会了树剖~~~ [兴奋]当初机房的大佬在学树剖的时候我反复强调过:"学树剖没有前途的!!!" 恩.真香. 一.重链与重儿子 所谓树剖--树链剖分,就是赋予一个链的 ...

  3. 洛谷·【模板】点分树 | 震波【including 点分树

    初见安-这里是传送门:洛谷P6329 [模板]点分树 | 震波 一.点分树 其实你会点分治的话,点分树就是把点分治时的重心提出来重新连城一棵树. 比如当前点是u,求出子树v的重心root后将root与 ...

  4. 【洛谷P4705】玩游戏【二项式定理】【NTT卷积】【生成函数】【分治NTT】【函数求导】【多项式对数】

    传送门 题意:给定长度为N,MN,MN,M的序列a,ba,ba,b和ttt,随机选取x∈[1,N],y∈[1,M]x \in[1,N],y\in[1,M]x∈[1,N],y∈[1,M],对于i=1,2 ...

  5. 洛谷刷题C语言:闰年判断、Apples、洛谷团队系统、肥胖问题、三位数排序

    记录洛谷刷题QAQ 一.[深基3.例3]闰年判断 题目描述 输入一个年份,判断这一年是否是闰年,如果是输出 111,否则输出 000. 输入格式 输入一个正整数 nnn,表示年份. 输出格式 输出一行 ...

  6. 洛谷 P1919 模板】A*B Problem升级版(FFT快速傅里叶)

    https://www.luogu.com.cn/problem/P1919 题目背景 本题数据已加强,请使用 FFT/NTT,不要再交 Python 代码浪费评测资源. 题目描述 给你两个正整数 a ...

  7. 洛谷.4897.[模板]最小割树(Dinic)

    题目链接 最小割树模板.具体见:https://www.cnblogs.com/SovietPower/p/9734013.html. ISAP不知为啥T成0分了.. Dinic: //1566ms ...

  8. 强连通分量:洛谷P3387 模板:缩点

    传送门 顾名思义,模板awa #include <cstdio> #include <cstring> #include <cmath> #include < ...

  9. 【后缀数组】洛谷P3809模板题

    题目背景 这是一道模板题. 题目描述 读入一个长度为 n n n 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置. ...

最新文章

  1. 云从科技IPO上市,AI四小龙同路不同归
  2. SpringCloud Greenwich(七)集成dubbo先启动消费者(check=false),然后启动提供者无法自动发现注册
  3. SpringBoot:Could not autowire there is more than one bean of xx type
  4. TODA-MES电池行业解决方案
  5. Linux 基本命令篇 - 计算机信息
  6. 第十二章——SQLServer统计信息(3)——发现过期统计信息并处理
  7. micropython和python区别-MicroPython入坑记(三)板子上的Python到底有多快?
  8. 《淘宝网开店 拍摄 修图 设计 装修 实战150招》一一2.8  黄金分割的三分法构图...
  9. oracle实现累加,oracle用sum函数实现累加
  10. 【FTP工具】8UFTP工具是我自己比较经常用的,推荐。
  11. com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table doesn't exist
  12. SSM框架整合—CRM小案例
  13. 从图灵奖小插曲看50年来什么样的人工智能最受追捧
  14. 【UI设计No9】VI
  15. DSS部署-12、DSS安装
  16. 按照题目打印菜单c语言,--单片机C语言编程实训
  17. ewebeditor文件上传漏洞2.8.0版本(漏洞复现)
  18. 孝经白话:广要道章第十二
  19. Rimworld Mod制作教程1 认识Mod结构
  20. 【投影仪】投影仪相关知识及参数科普(秒懂如何选择一款合适的投影仪)

热门文章

  1. 写出最感兴趣的软件测试工作,你还不会写测试用例?!注意这五点,写出模板级的测试用例!...
  2. 企业品牌网站建设都涉及收取哪些方面的费用?
  3. python 微信模块_Python使用itchat模块实现简单的微信控制电脑功能示例
  4. 服务器信号分析,服务器及其讯号解析装置 Server and its signal analysis apparatus
  5. java concat和 的区别,RxJava2 merge和concat 区别
  6. mongodb模糊查询 php7_详解php7如何实现MongoDB模糊查询
  7. (传送门)Ubuntu 常用软件安装
  8. StratifiedShuffleSplit 交叉验证
  9. nginx 只写了listen80 没有 listen443 用https访问
  10. python3 打印完整报错信息 以flask 为例