【bzoj2179】FFT快速傅里叶变换(优化高精度乘法)

#include<bits/stdc++.h>
using namespace std;
#define pi acos(-1)
typedef complex<double> C;
const int N=201100;
int n,m,l,r[N],ans[N];
C a[N],b[N];
char s[N],t[N];
void fft(C *a,int f){
    for(int i=0;i<n;++i) if(r[i]>i) swap(a[i],a[r[i]]);//分配正确的顺序
    for(int i=1;i<n;i<<=1){//此时i枚举的是当前层小区间的长度
        C wn(cos(pi/i),f*sin(pi/i));//由于需要大区间的单位根,所以2*pi/2*i,消去2
        for(int j=0;j<n;j+=i<<1){ //j是你合并形成的每个区间的左端点
            C w=1;
            for(int k=0;k<i;k++,w*=wn){//在小区间内枚举复数,一次合并两个小区间
                C x=a[j+k],y=w*a[j+k+i];//蝴蝶变换
                a[j+k]=x+y;a[j+k+i]=x-y;
            }
        }
    }
}
int main(){
    scanf("%d%s%s",&m,s,t);
    for(int i=0;i<m;++i) a[i]=s[m-i-1]-‘0‘;
    for(int i=0;i<m;++i) b[i]=t[m-i-1]-‘0‘;
    for(n=1,m<<=1;n<m;n<<=1) l++;
    for(int i=0;i<n;++i) r[i]=((r[i>>1]>>1)|((i&1)<<(l-1)));//i到i*2要<<1,则r[i]到r[i*2]就要>>1,由于是从r[i]推到r[i*2],i*2第最低位的信息会缺失,所以要|((i&1)<<(l-1))
    fft(a,1),fft(b,1);//通过离散傅里叶变换(把n个复数带入多项式,得到点值表示)求出a,b的点值表示
    for(int i=0;i<n;++i) a[i]*=b[i];//新的多项式的点至表示就是g(x){(x0,a(x0)*b(x0)));(x1,a(x1)*b(x1));...(xn-1,a(xn-1)*b(xn-1))}
    fft(a,-1);//把前面的点值表示作为新多项式的系数,并把新多项式转化成系数表示法
    for(int i=0;i<n;++i) a[i]/=n;
    for(int i=0;i<m;++i) ans[i]=(int)(a[i].real()+0.1);
    for(int i=0;i<m;++i){
        if(ans[i]>=10){
            ans[i+1]+=ans[i]/10;ans[i]%=10;
        }else if(!ans[i]&&i==m-1) m--;
    }
    while(!ans[m-1]&&m>0) m--;
    for(int i=m-1;i>=0;--i) printf("%d",ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/kgxw0430/p/10296154.html

时间: 2024-10-11 07:02:50

【bzoj2179】FFT快速傅里叶变换(优化高精度乘法)的相关文章

准零基础搞懂FFT快速傅里叶变换及其实现程序(二)

上一篇文章我们了解了DFT的原理,FFT是基于DFT的更适合计算机运算的算法,本文我们就正式开始学习FFT的原理. 首先我么先来宏观的看一下FFT.如果我们把整个FFT的算法看成一个黑盒子的话,那么它的输入就是时间波形信号,比如声音波形(横轴为时间,纵轴为振幅).外什么FFT要比DFT速度更快呢?下面(图1)解释了FFT和DFT的(对于计算机的)算法复杂度 图1 从上面的数学表达式可以看出,一个1024采样点的FFT比DFT块了102.4倍.如果傅里叶变换的数量级更大,FFT的速度优势会更明显.

FFT快速傅里叶变换

摘自:https://www.cnblogs.com/RabbitHu/p/FFT.html 快速傅里叶变换(FFT)是一种能在O(nlogn)O(nlog?n)的时间内将一个多项式转换成它的点值表示的算法. 点值表示:设A(x)是一个n−1次多项式,那么把n个不同的x代入,会得到n个y.这n对(x,y)唯一确定了该多项.由多项式可以求出其点值表示,而由点值表示也可以求出多项式. 设有两个n−1次多项式A(x)和B(x)),我们的目标是——把它们乘起来.普通的多项式乘法是O(n^2),但有趣的是

FFT —— 快速傅里叶变换

问题: 已知A[], B[], 求C[],使: 定义C是A,B的卷积,例如多项式乘法等. 朴素做法是按照定义枚举i和j,但这样时间复杂度是O(n2). 能不能使时间复杂度降下来呢? 点值表示法: 我们把A,B,C看作表达式. 即: A(x)=a0 + a1* x + a2 * x2 +... 将A={(x1,A(x1)), (x2,A(x2)), (x3,A(x3))...}叫做A的点值表示法. 那么使用点值表示法做多项式乘法就很简单了:对应项相乘. 那么,如何将A和B转换成点值表示法,再将C转

【Delphi】如何在三轴加速器的频谱分析中使用FFT(快速傅里叶变换)算法

关于傅里叶变换的作用,网上说的太过学术化,且都在说原理,已经如何编码实现,可能很多人有个模糊影响,在人工智能,图像识别,运动分析,机器学习等中,频谱分析成为了必备的手段,可将离散信号量转换为数字信息进行归类分析. 今天这里将的不是如何实现,而是如何使用傅里叶变换 但频谱分析中,涉及到的信号处理知识对大部分软件开发的人来说,太过于晦涩难懂,傅里叶变换,拉普拉斯,卷积,模相,实数,虚数,复数,三角函数等等,已经能让软件工程师望而却步,造成懂知识的人无法开发,懂开发的人无法分析,而同时具备两种技能的人

浅谈FFT(快速傅里叶变换)

本文主要简单写写自己学习FFT的经历以及一些自己的理解和想法. FFT的介绍以及入门就不赘述了,网上有许多相关的资料,入门的话推荐这篇博客:FFT(最详细最通俗的入门手册),里面介绍得很详细. 为什么要学习FFT呢?因为FFT能将多项式乘法的时间复杂度由朴素的$O(n^2)$降到$O(nlogn)$,这相当于能将任意形如$f[k]=\sum\limits _{i+j=k}f[i]*f[j]$的转移方程的计算在$O(nlogn)$的时间内完成.因此对于想要进阶dp的同学来说,FFT是必须掌握的技能

Bzoj2179 FFT快速傅立叶

Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 3079  Solved: 1581 Description 给出两个n位10进制整数x和y,你需要计算x*y. Input 第一行一个正整数n. 第二行描述一个位数为n的正整数x. 第三行描述一个位数为n的正整数y. Output 输出一行,即x*y的结果. Sample Input 1 3 4 Sample Output 12 数据范围: n<=60000 HINT Source FFT FFT真

【模板】FFT快速傅里叶变换

1 struct Complex{ 2 double x, y; 3 inline Complex(double xx=0, double yy=0){ 4 x=xx; y=yy; 5 } 6 inline Complex operator + (Complex a){ 7 return Complex(x+a.x, y+a.y); 8 } 9 inline Complex operator - (Complex a){ 10 return Complex(x-a.x, y-a.y); 11 }

FFT 快速傅里叶变换

这个东西很神奇,看了半天网上的解释和课件,研究了很长时间,算是大概明白了它的原理. 话不多说先上图. 我们要求的h(x)=f(x)*g(x),f(x)=Σai*x^i,g(x)=Σbi*x^i. 朴素求复杂度是n2的,但一个x次多项式在平面上可以由x+1个点唯一插值表示,所以我们可以先用求出x+1个点(xi,f(xi))和(xi,g(xi)),再求出(xi,f(xi)*g(xi)),就可以反解出    h(x)的表达式. 那么我们需要在nlogn的时间内干完这两步,首先xi的取值需要特殊取,令x

BZOJ 2179 FFT快速傅立叶 ——FFT

[题目分析] 快速傅里叶变换用于高精度乘法. 其实本质就是循环卷积的计算,也就是多项式的乘法. 两次蝴蝶变换. 二进制取反化递归为迭代. 单位根的巧妙取值,是的复杂度成为了nlogn 范德蒙矩阵计算逆矩阵又减轻了拉格朗日插值法的复杂度. 十分神奇. [代码] #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <set> #includ