任意模数多项式乘法MTT(可拆系数FFT)详解

更好的阅读体验

任意模数多项式乘法

前言:
在教练讲的时候脑子并不清醒,所以没听懂。后来自己看博客学会了,但目前只学了一种方法:可拆系数FFT。为了方便日后复习,决定先写下这个的笔记,关于三模数NTT下次再补。

建议:准备好演算纸和笔,本篇含有大量推算部分。

为什么不直接使用NTT/FFT

此处的模数是任意的,所以我们使用NTT时,有局限性。只有当模数满足下列情况时才可使用NTT。

模数为 P P P P = r × 2 k + 1 P=r\times 2^k + 1 P=r×2k+1,其中 k k k足够大,满足 2 k ≥ N 2^k \geq N 2kN,其中 N N N为多项式扩充后的项数,多项式乘法都需要将项数扩充到 2 2 2的幂。

如果不满足上述条件,就不能直接使用NTT。

那为什么不使用FFT带模运算?
首先不考虑模数的情况下,多项式结果的系数不能超过 d o u b l e double double能表示的精度(一般在 1 0 16 10^{16} 1016)。超过后, d o u b l e double double所表示的结果将不再精确。

那怎么办?目前可以给出两种解决方法

  1. 可拆系数FFT
  2. 三模数NTT<s>(可是我还没学懂QAQ)</s>

所以,向可拆系数FFT进发!

可拆系数FFT

怎么用可拆系数FFT

首先我们还是先假设一个情景:

求: c 1 c_1 c1 c 2 c_2 c2的卷积

我们可以把一个数拆成 a × 2 15 + b a\times 2^{15}+b a×215+b的形式(不一定是 2 15 2^{15} 215,大概在 值域 \sqrt{值域} 值域 内)。

c 1 = a 1 × 2 15 + a 2 c 2 = b 1 × 2 15 + b 2 c_1=a_1\times 2^{15}+a_2 \\ c_2=b_1\times 2^{15}+b_2 c1=a1×215+a2c2=b1×215+b2

那这俩的积为

c 1 × c 2 = ( a 1 × 2 15 + a 2 ) × ( b 1 × 2 15 + b 2 ) = a 1 b 1 × 2 30 + ( a 1 b 2 + a 2 b 1 ) × 2 15 + a 2 b 2 \begin{aligned} c_1\times c_2&=(a_1\times 2^{15}+a_2)\times(b_1\times 2^{15}+b_2)\\&=a_1b_1\times 2^{30}+(a_1b_2+a_2b_1)\times 2^{15}+a_2b_2 \end{aligned} c1×c2=(a1×215+a2)×(b1×215+b2)=a1b1×230+(a1b2+a2b1)×215+a2b2

好耶!那我们可以直接做4次FFT( a 1 b 1 a_1b_1 a1b1 a 1 b 2 a_1b_2 a1b2 a 2 b 1 a_2b_1 a2b1 a 2 b 2 a_2b_2 a2b2)!
<s>然后你发现正逆变换总共做了8次常数爆炸然后炸了</s>

所以,我们需要优化!

优化可拆系数FFT

注意:我们这里的优化会用到复数,你可能会害怕得逃走,但是你无需害怕,因为<s>(我也是这样过来的)</s>我会简单地讲一讲。

小资料(可能不太学术规范):
啥是复数?

其实复数,是一种含实部和虚部的一种数。我们知道 i = − 1 i=\sqrt{-1} i=1 i i i就是虚数。那我们以实部建立 x x x轴、虚部建立 y y y轴。

那我们假设在这个平面直角坐标系上有一个点 A ( 2 , 3 ) A(2,3) A(2,3),那这个点的复数表示为 2 + 3 i 2+3i 2+3i

那你就基本知道什么是复数了,让我们学一下基本运算吧。(这个自己记一记好了)

我们可以利用一下复数的乘法运算:

( a + b i ) ( c + d i ) = ( a c − b d ) + ( a d + b c ) i ( a − b i ) ( c + d i ) = ( a c + b d ) + ( a d − b c ) i (a+bi)(c+di)=(ac-bd)+(ad+bc)i\\ (a-bi)(c+di)=(ac+bd)+(ad-bc)i (a+bi)(c+di)=(acbd)+(ad+bc)i(abi)(c+di)=(ac+bd)+(adbc)i

现在令 P 1 = a 1 + a 2 i P_1=a_1+a_2i P1=a1+a2i P 2 = a 1 − a 2 i P_2=a_1-a_2i P2=a1a2i Q = b 1 + b 2 i Q=b_1+b_2i Q=b1+b2i
计算:

P 1 Q + P 2 Q = ( a 1 b 1 − a 2 b 2 ) + ( a 1 b 2 + a 2 b 1 ) i + ( a 1 b 1 + a 2 b 2 ) + ( a 1 b 2 − a 2 b 1 ) i = 2 ( a 1 b 1 + a 1 b 2 i ) \begin{aligned} P_1Q+P_2Q&=(a_1b_1-a_2b_2)+(a_1b_2+a_2b_1)i+(a_1b_1+a_2b_2)+(a_1b_2-a_2b_1)i\\ &=2(a_1b_1+a_1b_2i) \end{aligned} P1Q+P2Q=(a1b1a2b2)+(a1b2+a2b1)i+(a1b1+a2b2)+(a1b2a2b1)i=2(a1b1+a1b2i)

如果我们将上式除以 2 2 2,那我们可以得到 a 1 b 1 , a 1 b 2 a_1b_1,a_1b_2 a1b1,a1b2(分别通过“实部相加/2”、“虚部相加/2”可得)。

我们把得到的 a 1 b 1 a_1b_1 a1b1代入 P 2 Q P_2Q P2Q的实部,可得 a 2 b 2 a_2b_2 a2b2
类似地,将 a 1 b 2 a_1b_2 a1b2代入 P 1 Q P_1Q P1Q的虚部,可得 a 2 b 1 a_2b_1 a2b1

(注:这里的运算请自己用演算纸推一下)

我们就可以带回 c 1 × c 2 c_1\times c_2 c1×c2了。

那我们的任务就完成啦!!

代码实现

注:此处的FFT部分与FFT版题的部分是一模一样的,可参照本人之前所写的FFT笔记。

板子:P4245 【模板】任意模数多项式乘法

code:

#include<bits/stdc++.h>
using namespace std;#define ll long long
#define rp(i,o,p) for(ll i=o;i<=p;++i)
#define pr(i,o,p) for(ll i=o;i>=p;--i)
#define cp complex<long double>const ll MAXN=1e5+5,P=1e9+7;
const ll lim=32000; // lim = sqrt(值域) <- 1e9
const long double PI=acos(-1.0);cp p1[MAXN<<2],p2[MAXN<<2],q[MAXN<<2];
ll n,m,limit;
cp p[MAXN<<2],omg[MAXN<<2],inv[MAXN<<2];void init() {for (ll i = 0; i < limit; ++i) {omg[i] = cp(cos(2 * PI * i / limit), sin(2 * PI * i / limit));inv[i] = conj(omg[i]);}
}void fft(cp *a, cp *omg) {for (ll i = 0, j = 0; i < limit; ++i) {if (i > j)swap(a[i], a[j]);for (ll l = limit >> 1; (j ^= l) < l; l >>= 1);}for (ll l = 2; l <= limit; l <<= 1) {ll m = l >> 1;for (cp *p = a; p != a + limit; p += l) {rp(i, 0, m - 1) {cp t = omg[limit / l * i] * p[i + m];p[i + m] = p[i] - t;p[i] += t;}}}
}int main()
{scanf("%lld%lld",&n,&m);rp(i,0,n){ll x;scanf("%lld",&x);p1[i]=cp(x/lim,x%lim);p2[i]=cp(x/lim,-x%lim);}rp(i,0,m){ll x;scanf("%lld",&x);q[i]=cp(x/lim,x%lim);}limit=1;while(limit<=n+m) limit<<=1;init();fft(p1,omg),fft(p2,omg),fft(q,omg);rp(i,0,limit-1){long double xx,xy;xx=p1[i].real()*q[i].real(),yy=p1[i].imag()*q[i].imag();xy=p1[i].real()*q[i].imag(),yx=p1[i].imag()*q[i].real();p1[i]=cp(xx/limit-yy/limit,xy/limit+yx/limit);xx=p2[i].real()*q[i].real(),yy=p2[i].imag()*q[i].imag();xy=p2[i].real()*q[i].imag(),yx=p2[i].imag()*q[i].real();p2[i]=cp(xx/limit-yy/limit,xy/limit+yx/limit);}/*上面的循环等价于这两行循环,但是因为c++中complex模板为const类型,单独的real()或imag()值不可以直接修改,只可以两个同时赋值来修改,所以上面的循环还用到了复数的除法运算,自己看看吧rp(i,0,limit-1) q[i].real()/=limit,q[i].imag()/=limit;rp(i,0,limit-1) p1[i]*=q[i],p2[i]*=q[i];*/fft(p1,inv),fft(p2,inv);rp(i,0,n+m){ll a1b1=(ll)((p1[i].real()+p2[i].real())/2+0.5)%P;ll a1b2=(ll)((p1[i].imag()+p2[i].imag())/2+0.5)%P;ll a2b1=(ll)((p1[i].imag()+0.5)-a1b2)%P;ll a2b2=(ll)((p2[i].real()+0.5)-a1b1)%P;ll ans=(a1b1*lim*lim+(a1b2+a2b1)*lim+a2b2)%P;ans=(ans%P+P)%P;printf("%lld ",ans);}return 0;
}

后记

三模数NTT的内容会尽快补上的。

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

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

相关文章

【Linux】常见指令(一)

前言: Linux有许多的指令&#xff0c;通过学习这些指令&#xff0c;可以对目录及文件进行操作。 文章目录 一、基础指令1. ls—列出目录内容2. pwd—显示当前目录3. cd—切换目录重新认识指令4. touch—创建文件等5. mkdir—创建目录6. rmdir指令 && rm 指令7. man—显…

【胡寿松 自动控制原理】【考研冲刺加分神器】各院校考研例题详细讲解

声明&#xff1a;本人水平有限&#xff0c;博客可能存在部分错误的地方&#xff0c;请广大读者谅解并向本人反馈错误。    本专栏中包含【胡寿松 自动控制原理】专业课的例题讲解&#xff0c;适合考研冲刺阶段学习&#xff0c;该视频只适合作为辅助教学视频来使用&#xff0c…

关于linux 救援模式出现xfs 文件系统挂载报 bad supperblock

关于linux 救援模式出现xfs 文件系统挂载报 bad supperblock 一种情况说明 挂载ISO文件进入救援模式&#xff0c;无法挂载XFS文件系统&#xff0c;xfs_repair也是报未知的超级块 使用 xfs_info 可以取到 xfs文件系统分区信息 xfs_db -c “sb 0” -c “p” $your_xfs_dev 也能…

笔试面试题——二叉树进阶(三)

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、二叉树的前序非递归遍历1、题目讲解2、思路讲解3、代码实现 二、二叉树的中序非递归遍历1…

GitHub README-Template.md - README.md 模板

GitHub README-Template.md - README.md 模板 1. README-Template.md 预览模式2. README-Template.md 编辑模式References A template to make good README.md. https://gist.github.com/PurpleBooth/109311bb0361f32d87a2 1. README-Template.md 预览模式 2. README-Templat…

go语言(十三)-----interface

一、Interface 通用万能类型 空接口int&#xff0c;string&#xff0c;float&#xff0c;struct都实现了interface都可以用interface{}类型,引用任意的数据类型 package mainimport "fmt"//interface()是万能数据类型 func myFunc(arg interface{}) {fmt.Println(&…

续签KES证书

MiniO KES&#xff08;密钥加密服务&#xff09;是 MinIO 开发的一项服务&#xff0c;旨在弥合在 Kubernetes 中运行的应用程序与集中式密钥管理服务 &#xff08;KMS&#xff09; 之间的差距。中央 KMS 服务器包含所有状态信息&#xff0c;而 KES 在需要执行与获取新密钥或更新…

Med-YOLO:3D + 医学影像 + 检测框架

Med-YOLO&#xff1a;3D 医学影像 检测框架 提出背景设计思路网络设计训练设计讨论分析 魔改代码&#xff1a;加强小目标检测总结 提出背景 论文链接&#xff1a;https://arxiv.org/abs/2312.07729 代码链接&#xff1a;https://github.com/JDSobek/MedYOLO 提出背景&…

一文梳理Windows自启动位置

不同版本的Windows开机自启动的位置略有出入&#xff0c;一般来说&#xff0c;Windows自启动的位置有&#xff1a;自启动文件夹、注册表子键、自动批处理文件、系统配置文件等。如果计算机感染了木马&#xff0c;很有可能就潜伏于其中&#xff01;本文将说明这些常见的Windows开…

理想架构的非对称高回退Doherty功率放大器理论与仿真

Doherty理论—理想架构的非对称高回退Doherty功率放大器理论与仿真 参考&#xff1a; 三路Doherty设计 01 射频基础知识–基础概念 Switchmode RF and Microwave Power Amplifiers 目录 Doherty理论---理想架构的非对称高回退Doherty功率放大器理论与仿真0、高回退Doherty功率…

UVT音乐证书考试时间确定,学习氛围渐浓

美国职业资格与人才管理中心&#xff08;UVT&#xff09;音乐证书考试时间正式确定&#xff0c;学习氛围逐渐浓厚。众多热爱音乐的从业者和学生开始积极备考&#xff0c;希望通过这一考试获得音乐领域的宝贵证书。音乐证书被认为是音乐人才展示个人专业水平的重要机会&#xff…

【K8S 云原生】K8S的包包管理器-helm

目录 一、helm概念 1、什么是helm 2、helm的概念&#xff1a; 二、实验部署&#xff1a; 1、安装helm&#xff1a; 2、对chart仓库的基本使用&#xff1a; 2.1、查看和更新chart仓库 2.2、安装chart 2.3、卸载chart&#xff1a; 3、helm自定义模版&#xff1a; 3.1、…

常规二分查找中遇到的问题

以前我们写二分查找的时候&#xff0c;是这么写的&#xff1a; public static int binarySearch2(int []a,int target){int i0,ja.length-1;while(i<j){int mid(ij)/2;if(a[mid]target){return mid;}else if(a[mid]<target){imid1;}else {jmid-1;}}return -1;} 这么写&…

签名不对,请检查包名是否与开放平台上填写的一致。微信分享 errorCode 为-6(方法有两种)

微信分享 errorCode 为-6 解决办法1.自己编译&#xff0c;把MD5加密文件改成小写且去掉&#xff1a;如下图 解决方法2 下载GenSignature 输入包名 然后生成应用签名 在微信开放平台创建应用&#xff0c;填写应用签名

74.MySQL 分页原理与优化(下)

文章目录 前言一、一次分页查询的演进二、分页数据在不同页反复出现的坑 前言 上一篇文章介绍了分页原理与优化&#xff1a;73.MySQL 分页原理与优化&#xff08;上&#xff09; 但分页还有一个“坑”需要注意&#xff0c;本文细细道来&#xff0c;可能很多朋友都踩过这个坑还…

REVIT二次开发批量编号

步骤1 步骤2 步骤3 实现代码using System; using System.Collections.Generic; using System.Linq; using Syste

基于springboot+vue的教师工作量管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目背景…

Mybatis-Generator-1.4.2

知道代码自动化原理&#xff0c;可以自己搞的&#xff0c;连客户端js html一起弄掉 Low Code Development Platform(LCDP)_cms lcdp-CSDN博客

一种行之有效的防错策略:在支付系统中实施防呆设计的实践

聊个支付人都会碰到的问题&#xff1a;资损防控。做支付如果还没有碰到过资损&#xff0c;那就是做得时间还不够久。资损防控是一个很大的话题&#xff0c;需要开几篇文章才能讲完&#xff0c;今天只从一件小事入手聊一个简单而又行之有效的防错策略&#xff1a;防呆设计的实践…

论文阅读_tinyllama_轻量级大模型

英文名称: TinyLlama: An Open-Source Small Language Model中文名称: TinyLlama: 一个开源的小型语言模型链接: http://arxiv.org/abs/2401.02385v1代码: https://github.com/jzhang38/TinyLlama作者: Peiyuan Zhang, Guangtao Zeng, Tianduo Wang, Wei Lu机构: 新加坡科技与设…