# 一、多项式的两种表示方法

$A(x)=\sum _{i=0}^n a_ix^i$

# 二、单位根

1.折半引理

$w_{2n}^{2k}=w_n^k$

2.消去引理

$w_n^{k+\frac{n}{2}}=-w_n^k$

3.（不知道叫什么的性质）其中$k$是整数

$w_n^{a+kn}=w_n^a$

# 三、离散傅里叶变换（DFT）

DFT把多项式从系数表示法转换到点值表示法。

$A_1(x)=\sum_{i=0}^{\frac{n-1}{2}}a_{2i}·x^i$

$A_2(x)=\sum_{i=0}^{\frac{n-1}{2}}a_{2i+1}·x^i$

$A(x)=A_1(x^2)+x·A_2(x^2)$

$w_n^k$代入，得：

$A(w_n^k)=A_1(w_n^{2k})+w_n^k·A_2(w_n^{2k})$

$A(w_n^k)=A_1(w_{\frac{n}{2}}^k)+w_n^k·A_2(w_{\frac{n}{2}}^k)$

$w_n^a=-w_n^k$

$w_{\frac{n}{2}}^a=w_{\frac{n}{2}}^k$

$A(w_n^k)=A_1(w_{\frac{n}{2}}^a)-w_n^a·A_2(w_{\frac{n}{2}}^a)$

# 四、离散傅里叶反变换（IDFT）

$w_n^k(0\leq k<n)$代入多项式$A(x)$后得到的点值为$b_k$，令多项式$B(x)$

$B(x)=\sum_{i=0}^{n-1}b_ix^i$

\begin{aligned} c_k&=\sum_{i=0}^{n-1}b_i·w_n^{-ik}\\ &=\sum_{i=0}^{n-1}\sum_{j=0}^{n-1}a_j·w_n^{ij}·w_n^{-ik}\\ &=\sum_{j=0}^{n-1}a_j\sum_{i=0}^{n-1}w_n^{i(j-k)} \end{aligned}

$j=k$$w_n^0=1$，所以上式的值是$n$

const int N = (1e6 + 10) * 4;
const double PI = 3.141592653589793238462643383279502884197169399375105820974944;
struct cpx
{
double a, b;
cpx(){}
cpx(const double x, const double y = 0)
: a(x), b(y){}
cpx operator + (const cpx &c) const
{
return (cpx){a + c.a, b + c.b};
}
cpx operator - (const cpx &c) const
{
return (cpx){a - c.a, b - c.b};
}
cpx operator * (const cpx &c) const
{
return (cpx){a * c.a - b * c.b, a * c.b + b * c.a};
}
};
int n, m;
cpx a[N], b[N], buf[N];
inline cpx omega(const int n, const int k)
{
return (cpx){cos(2 * PI * k / n), sin(2 * PI * k / n)};
}
void FFT(cpx *a, const int n, const bool inv)
{
if (n == 1)
return;
static cpx buf[N];
int mid = n >> 1;
for (int i = 0; i < mid; i++)
{
buf[i] = a[i << 1];
buf[i + mid] = a[i << 1 | 1];
}
memcpy(a, buf, sizeof(cpx[n]));
//now a[i] is coefficient
FFT(a, mid, inv), FFT(a + mid, mid, inv);
//now a[i] is point value
//a[i] is A1(w_n^i), a[i + mid] is A2(w_n^i)
for (int i = 0; i < mid; i++)
{//calculate point value of A(w_n^i) and A(w_n^{i+n/2})
cpx x = omega(n, i * (inv ? -1 : 1));
buf[i] = a[i] + x * a[i + mid];
buf[i + mid] = a[i] - x * a[i + mid];
}
memcpy(a, buf, sizeof(cpx[n]));
}
int work()
{
for (int i = 0; i <= n; i++)
{
int tmp;
a[i] = tmp;
}
for (int i = 0; i <= m; i++)
{
int tmp;
b[i] = tmp;
}
for (m += n, n = 1; n <= m; n <<= 1);
FFT(a, n, false), FFT(b, n, false);
for (int i = 0; i < n; i++)
a[i] = a[i] * b[i];
FFT(a, n, true);
for (int i = 0; i <= m; i++)
write((int)((a[i].a / n) + 0.5)), putchar(' ');
return 0;
}

# 五、优化

rev[i] = rev[i >> 1] >> 1 | ((i & 1) << (lg2 - 1))

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

namespace zyt
{
template<typename T>
inline void read(T &x)
{
char c;
bool f = false;
x = 0;
do
c = getchar();
while (c != '-' && !isdigit(c));
if (c == '-')
f = true, c = getchar();
do
x = x * 10 + c - '0', c = getchar();
while (isdigit(c));
if (f)
x = -x;
}
inline void read(char &c)
{
do
c = getchar();
while (!isgraph(c));
}
template<typename T>
inline void write(T x)
{
static char buf[20];
char *pos = buf;
if (x < 0)
putchar('-'), x = -x;
do
*pos++ = x % 10 + '0';
while (x /= 10);
while (pos > buf)
putchar(*--pos);
}
const int N = (1 << 17) + 11;
const double PI = acos(-1.0L);
struct cpx
{
double a, b;
cpx(const double x = 0, const double y = 0)
:a(x), b(y) {}
cpx operator + (const cpx &c) const
{
return (cpx){a + c.a, b + c.b};
}
cpx operator - (const cpx &c) const
{
return (cpx){a - c.a, b - c.b};
}
cpx operator * (const cpx &c) const
{
return (cpx){a * c.a - b * c.b, a * c.b + b * c.a};
}
cpx conj() const
{
return (cpx){a, -b};
}
~cpx(){}
}omega[N], inv[N];
int rev[N];
void FFT(cpx *a, const int n, const cpx *w)
{
for (int i = 0; i < n; i++)
if (i < rev[i])
swap(a[i], a[rev[i]]);
for (int len = 1; len < n; len <<= 1)
for (int i = 0; i < n; i += (len << 1))
for (int k = 0; k < len; k++)
{
cpx tmp = a[i + k] - w[k * (n / (len << 1))] * a[i + len + k];
a[i + k] = a[i + k] + w[k * (n / (len << 1))] * a[i + len + k];
a[i + len + k] = tmp;
}
}
void init(const int lg2)
{
for (int i = 0; i < (1 << lg2); i++)
{
rev[i] = rev[i >> 1] >> 1 | (i & 1) << (lg2 - 1);
omega[i] = (cpx){cos(2 * PI * i / (1 << lg2)), sin(2 * PI * i / (1 << lg2))};
inv[i] = omega[i].conj();
}
}
int work()
{
int n;
static cpx a[N], b[N];
for (int i = 0; i < n; i++)
{
char c;
a[i] = c - '0';
}
for (int i = 0; i < n; i++)
{
char c;
b[i] = c - '0';
}
for (int i = 0; (i << 1) < n; i++)
swap(a[i], a[n - i - 1]), swap(b[i], b[n - i - 1]);
int lg2 = 0, tmp = n << 1;
for (n = 1; n < tmp; ++lg2, n <<= 1);
init(lg2);
FFT(a, n, omega), FFT(b, n, omega);
for (int i = 0; i < n; i++)
a[i] = a[i] * b[i];
FFT(a, n, inv);
bool st = false;
static int ans[N];
for (int i = 0; i < n; i++, n += (ans[n]))
{
ans[i] += (int)(a[i].a / n + 0.5);
ans[i + 1] += ans[i] / 10;
ans[i] %= 10;
}
for (int i = n - 1; i >= 0; i--)
if (st || ans[i])
write(ans[i]), st = true;
return 0;
}
}
int main()
{
return zyt::work();
}
posted @ 2018-11-14 23:54 Inspector_Javert 阅读(...) 评论(...) 编辑 收藏