51nod 1028 大数乘法 V2 【FFT模板题】

题目链接

模板题。。

#include<bits/stdc++.h>
using namespace std;
typedef int LL;
typedef double db;
namespace FFT //使用前需要用 fft_init()函数 初始化 { const int FFT_MAXN=1<<18; const db pi=3.14159265358979323846264338327950288L; struct cp { db a,b; cp(double a_=0,double b_=0) { a=a_,b=b_; } cp operator +(const cp&rhs)const { return cp(a+rhs.a,b+rhs.b); } cp operator -(const cp&rhs)const { return cp(a-rhs.a,b-rhs.b); } cp operator *(const cp&rhs)const { return cp(a*rhs.a-b*rhs.b,a*rhs.b+b*rhs.a); } cp operator !()const { return cp(a,-b); } }nw[FFT_MAXN+1],f[FFT_MAXN],g[FFT_MAXN],t[FFT_MAXN]; //a<->f,b<->g,t<->c int bitrev[FFT_MAXN]; void fft_init() //初始化 nw[],bitrev[] { int L=0;while((1<<L)!=FFT_MAXN) L++; for(int i=1;i<FFT_MAXN;i++) bitrev[i]=bitrev[i>>1]>>1|((i&1)<<(L-1)); for(int i=0;i<=FFT_MAXN;i++) nw[i]=cp((db)cosl(2*pi/FFT_MAXN*i),(db)sinl(2*pi/FFT_MAXN*i)); } // n已保证是2的整数次幂 // flag=1:DFT | flag=-1: IDFT void dft(cp *a,int n,int flag=1) { int d=0;while((1<<d)*n!=FFT_MAXN) d++; for(int i=0;i<n;i++) if(i<(bitrev[i]>>d)) swap(a[i],a[bitrev[i]>>d]); // NOTICE! for(int l=2;l<=n;l<<=1) { int del=FFT_MAXN/l*flag; // 决定 wn是在复平面是顺时针还是逆时针变化,以及变化间距 for(int i=0;i<n;i+=l) // ????????????????? { cp *le=a+i,*ri=a+i+(l>>1); // ????????????????? cp *w=flag==1? nw:nw+FFT_MAXN; // 确定wn的起点 for(int k=0;k<(l>>1);k++) { cp ne=*ri * *w; *ri=*le-ne,*le=*le+ne; le++,ri++,w+=del; } } } if(flag!=1) for(int i=0;i<n;i++) a[i].a/=n,a[i].b/=n; } // convo(a,n,b,m,c) a[0..n]*b[0..m] -> c[0..n+m] void convo(LL *a,int n,LL *b,int m,LL *c) {//if(n<=100 && m<=100 || min(n,m)<=5) 标程用了直接暴力的方式,或许可以更快 int N=2;while(N<=n+m) N<<=1; // N+1是c扩展后的长度 for(int i=0;i<N;i++) // 扩展 a[],b[] ,存入f[],g[] ,以0填充新空间 { f[i]=cp((db)(i<=n? a[i]:0),0); g[i]=cp((db)(i<=m? b[i]:0),0); } dft(f,N),dft(g,N); for(int i=0;i<N;i++) // 频域求积 t[i]=f[i]*g[i]; dft(t,N,-1); for(int i=0;i<=n+m;i++) c[i]=LL(t[i].a+0.5); } } char s1[1<<18|1],s2[1<<18|1],s3[1<<18|1]; LL a[1<<18|1],b[1<<18|1],c[1<<18|1]; int main() { FFT::fft_init(); while(~scanf("%s%s",s1,s2)) { memset(s3,0,sizeof(s3)); int n=strlen(s1)-1,m=strlen(s2)-1; for(int i=0;i<=n;i++) a[i]=s1[i]-'0'; for(int i=0;i<=m;i++) b[i]=s2[i]-'0'; FFT::convo(a,n,b,m,c); c[n+m+1]=0; for(int i=0;i<n+m-i;i++) swap(c[i],c[n+m-i]); for(int i=0;i<=n+m;i++) { c[i+1]+=c[i]/10; c[i]%=10; } int len=n+m+1; while(c[len]==0&&len>0) len--; for(int i=len;i>=0;i--) s3[len-i]=c[i]+'0'; s3[len+1]=0; puts(s3); } }

 

转载于:https://www.cnblogs.com/Just--Do--It/p/7347193.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值