多项式乘法运算初级版

article/2025/8/15 9:11:54

快速傅里叶变换在信息学竞赛中主要用于求卷积,或者说多项式乘法。我们知道,多项式乘法的普通算法时间复杂度

,通过快速傅里叶变换可以使时间降为,那么接下来会详细介绍快速傅里叶变换的原理。

 

首先来介绍多项式的两种表示方法,即系数表示法点值表示法。从某种意义上说,这两种方法是等价的。先设

 

   

 

 

(1)系数表示法

 

    对于一个次数界为的多项式来说,其系数表示法就是一个由系数组成的向量,很

    明显,这样的多项式乘法运算的时间复杂度为

 

(2)点值表示法

 

    对于一个次数界为的多项式来说,其点值是个点值对所形成的集合

 

   

 

    其中各不相同,并且当时,有。可以看出一个多项式可以有多种不同的点值

    表示法,而通过这个不同的点值对可以表示一个唯一的多项式。而通过点值表示法来计算多项式的乘法,时间

    复杂度为

 

    从原则上来说,计算多项式的点值是简单易行的,因为我们只需要先选取个相异的点,然后通过秦九韶算法

    以在时间内求出所有的,实际上如果我们的选得巧妙的话,就可以加速这一过程,使其运行时间变

    为

 

    根据多项式的系数表示法求其点值表示法的过程称为求值,而根据点值表示法求其系数表示法的过程称为插值

 

    对于求卷积或者说多项式乘法运算问题,先是通过傅里叶变换对系数表示法的多项式进行求值运算,这一步的时

    间复杂度为,然后在时间内进行点值相乘,再进行插值运算。

 

那么,接下来就是我们今天的重点了,如何高效地对一个多项式进行求值运算,即将多项式的表示法变为点值表示法。

 

如果选取单位复根作为求值点,则可以通过对系数向量进行离散傅里叶变换(DFT),得到相应的点值表示。同样地

也可以通过对点值对进行逆DFT运算,获得相应的系数向量。DFT逆DFT的时间复杂度均为

 

 

一. 求DFT

 

    选取次单位复根作为来求点值是比较巧妙的做法。

    次单位复根是满足的复数次单位复根恰好有个,它们是,为

    了解释这一式子,利用复数幂的定义,值称为主次单位根,所有其

    它次单位复根都是次幂。

 

    次单位复根在乘法运算下形成一个群,该群的结构与加法群相同。

 

    接下来认识几个关于次单位复根的重要性质。

   

    (1)相消引理

 

        对于任何整数,有

 

    (2)折半引理

 

        如果且为偶数,则

 

    (3)求和引理

 

        对任意整数和不能被整除的非零整数,有

 

          

 

     回顾一下,我们希望计算次数界为的多项式

 

    

 

     在处的值,假定2的幂,因为给定的次数界总可以增大,如果需要,总可以添加值为零

     的新的高阶系数。假定已知的系数形式为,对,定义结果

     如下

 

                

 

     向量是系数向量的离散傅里叶变换,写作

     通过使用一种称为快速傅里叶变换(FFT)的方法,就可以在时间内计算出,而直接

     计算的方法所需时间为FFT主要是利用单位复根的特殊性质。FFT方法运用了分治策略,它用

     中偶数下标的系数与奇数下标的系数,分别定义了两个新的次数界为的多项式

 

     

 

     则进一步有

 

     这样处的值得问题就转换为求次数界为的多项式在点

     处的值。由于在奇偶分类时导致顺序发生变化,所以需要先通过Rader算法进行

     倒位序,在FFT中最重要的一个操作是蝴蝶操作,通过蝴蝶操作可以将前半部分和后半部分的值求出。

 

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1402

 

题意:大数乘法,需要用FFT实现。

 

代码:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>using namespace std;
const int N = 500005;
const double PI = acos(-1.0);struct Virt
{double r, i;Virt(double r = 0.0,double i = 0.0){this->r = r;this->i = i;}Virt operator + (const Virt &x){return Virt(r + x.r, i + x.i);}Virt operator - (const Virt &x){return Virt(r - x.r, i - x.i);}Virt operator * (const Virt &x){return Virt(r * x.r - i * x.i, i * x.r + r * x.i);}
};//雷德算法--倒位序
void Rader(Virt F[], int len)
{int j = len >> 1;for(int i=1; i<len-1; i++){if(i < j) swap(F[i], F[j]);int k = len >> 1;while(j >= k){j -= k;k >>= 1;}if(j < k) j += k;}
}//FFT实现
void FFT(Virt F[], int len, int on)
{Rader(F, len);for(int h=2; h<=len; h<<=1) //分治后计算长度为h的DFT{Virt wn(cos(-on*2*PI/h), sin(-on*2*PI/h));  //单位复根e^(2*PI/m)用欧拉公式展开for(int j=0; j<len; j+=h){Virt w(1,0);            //旋转因子for(int k=j; k<j+h/2; k++){Virt u = F[k];Virt t = w * F[k + h / 2];F[k] = u + t;     //蝴蝶合并操作F[k + h / 2] = u - t;w = w * wn;      //更新旋转因子}}}if(on == -1)for(int i=0; i<len; i++)F[i].r /= len;
}//求卷积
void Conv(Virt a[],Virt b[],int len)
{FFT(a,len,1);FFT(b,len,1);for(int i=0; i<len; i++)a[i] = a[i]*b[i];FFT(a,len,-1);
}char str1[N],str2[N];
Virt va[N],vb[N];
int result[N];
int len;void Init(char str1[],char str2[])
{int len1 = strlen(str1);int len2 = strlen(str2);len = 1;while(len < 2*len1 || len < 2*len2) len <<= 1;int i;for(i=0; i<len1; i++){va[i].r = str1[len1-i-1] - '0';va[i].i = 0.0;}while(i < len){va[i].r = va[i].i = 0.0;i++;}for(i=0; i<len2; i++){vb[i].r = str2[len2-i-1] - '0';vb[i].i = 0.0;}while(i < len){vb[i].r = vb[i].i = 0.0;i++;}
}void Work()
{Conv(va,vb,len);for(int i=0; i<len; i++)result[i] = va[i].r+0.5;
}void Export()
{for(int i=0; i<len; i++){result[i+1] += result[i]/10;result[i] %= 10;}int high = 0;for(int i=len-1; i>=0; i--){if(result[i]){high = i;break;}}for(int i=high; i>=0; i--)printf("%d",result[i]);puts("");
}int main()
{while(~scanf("%s%s",str1,str2)){Init(str1,str2);Work();Export();}return 0;
}


题目:http://acm.hdu.edu.cn/showproblem.php?pid=4609

 

题意:给定n条长度已知的边,求能组成多少个三角形。

 

分析:用一个num数组来记录次数,比如num[i]表示长度为i的边有num[i]条。然后对num[]求卷积,除去本身重

     复的和对称的,然后再整理一下就好了。

 

代码:

#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
#include <math.h>using namespace std;
typedef long long LL;const int N = 400005;
const double PI = acos(-1.0);struct Virt
{double r,i;Virt(double r = 0.0,double i = 0.0){this->r = r;this->i = i;}Virt operator + (const Virt &x){return Virt(r+x.r,i+x.i);}Virt operator - (const Virt &x){return Virt(r-x.r,i-x.i);}Virt operator * (const Virt &x){return Virt(r*x.r-i*x.i,i*x.r+r*x.i);}
};//雷德算法--倒位序
void Rader(Virt F[],int len)
{int j = len >> 1;for(int i=1; i<len-1; i++){if(i < j) swap(F[i], F[j]);int k = len >> 1;while(j >= k){j -= k;k >>= 1;}if(j < k) j += k;}
}//FFT实现
void FFT(Virt F[],int len,int on)
{Rader(F,len);for(int h=2; h<=len; h<<=1) //分治后计算长度为h的DFT{Virt wn(cos(-on*2*PI/h),sin(-on*2*PI/h));  //单位复根e^(2*PI/m)用欧拉公式展开for(int j=0; j<len; j+=h){Virt w(1,0);            //旋转因子for(int k=j; k<j+h/2; k++){Virt u = F[k];Virt t = w*F[k+h/2];F[k] = u+t;      //蝴蝶合并操作F[k+h/2] = u-t;w = w*wn;      //更新旋转因子}}}if(on == -1)for(int i=0; i<len; i++)F[i].r /= len;
}//求卷积
void Conv(Virt F[],int len)
{FFT(F,len,1);for(int i=0; i<len; i++)F[i] = F[i]*F[i];FFT(F,len,-1);
}int a[N];
Virt F[N];
LL num[N],sum[N];
int len,n;void Init()
{memset(num,0,sizeof(num));scanf("%d",&n);for(int i=0; i<n; i++){scanf("%d",&a[i]);num[a[i]]++;}sort(a, a + n);int len1 = a[n-1] + 1;len  = 1;while(len < len1*2) len <<= 1;for(int i=0; i<len1; i++)F[i] = Virt(num[i],0);for(int i=len1; i<len; i++)F[i] = Virt(0,0);
}void Work()
{Conv(F,len);for(int i=0; i<len; i++)num[i] = (LL)(F[i].r+0.5);len = a[n-1]*2;for(int i=0; i<n; i++)num[a[i]+a[i]]--;for(int i=1; i<=len; i++)num[i] >>= 1;sum[0] = 0;for(int i=1; i<=len; i++)sum[i] = sum[i-1] + num[i];LL cnt = 0;for(int i=0; i<n; i++){cnt+=sum[len]-sum[a[i]];//减掉一个取大,一个取小的cnt-=(LL)(n-1-i)*i;//减掉一个取本身,另外一个取其它cnt-=(n-1);//减掉大于它的取两个的组合cnt-=(LL)(n-1-i)*(n-i-2)/2;}LL tot = (LL)n*(n-1)*(n-2)/6;printf("%.7lf\n",(double)cnt/tot);
}int main()
{int T;scanf("%d",&T);while(T--){Init();Work();}return 0;
}

 

 


http://chatgpt.dhexx.cn/article/AfoFa7SQ.shtml

相关文章

FFT与多项式乘法

网上关于FFT在信号处理中应用的文章并不少&#xff0c;这里尽量少说废话&#xff0c;直接说如何用FFT实现多项式乘法。 多项式乘法&#xff0c;通常是用系数乘积的方式完成&#xff0c;这样的时间复杂度是O(n^2) n为多项式项数。系数乘法可以满足大多数的乘法需求&#xff0c;然…

多项式乘法

实验题目&#xff1a;多项式乘法问题 实验内容与要求 一元稀疏多项式简单计算器的基本功能是&#xff1a; &#xff08;1)输入并建立多项式。&#xff1b; &#xff08;2&#xff09;输出多项式&#xff0c;输出形式为整数序列&#xff1a;n,c1,e1,c2,e2,…,cn,en,其中n是多项…

多项式乘法运算终极版

在上一篇文章中 http://blog.csdn.net/acdreamers/article/details/39005227 介绍了用快速傅里叶变 换来求多项式的乘法。可以发现它是利用了单位复根的特殊性质&#xff0c;大大减少了运算&#xff0c;但是这种做法是对复数系数的矩阵 加以处理&#xff0c;每个复数系数的实…

多项式乘法(FFT)

1 前言 作为一名OI选手&#xff0c;至今未写过fft相关的博客&#xff0c;真是一大遗憾&#xff0c;这也导致我并没有真正推过fft的所有式子 这一篇fft的博客我将详细介绍多项式乘法&#xff0c;易于理解&#xff0c;主要是为了等我啥时候忘了回来看&#xff0c;当然&#xff0…

分治算法-03多项式乘法问题

多项式乘法 简介 多项式的运算表示是一个很常见的算法问题。 问题描述 给予两个多项式A(x)与B(x)&#xff0c;得出C(x)A(x)B(x)。例如&#xff0c;A(x)32x3x24x3&#xff0c;B(x)2x2&#xff0c;C(x)64x9x210x33x44x^5。 问题分析 一般情况下&#xff0c;使用系数表示多项式&a…

【数据结构】——多项式乘法

题目要求 从字符文件输入两个多项式的非零系数及对应的指数&#xff0c;建立多项式的链式存储结构&#xff0c;计算这两个多项式的乘积&#xff0c;输出乘积多项式的全部非零系数及对应的指数到另一字符文件中。 算法原理 两个多项式的乘法&#xff0c;可以借助两个多项式的…

多项式乘法(FFT)详解

本文只探讨多项式乘法(FFT)在信息学中的应用 如有错误或不明欢迎指出或提问&#xff0c;在此不胜感激 多项式 1. 系数表示法 一般应用最广泛的表示方式 用A(x)表示一个x-1次多项式&#xff0c;a[i]为 xi x i 的系数&#xff0c;则A(x) ∑n−10 ∑ 0 n − 1 a[i] * xi x i…

2.2 多项式乘法与加法运算(线性结构,C)

多项式乘法与加法运算 设计函数分别求两个一元多项式的乘积与和题意理解题意理解和积 求解思路多项式表示两种表示方式在事先已经知道具体多少项的时候&#xff0c;本题较好的实现方法&#xff1a;动态数组链表表示多项式的方法 程序框架如何读入多项式读入多项式的完整程序 加…

多项式乘法问题

多项式乘法问题 实验目的&#xff1a;设计一个一元稀疏多项式简单计算器。 实验内容与要求&#xff1a; 一元稀疏多项式简单计算器的基本功能是&#xff1a; &#xff08;1&#xff09;输入并建立多项式&#xff1b; &#xff08;2&#xff09;输出多项式&#xff0c;序列…

网络协议之视频直播核心技术讲解

网络视频直播存在已有很长一段时间&#xff0c;随着移动上下行带宽提升及资费的下调&#xff0c;视频直播被赋予了更多娱乐和社交的属性&#xff0c;人们享受随时随地进行直播和观看&#xff0c;直播的打开时间和延迟变成了影响产品功能发展重要指标。 那么&#xff0c;问题来了…

直播软件搭建技术原理:CDN 与直播

直播软件搭建技术原理&#xff1a;CDN 与直播 很多直播都是基于 CDN 来实现的。而通过声网的服务&#xff0c;或基于声网SDK与 CDN 结合&#xff0c;还可以实现在直播中的连麦互动、白板同步等强调实时性的场景。本文源自社区投稿&#xff0c;介绍了该场景下的一些基础知识。如…

暑期实习+秋招面经合集(更新ing)

大纲 开篇 自我介绍 &#xff1a;面试官你好&#xff0c;我叫林飞武&#xff0c;是一名通信工程大三学生&#xff0c;对计算机专业有着浓厚兴趣并且未来有志于在互联网的测试领域有深入发展。全套学习了计算机专业的专业课&#xff0c;计算机网络&#xff0c;操作系统等&#…

DNSPod十问王征:为什么你的网站无人问津?

&#x1f4e2; DNSPod十八周年庆将至&#xff0c;下期十问交给你来提问——《你&#xff0c;十问DNSPod》&#xff01;评论区留下你想问DNSPod团队的问题&#xff0c;一旦提问被选中&#xff0c;将得到十八周年纪念T恤&#xff01;详情请移步至DNSPod公众号十八周年庆推送。 广…

阿里云ACP认证考试笔记

课件&#xff1a;https://gitee.com/HanFerm/technical-documentation/tree/master/阿里云acp教材 本文档为公开内容 一、ACP是干嘛的 内容范围&#xff1a; 历史 二、阿里云综述 技术架构 优势 三、弹性计算 ECS ECS的组成与功能 ECS是由多个并列又相互关联的产品概念组成…

在互联网上,没有人知道你是一条狗?

1993 年&#xff0c;《纽约客》&#xff08;The New Yorker&#xff09;杂志刊登一则由彼得施泰纳&#xff08;Peter Steiner&#xff09;创作的漫画&#xff1a;标题是【On the Internet, nobody knows you’re a dog.】 这则漫画中有两只狗&#xff1a;一只黑狗站在电脑椅上…

分库分表和NewSQL如何选择?分库分表真的适合你的系统吗?

曾几何时&#xff0c;“并发高就分库&#xff0c;数据大就分表”已经成了处理 MySQL 数据增长问题的圣经。 面试官喜欢问&#xff0c;博主喜欢写&#xff0c;候选人也喜欢背&#xff0c;似乎已经形成了一个闭环。 但你有没有思考过&#xff0c;分库分表真的适合你的系统吗&am…

分库分表不一定适合你的系统,聊聊分库分表和NewSQL如何选择

曾几何时&#xff0c;“并发高就分库&#xff0c;数据大就分表”已经成了处理 MySQL 数据增长问题的圣经。 面试官喜欢问&#xff0c;博主喜欢写&#xff0c;候选人也喜欢背&#xff0c;似乎已经形成了一个闭环。 但你有没有思考过&#xff0c;分库分表真的适合你的系统吗&am…

分库分表真的适合你的系统吗?聊聊分库分表和NewSQL如何选择

曾几何时&#xff0c;“并发高就分库&#xff0c;数据大就分表”已经成了处理 MySQL 数据增长问题的圣经。 面试官喜欢问&#xff0c;博主喜欢写&#xff0c;候选人也喜欢背&#xff0c;似乎已经形成了一个闭环。 但你有没有思考过&#xff0c;分库分表真的适合你的系统吗&am…

分库分表和 NewSQL 到底怎么选?

文章来源&#xff1a;【公众号&#xff1a;CoderW】 目录 背景分表分库分库分表的成本NewSQLNewSQL 平滑接入方案NewSQL 真的有那么好吗&#xff1f;NewSQL 的应用分库分表和 NewSQL 到底怎么选&#xff1f; 背景 曾几何时&#xff0c;“并发高就分库&#xff0c;数据大就分表”…

软考初级-信息处理技术员

22年下半年也是顺利通过了软考初级-信息处理技术员&#xff0c;明年再报一次软设&#xff0c;今年上半年软设下午题没过&#xff0c;总结还是代码敲的少&#xff0c;想的太多hh&#xff0c;下面来看看我总结的上午题考点&#xff0c;非常感谢我好友老郑教我指点了我excel的函数…