HDU 1402. A * B Problem Plus(FFT)

递归版本的FFT还是好写…
输出结果时,注意特殊情况0*0=0

#include <iostream>
#include <cstdio>
#include <complex>
#include <cstring>
#include <cmath>

using namespace std;

typedef complex<double> Comp;

const Comp I(0, 1);
const int MAX_N = 50000 + 10;
#ifndef M_PI
  #define M_PI 3.14159265358979323846
#endif

Comp tmp[1 << 17];
void DFT(Comp* a, int n, int rev) {
  if (n == 1) return;
  for (int i = 0; i < n; i++) {
    tmp[i] = a[i];
  }
  for (int i = 0; i < n; i++) {
    if (i & 1)
      a[n / 2 + i / 2] = tmp[i];
    else
      a[i / 2] = tmp[i];
  }
  Comp *a0 = a, *a1 = a + n / 2;
  DFT(a0, n / 2, rev);
  DFT(a1, n / 2, rev);

  Comp cur(1, 0);
  double alpha = 2 * M_PI / n * rev;
  Comp step = exp(I * alpha);
  for (int k = 0; k < n / 2; k++) {
    tmp[k] = a0[k] + cur * a1[k];
    tmp[k + n / 2] = a0[k] - cur * a1[k];
    cur *= step;
  }

  for (int i = 0; i < n; i++) {
    a[i] = tmp[i];
  }
}

char A[MAX_N], B[MAX_N];
Comp a[1 << 17] = { }, b[1 << 17] = { };
int res[1 << 17];

int main() {
  while (scanf("%s %s", A, B) != EOF) {
    int lA = strlen(A), lB = strlen(B);
    int n = 1;
    while (n < lA + lB) n <<= 1;
    for (int i = 0; i < n; i++) {
      a[i] = 0;
      b[i] = 0;
    }
    for (int i = 0; i < lA; i++) {
      a[i] = A[lA - 1 - i] - '0';
    }
    for (int i = 0; i < lB; i++) {
      b[i] = B[lB - 1 - i] - '0';
    }
    // FFT
    DFT(a, n, 1);
    DFT(b, n, 1);
    for (int i = 0; i < n; i++) {
      a[i] *= b[i];
    }
    DFT(a, n, -1);
    for (int i = 0; i < n; i++) {
      a[i] /= n;
    }
    // res processing
    memset(res, 0, sizeof(res));
    for (int i = 0; i + 1 < n; i++) {
      res[i] += int(a[i].real() + 0.5);
      res[i + 1] = res[i] / 10;
      res[i] %= 10;
    }
    int k = n - 1;
    while (res[k] == 0) k--;
    if (k < 0) {
      printf("0");
    } else {
      while (k >= 0) printf("%d", res[k--]);
    }
    printf("\n");
  }

  return 0;
}

Reference:http://blog.miskcoo.com/2015/04/polynomial-multiplication-and-fast-fourier-transform#i-12

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值