bzoj2194 快速傅立叶之二

2194: 快速傅立叶之二

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 1730  Solved: 1026
[Submit][Status][Discuss]

5
3 1
2 4
1 1
2 4
1 4

Sample Output

24
12
10
6
1

一般而言，能用FFT求的式子c[k] = a[i] * b[j], i + j是一个只与k有关的式子，其它的都是常数项.  对于这道题，把bi变成b_n-i-1

最后c数组的值要整体向后移k位.
#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = (1 << 18) + 5;
const double pai = acos(-1.0);
int n,a[maxn],b[maxn],len;

struct node
{
double real, imag;
node(double real = 0.0, double imag = 0.0)
{
this->real = real, this->imag = imag;
}
node operator - (const node&elem) const
{
return node(this->real - elem.real, this->imag - elem.imag);
}
node operator + (const node&elem) const
{
return node(this->real + elem.real, this->imag + elem.imag);
}
node operator * (const node&elem) const
{
return node(this->real * elem.real - this->imag * elem.imag, this->real * elem.imag + this->imag * elem.real);
}
void set(double real = 0.0, double imag = 0.0)
{
this->real = real, this->imag = imag;
}
} A[maxn],B[maxn];

void pre()
{
for (int i = 0; i < n; i++)
scanf("%d%d",&a[i],&b[i]);
len = 1;
while (len < (n << 1))
len <<= 1;
for (int i = 0; i < n; i++)
A[i].set(a[i],0),B[i].set(b[n - i - 1],0);
for (int i = n; i < len; i++)
A[i].set(),B[i].set();
}

void Swap(node &a,node &b)
{
node temp = a;
a = b;
b = temp;
}

void zhuan(node *y)
{
for (int i = 1,j = len >> 1,k; i < len - 1; i++)
{
if (i < j)
Swap(y[i],y[j]);
k = len >> 1;
while (j >= k)
{
j -= k;
k >>= 1;
}
if (j < k)
j += k;
}
}

void FFT(node *y,int op)
{
zhuan(y);
for (int h = 2; h <= len; h <<= 1)
{
node temp(cos(op * pai * 2 / h),sin(op * pai * 2 / h));
for (int i = 0; i < len; i += h)
{
node W(1,0);
for (int j = i; j < i + h / 2; j++)
{
node u = y[j];
node v = W * y[j + h / 2];
y[j] = u + v;
y[j + h / 2] = u - v;
W = W * temp;
}
}
}
if (op == -1)
for (int i = 0; i < len; i++)
y[i].real /= len;
}

void solve(node *A,node *B)
{
FFT(A,1);
FFT(B,1);
for (int i = 0; i < len; i++)
A[i] = A[i] * B[i];
FFT(A,-1);
}

int main()
{
scanf("%d",&n);
pre();
solve(A,B);
for (int i = n - 1; i < 2 * n - 1; i++)
printf("%d\n",(int)(A[i].real + 0.5));

return 0;
}

posted @ 2018-03-24 16:46  zbtrs  阅读(116)  评论(0编辑  收藏  举报