FFT学习参考这两篇博客,很详细,结合这看,互补。

博客一

博客二

 

很大一部分题目需要构造多项式相乘来进行计数问题。

 把A和B分别当作多项式的系数。

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;

const double PI = acos(-1.0);
const int maxn = 5e4+50;
struct Complex
{
    double real,image; ///实部和虚部
    Complex(double _real,double _image)
    {
        real = _real;
        image = _image;
    }
    Complex(){}
};

Complex operator + (const Complex &c1,const Complex &c2)
{
    return Complex(c1.real+c2.real,c1.image+c2.image);
}

Complex operator - (const Complex &c1,const Complex &c2)
{
    return Complex(c1.real-c2.real,c1.image-c2.image);
}

Complex operator * (const Complex &c1,const Complex &c2)
{
    return Complex(c1.real*c2.real-c1.image*c2.image, c1.real*c2.image + c1.image * c2.real);
}

int rev(int id,int len)
{
    int ret = 0;
    for(int i=0;(1<<i)<len;i++)
    {
        ret <<= 1;
        if(id & (1<<i)) ret |= 1;
    }
    return ret;
}
Complex A[135000];
void FFT(Complex* a,int len,int DFT) ///对a进行DFT或者逆DFT,结果存在a当中
{
    for(int i = 0; i < len; i++)
        A[rev(i,len)] = a[i]; ///按其在叶子节点中的顺序存储
    for(int s = 1; (1 << s)<= len; s++)
    {
        int m = (1 << s);
        Complex wm = Complex(cos(DFT*2*PI/m),sin(DFT*2*PI/m)); ///主n次单位根
        for(int k = 0; k < len; k += m)
        {
            Complex w = Complex(1, 0); ///旋转因子
            for(int j = 0; j < (m >> 1); j++)
            {
                Complex t = w * A[k + j + (m >> 1)];
                Complex u = A[k + j];
                A[k + j] = u + t;
                A[k + j + (m >> 1)] = u - t;
                w = w * wm;
            }
        }
    }
    if(DFT == -1) for(int i = 0; i < len; i++) A[i].real /= len, A[i].image /= len;
    for(int i = 0; i < len; i++) a[i] = A[i];
    return;
}
char coA[maxn],coB[maxn];
///把每一位作为系数

///乘积后次数最大为2 * n - 2,转换成2的k次幂,(1<<16)<2*n-2<(1<<17)
Complex a[135000],b[135000];
int ans[135000];

int main()
{
    while(scanf("%s",coA)!=EOF)
    {
        int lenA = strlen(coA);
        int mia = 0;
        while((1<<mia)<lenA) mia++; ///2^mia>=lenA
        scanf("%s",coB);
        int lenB = strlen(coB);
        int mib = 0;
        while((1<<mib)<lenB) mib++;
        int len(1<<(max(mia,mib)+1));
        for(int i=0;i<len;i++)
        {
            if(i<lenA) a[i] = Complex(coA[lenA-i-1]-'0',0); ///表示系数,A数组从左往右存了进去 2000 --> 0002
            else a[i] = Complex(0,0);
            if(i<lenB) b[i] = Complex(coB[lenB-i-1]-'0',0);
            else b[i] = Complex(0,0);
        }
        ///求A和B的点值表达式
        FFT(a, len, 1);
        FFT(b, len, 1);
        for(int i = 0; i < len; i++)
            a[i] = a[i] * b[i]; ///求C的点值
        FFT(a, len, -1); ///逆DFT得到系数
        for(int i = 0; i < len; i++)
            ans[i] = (int)(a[i].real + 0.5); ///四舍五入
        for(int i = 0; i <len - 1; i++)
        {
            ans[i + 1] += ans[i] / 10;
            ans[i] %= 10;
        }
        bool flag = 0;
        for(int i = len - 1; i >= 0; i--) ///防止出现前导0
        {
            if(ans[i]) printf("%d",ans[i]), flag = 1;
            else if(flag || i == 0) printf("0");
        }
        puts("");
    }
    return 0;
}
Code

相关文章:

  • 2021-07-21
  • 2022-12-23
  • 2021-11-23
  • 2022-02-21
  • 2022-12-23
  • 2021-09-03
猜你喜欢
  • 2021-10-24
  • 2022-12-23
  • 2021-09-20
  • 2021-08-14
  • 2021-07-22
  • 2022-12-23
  • 2021-09-08
相关资源
相似解决方案