MTT 学习笔记

很久以前就听说了这东西,一直没空学。最近重学多项式,就重新搞了一下。

MTT 主要解决的是任意模数(或者说是没有模数)的多项式乘法,可以用于应对专门恶心人的毒瘤题。

首先,假设多项式次数 10510^5105,值域 10910^9109,那么朴素 FFT 光答案就高达 102310^{23}1023,就算你不损失精度也转不成 long long,况且中间值比这还要高几个量级。

MTT 采用拆系数的方法,即对于多项式 A(x)A(x)A(x),拆成两个多项式 MA0(x)+A1(x)MA_0(x)+A_1(x)MA0(x)+A1(x) 来减小精度压力。其中 MMM 为一较大整数,一般取 MOD\sqrt {MOD}MOD。要注意模数 2e92e92e9 级别的时候不要偷懒用位运算,2152^{15}2152162^{16}216 都容易炸,并且复杂度瓶颈不在这,不用卡这点常。

然后你只需要求 (MA0(x)+A1(x))(MB0(x)+B1(x))=M2A0(x)B0(x)+M(A0(x)B1(x)+A1(x)B0(x))+A1(x)B1(x)(MA_0(x)+A_1(x))(MB_0(x)+B_1(x))=M^2A_0(x)B_0(x)+M(A_0(x)B_1(x)+A_1(x)B_0(x))+A_1(x)B_1(x)(MA0(x)+A1(x))(MB0(x)+B1(x))=M2A0(x)B0(x)+M(A0(x)B1(x)+A1(x)B0(x))+A1(x)B1(x) 就可以了,这样答案是 101410^{14}1014 级别,开 long double 完全不虚。

这样一共需要 777 次 DFT,一般问题不大。接下来是利用高超的玄学技巧压到 444 次 DFT 的方法。

前置知识:普通 FFT 三次变两次

对于一般的实系数多项式乘法 A(x)⋅B(x)A(x)\cdot B(x)A(x)B(x),有一种优化方法是构造一个多项式 A(x)+i⋅B(x)A(x)+i\cdot B(x)A(x)+iB(x),因为是实系数,所以直接把 B(x)B(x)B(x) 的系数挂到虚部上就可以了。

对它做一次 DFT 然后自己乘自己,得到的是 A2(x)−B2(x)+2i⋅A(x)B(x)A^2(x)-B^2(x)+2i\cdot A(x)B(x)A2(x)B2(x)+2iA(x)B(x)

这样算出来的虚部除以 222 就是答案。

该算法将大量用到该思想。

DFT

考虑我们对两个实系数多项式 A(x),B(x)A(x),B(x)A(x),B(x) 做 DFT,因为是实系数,我们把虚部在那里空着显得很浪费,尝试把这个优化成一次 DFT。

构造多项式 A(x)+iB(x)A(x)+iB(x)A(x)+iB(x),花费一次 DFT 得到 DFT⁡(A(x)+i(B(x)))\operatorname{DFT}(A(x)+i(B(x)))DFT(A(x)+i(B(x)))。因为 DFT 的本质是点值,所以这个也等于 DFT⁡(A(x))+iDFT⁡(B(x))\operatorname{DFT}(A(x))+i\operatorname{DFT}(B(x))DFT(A(x))+iDFT(B(x))

这个显然不是实部和虚部的关系了。现在我们需要不用 DFT 把这两个分离开。

考虑共轭虚多项式 A(x)−iB(x)A(x)-iB(x)A(x)iB(x),如果它的 DFT 可以快速得到,我们就可以简单地求出 A(x)A(x)A(x)B(x)B(x)B(x) 的 DFT。

然后又是愉快的推式子时间。

设两个多项式的系数为 ai,bia_i,b_iai,bi,代入一个单位根 ωnk\omega_n^kωnk

DFT⁡(A(x)+iB(x))=A(ωnk)+iB(ωnk)\operatorname{DFT}(A(x)+iB(x))=A(\omega_n^k)+iB(\omega_n^k)DFT(A(x)+iB(x))=A(ωnk)+iB(ωnk)

=∑j=0n−1ajωnkj+ibjωnkj=\sum_{j=0}^{n-1}a_j\omega_n^{kj}+ib_j\omega_n^{kj}=j=0n1ajωnkj+ibjωnkj

推不动了,考虑硬算。令 ωnkj=xj+iyj\omega_n^{kj}=x_j+iy_jωnkj=xj+iyj

DFT⁡(A(x)+iB(x))=∑j=0n−1aj(xj+iyj)+ibj(xj+iyj)\operatorname{DFT}(A(x)+iB(x))=\sum_{j=0}^{n-1}a_j(x_j+iy_j)+ib_j(x_j+iy_j)DFT(A(x)+iB(x))=j=0n1aj(xj+iyj)+ibj(xj+iyj)

=∑j=0n−1(ajxj−bjyj)+i(ajyj+bjxj)=\sum_{j=0}^{n-1}(a_jx_j-b_jy_j)+i(a_jy_j+b_jx_j)=j=0n1(ajxjbjyj)+i(ajyj+bjxj)

然后这不是三角函数公式吗?

所以 DFT 的某一点值的本质就是两个多项式对应项组成的向量 (aj,bj)(a_j,b_j)(aj,bj) 旋转同一角度后的向量和。

对于另一边 DFT⁡(A(x)−iB(x))\operatorname{DFT}(A(x)-iB(x))DFT(A(x)iB(x)),其对应的向量是 (aj,−bj)(a_j,-b_j)(aj,bj) ,也就是关于 xxx 轴对称。那么我们把上面那个角度倒着旋转,得到的向量和也是对称的。

翻译成人话, DFT 后翻转再共轭就得到了共轭虚多项式的 DFT。

注意是长度为 nnn 的翻转,所以 000 的位置需要特判。

这样,我们用两次 DFT 得到了 A0(x),A1(x),B0(x),B1(x)A_0(x),A_1(x),B_0(x),B_1(x)A0(x),A1(x),B0(x),B1(x) 的 DFT。

然后我们就可以求出 A0(x)B0(x),A0(x)B1(x),A1(x)B0(x),A1(x)B1(x)A_0(x)B_0(x),A_0(x)B_1(x),A_1(x)B_0(x),A_1(x)B_1(x)A0(x)B0(x),A0(x)B1(x),A1(x)B0(x),A1(x)B1(x) 的点值了。

IDFT

还是用一样的方法抱团变换。

考虑构造多项式 P(x)=A0(x)B0(x)+iA0(x)B1(x)P(x)=A_0(x)B_0(x)+iA_0(x)B_1(x)P(x)=A0(x)B0(x)+iA0(x)B1(x),注意是 IDFT 之后的,也就是这里设的是我们要求的答案。

因为我们知道 A0(x)B0(x),A0(x)B1(x)A_0(x)B_0(x),A_0(x)B_1(x)A0(x)B0(x),A0(x)B1(x) 在所有单位根上的点值,所以可以直接求出 P(x)P(x)P(x) 的点值,然后做 IDFT,实部虚部就是 A0(x)B0(x)A_0(x)B_0(x)A0(x)B0(x)A0(x)B1(x)A_0(x)B_1(x)A0(x)B1(x)

另外两个同理,需要 222 次 IDFT。

总共做了 444 次 DFT,比三模数快了 888 倍。

注意输出的时候答案已经很大了,要先模了再乘 MMM

#include <iostream>
#include <cstring>
#include <cctype>
#include <cstdio>
#include <cmath>
#define MAXN 262144+5
#define double long double
using namespace std;
inline int read()
{int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans;
}
typedef long long ll;
const double Pi=acos(-1.0);
int p;
struct complex
{double x,y;inline complex(const double& x=0,const double& y=0):x(x),y(y){}	
};
inline complex operator +(const complex& a,const complex& b){return complex(a.x+b.x,a.y+b.y);}
inline complex operator -(const complex& a,const complex& b){return complex(a.x-b.x,a.y-b.y);}
inline complex operator *(const complex& a,const complex& b){return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
inline complex rev(const complex& a){return complex(a.x,-a.y);}
complex rt[2][20];
int l,lim,r[MAXN];
inline void init(){lim=1<<l;for (int i=0;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));}
inline void fft(complex* a,int type)
{for (int i=0;i<lim;i++) if (i<r[i]) swap(a[i],a[r[i]]);for (int L=0;L<l;L++){int mid=1<<L,len=mid<<1;complex Wn=rt[type][L+1];for (int s=0;s<lim;s+=len){complex w(1,0);for (int k=0;k<mid;k++,w=w*Wn){complex x=a[s+k],y=w*a[s+mid+k];a[s+k]=x+y,a[s+mid+k]=x-y;}}}if (type) for (int i=0;i<lim;i++) a[i].x/=lim,a[i].y/=lim;
}
complex A[MAXN],B[MAXN],C[MAXN],D[MAXN];
int main()
{freopen("test.in","r",stdin);freopen("test.out","w",stdout);for (int i=0;i<20;i++){double a=2*Pi/(1<<i);rt[0][i]=rev(rt[1][i]=complex(cos(a),sin(a)));}int n,m;n=read(),m=read(),p=read();for (l=0;(1<<l)<=n+m;l++);init();for (int i=0;i<=n;i++){int x=read();A[i]=complex(x>>15,x&((1<<15)-1));}for (int i=0;i<=m;i++){int x=read();C[i]=complex(x>>15,x&((1<<15)-1));}fft(A,0),fft(C,0);B[0]=rev(A[0]),D[0]=rev(C[0]);for (int i=1;i<lim;i++) B[i]=rev(A[lim-i]),D[i]=rev(C[lim-i]);for (int i=0;i<lim;i++) {complex a=A[i],b=B[i],c=C[i],d=D[i];A[i]=(a+b)*complex(0.5,0),B[i]=(a-b)*complex(0,-0.5);C[i]=(c+d)*complex(0.5,0),D[i]=(c-d)*complex(0,-0.5);}for (int i=0;i<lim;i++){complex a=A[i],b=B[i],c=C[i],d=D[i];A[i]=a*c+a*d*complex(0,1);B[i]=b*c+b*d*complex(0,1);}fft(A,1),fft(B,1);for (int i=0;i<=n+m;i++){ll ans=0;ll a=A[i].x+0.5,b=A[i].y+B[i].x+0.5,c=B[i].y+0.5;ans=(ans+((a%p)<<30))%p;ans=(ans+((b%p)<<15))%p;ans=(ans+c)%p;printf("%lld ",ans);}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/314825.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在 VS Code 中轻松 review GitHub Pull Requests

相信大家在平时工作或者自己的项目中&#xff0c;一定都有在 GitHub 上进行 Code Review 的经历。对于韩老师来说&#xff0c;不论是平时工作的项目&#xff0c;还是自己的业余项目&#xff0c;代码基本都是在 GitHub 上。所以&#xff0c;在 GitHub 上进行 Pull Requests 的 C…

Codeforces Round #732 (Div. 2) C. AquaMoon and Strange Sort 思维

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你nnn个数&#xff0c;每个数初始方向是向右&#xff0c;每次可以交换相邻两个位置并且将这两个位置的方向调换&#xff0c;问这个序列的最终状态能否是非递减且方向都向右。 n≤1e5,ai≤1e5n\le1e5,a_i\l…

【CC November Challenge 2012】Arithmetic Progressions【分块】【FFT】

题意&#xff1a;给定长度为 nnn 的正整数序列 AAA,求满足 i<j<k,Aj−AiAk−Aji<j<k,A_j-A_iA_k-A_ji<j<k,Aj​−Ai​Ak​−Aj​ 的三元组个数。 n≤105,Ai≤3104n\leq 10^5,A_i\leq 3\times 10^4n≤105,Ai​≤3104 三个位置只有 jjj 限制比较紧&#xff0c…

火热的云原生到底是什么?一文了解云原生四要素!

所谓云原生&#xff0c;它不是一个产品&#xff0c;而是一套技术体系和一套方法论&#xff0c;而数字化转型是思想先行&#xff0c;从内到外的整体变革。更确切地说&#xff0c;它是一种文化&#xff0c;更是一种潮流&#xff0c;是云计算的一个必然导向。随着虚拟化技术的成熟…

Codeforces Round #732 (Div. 2) D. AquaMoon and Chess 组合数学 + 找规律

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个010101串&#xff0c;当且仅当某个111的某一边i1,i−1i1,i-1i1,i−1有111&#xff0c;这个111可以跟i2,i−2i2,i-2i2,i−2交换位置&#xff0c;问最终能产生多少状态。 n≤1e5n\le1e5n≤1e5 思路&a…

为什么说拥抱.NET CORE的时候到了

微软和社区已经做了大量艰苦的工作&#xff0c;使.Net Core成为市场上具有竞争力的框架&#xff0c;帮助开发人员快速开发具有最佳性能和可扩展性的强大应用程序。做的最棒的事情是.Net Framework开发人员不需要任何新知识来处理.Net Core。这也是开发人员在很短的时间内采用.N…

【HNOI2016】序列【莫队】【单调栈】【ST表】

题意&#xff1a;给定序列 aia_iai​&#xff0c;qqq 次询问 [l,r][l,r][l,r] 所有子区间最小值之和。 n,q≤105n,q\leq 10^5n,q≤105 这种题一眼看上去是离线线段树&#xff0c;但这题每移动一位要维护区间取 min⁡\minmin&#xff0c;历史值之和&#xff0c;非常不可做。 所…

湖南大学第十六届程序设计竞赛 B Yuki with emofunc and playf 同余最短路

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 初始有一个数111&#xff0c;你每次可以将其∗10*10∗10或者(x−1)(x-1)(x−1)&#xff0c;现在给你xxx&#xff0c;问最少经过多少步能到达nnn。 1≤n≤1e6,1≤m≤1e91\le n\le1e6,1\le m\le1e91≤n≤1e6,1…

【HNOI2019】白兔之舞【组合数学】【矩阵快速幂】【单位根反演】【Chirp Z-Transform】【原根】【MTT】

题意&#xff1a;有一张 (L1)n(L1)\times n(L1)n 个点的有向图&#xff0c;每个结点有二元组 (x,y)(0≤x≤L,1≤y≤n)(x,y)~(0\leq x\leq L,1\leq y\leq n)(x,y) (0≤x≤L,1≤y≤n) 表示。对于所有 (u1,v1),(u2,v2)(u_1,v_1),(u_2,v_2)(u1​,v1​),(u2​,v2​)&#xff0c;若 u…

程序员如何学习英语

首先&#xff0c;这不是一篇广告&#xff0c;虽然这个标题很像。其次&#xff0c;我的英语水平也很一般&#xff0c;所以更多的是谈谈一些失败的经历和思考&#xff0c;俗话说&#xff0c;成功的经验不可复制&#xff0c;失败的经验倒可以让我们少走弯路。英语的重要性毋庸置疑…

Educational Codeforces Round 111 (Rated for Div. 2) D. Excellent Arrays 组合数学

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个数组aia_iai​&#xff0c;定义一个数组是好的当且仅当对于所有iii都有ai!ia_i!iai​!i。定义f(a)f(a)f(a)表示数组aaa中i<j,aiajiji<j,a_ia_jiji<j,ai​aj​ij的(i,j)(i,j)(i,j)对数。定义…

使用Azure云原生构建博客是怎样一种体验?(上篇)

点击上方蓝字关注“汪宇杰博客”导语https://edi.wang我的网站是在.NET Core 平台上使用 C#语言编写的开源博客系统&#xff0c;运行于微软智慧云 Azure 国际版上。本文将重点介绍 Azure 的各项服务如何为博客带来丝滑体验与保驾护航。历史回顾我博客的历史可以追溯到2003年&am…

AtCoder Regular Contest 100 D - Equal Cut 思维 + 前缀和

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个数组aaa&#xff0c;你要将其分成四份&#xff0c;让这四份中和的最大值−-−最小值最小&#xff0c;输出这个最小值。 n≤2e5,ai≤1e9n\le2e5,a_i\le1e9n≤2e5,ai​≤1e9 思路&#xff1a; 直接枚…

【UOJ574】多线程计算【二元二项式反演】【定积分】【矩阵】【NTT 卷积】

题意&#xff1a;有 nmn\times mnm 的网格&#xff0c;每个结点在 [0,1)[0,1)[0,1) 内的一个随机时刻被点亮。有 hhh 个数对 xi,yix_i,y_ixi​,yi​&#xff0c;对于一个瞬间状态&#xff0c;如果存在一个 xi,yix_i,y_ixi​,yi​ 使得恰好有 xix_ixi​ 行 yiy_iyi​ 列被点亮&a…

Orleans 知多少 | 2. 核心概念一览

Orleans 术语解读上面这张图中包含了Orleans中的几个核心概念&#xff1a;GrainSiloOrleans ClusterOrleans Client从这张图&#xff0c;我们应该能理清他们之间的关系。Grain作为最小的执行单元Silo 是 Grain 的宿主运行环境&#xff0c;用来暴露具体的服务Orleans Server 提供…

Codeforces Round #587 (Div. 3) C. White Sheet 思维

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个白色的矩形和俩个黑色的矩形&#xff0c;问白色被黑色覆盖后还能不能看到。 思路&#xff1a; 经典被简单题卡。 一开始写了个自我感觉很对的做法&#xff0c;结果wa41wa41wa41&#xff0c;检查不…

【UOJ575】光伏元件【网络流建图】【上下界网络流】【费用流】

题意&#xff1a; nnn\times nnn 的 01 矩阵&#xff0c;对于 i∈[1,n]i \in [1,n]i∈[1,n] 有三个参数 li,li,kil_i,l_i,k_ili​,li​,ki​&#xff0c;表示第 iii 行&#xff0c;第 iii 列的 111 的个数分别在 [li,ri][l_i,r_i][li​,ri​] 中&#xff0c;且差的绝对值不超过…

动手造轮子:实现一个简单的 EventBus

动手造轮子&#xff1a;实现一个简单的 EventBusIntroEventBus 是一种事件发布订阅模式&#xff0c;通过 EventBus 我们可以很方便的实现解耦&#xff0c;将事件的发起和事件的处理的很好的分隔开来&#xff0c;很好的实现解耦。微软官方的示例项目 EShopOnContainers 也有在使…

Codeforces Round #733 (Div. 1 + Div. 2) E. Minimax 分情况讨论 + 思维

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个串&#xff0c;你可以随意安排这个串&#xff0c;使得这个串的每个前缀的kmpkmpkmp数组最大值最小&#xff0c;定义为f(a)f(a)f(a)&#xff0c;并且字典序最小&#xff0c;输出安排之后的串。 n≤1e…

【Ynoi2011】成都七中【树论】【点分树】【离线】【树状数组】

题意&#xff1a;给一棵树&#xff0c;点有颜色&#xff0c;qqq 次询问&#xff0c;每次给定 l,r,xl,r,xl,r,x &#xff0c;求只保留编号在 [l,r][l,r][l,r] 中的点时点 xxx 所在连通块的颜色数。 所有数 ≤105\leq 10^5≤105 题目背景好评 首先所有颜色不同的话就是数连通块…