0% found this document useful (0 votes)
9 views5 pages

FFT

The document contains C++ code implementing the Fast Fourier Transform (FFT) for polynomial multiplication and inversion, along with mathematical concepts related to generating functions and their applications in combinatorial problems. It also discusses methods for calculating logarithms and exponentials of polynomials, as well as Newton's iteration method for polynomial operations. The code includes examples of FFT, polynomial multiplication, and polynomial inversion with modular arithmetic.

Uploaded by

dingtaodtdt
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views5 pages

FFT

The document contains C++ code implementing the Fast Fourier Transform (FFT) for polynomial multiplication and inversion, along with mathematical concepts related to generating functions and their applications in combinatorial problems. It also discusses methods for calculating logarithms and exponentials of polynomials, as well as Newton's iteration method for polynomial operations. The code includes examples of FFT, polynomial multiplication, and polynomial inversion with modular arithmetic.

Uploaded by

dingtaodtdt
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 5

#include<bits/stdc++.

h>

using namespace std;


const int N=100;
const double pi=acos(-1);
struct comp{
double r,i;comp(double _r=0,double _i=0){r=_r;i=_i;}
comp operator+(const comp x){return comp(r+x.r,i+x.i);}
comp operator-(const comp x){return comp(r-x.r,i-x.i);}
comp operator*(const comp x){return comp(r*x.r-i*x.i,r*x.i+i*x.r);}
}A[N], B[N];
void FFT(comp a[],int n,int t){
for(int i=1,j=0;i<n-1;i++){
for(int s=n;j^=s>>=1,~j&s;);
if(i<j)swap(a[i],a[j]);
}
for(int d=0;(1<<d)<n;d++){
int m=1<<d,m2=m<<1;
double o=pi/m*t;comp _w(cos(o),sin(o));
for(int i=0;i<n;i+=m2){
comp w(1,0);
for(int j=0;j<m;j++){
comp &A=a[i+j+m],&B=a[i+j],t=w*A;
A=B-t;B=B+t;w=w*_w;
}
}
}
if(t==-1)for(int i=0;i<n;i++)a[i].r/=n;
}
int a[N],b[N];
comp A[N],B[N];
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
for(int i=0;i<n;i++) scanf("%d",&b[i]);
n*=2;
for(int i=0;i<n;i++) A[i]=comp(a[i],0);
for(int i=0;i<n;i++) B[i]=comp(b[i],0);
FFT(A,n,1);
//FFT(A,n,-1);
FFT(B,n,1);
for(int i=0;i<n;i++) A[i]=A[i]*B[i];
FFT(A,n,-1);
for(int i=0;i<n;i++) a[i]=A[i].a+0.5;
for(int i=0;i<n;i++) printf("%d ",a[i]);
return 0;
}

正整数的有序拆分问题
生成函数 A(x)=x+x^2+...=x/(1-x);
则序列有 B(x)=1+A+A^2+...=1/(1-A),所以 B(x)=1+x/(1-2x)=1+x+2x^2+4x^3+...;
已知多项式 f(x),可以在 O(nlogn)求出 1/f(x)模 x^n 意义下(条件是 f(x)的常数项存在逆元)

已知 f(x),求 ln f(x)
设 g(x)=ln f(x),g'(x)=f'(x)/f(x),则 f(x)=f'(x)/g'(x);
n 个点连通图方案数
n 个点的图的生成函数 G(x)=∑2^c(i,2)x^i/i!;
n 个点连通图生成函数为 C(x)=∑Cix^i/i!;
G(x)=e^C(x),则 C(x)=ln(G(x));
已知 f(x),求 e^f(x) 牛顿迭代法 o(nlogn)
已知 f(x),求 f(x)^k mod x^n,
1.倍增快速幂的方法,O(nlognlogk)
2.f(x)^k=exp(ln(f(x)^k))=exp(kln(f(x))).(注意要将 f(x)常数项为 1,得求出逆元)

自己写的 fft,常数巨大
#include<bits/stdc++.h>

using namespace std;


const double pi=acos(-1.0);
const int N=1e6+5;
int a[N],b[N];
struct comp
{
double a,b;
comp(){}
comp(double _a,double _b):a(_a),b(_b){}
friend comp operator *(const comp &A,const comp &B)
{
return comp(A.a*B.a-A.b*B.b,A.a*B.b+A.b*B.a);
}
friend comp operator +(const comp &A,const comp &B)
{
return comp(A.a+B.a,A.b+B.b);
}
};
comp tmp[N];
comp A[N],B[N];
void FFT(comp *a,int l,int r)
{
if(l==r){
return ;
}
int mid=(l+r)/2;
for(int i=l;i<=r;i++) tmp[i]=a[i];
for(int i=l,j=l;i<=mid;i++,j+=2) a[i]=tmp[j];
for(int i=mid+1,j=l+1;i<=r;i++,j+=2) a[i]=tmp[j];
FFT(a,l,mid);
FFT(a,mid+1,r);
int n=r-l+1;
comp res;
for(int i=l,j=0;i<=mid;i++,j++){
res=comp(cos(2*pi*j/n),sin(2*pi*j/n));
tmp[i]=a[l+j]+a[mid+1+j]*res;
}
for(int i=mid+1,j=0;i<=r;i++,j++){
res=comp(cos(2*pi*(n/2+j)/n),sin(2*pi*(n/2+j)/n));
tmp[i]=a[l+j]+a[i]*res;
}
for(int i=l;i<=r;i++) a[i]=tmp[i];
}
void UFFT(comp *a,int l,int r)
{
if(l==r){
return ;
}
int mid=(l+r)/2;
for(int i=l;i<=r;i++) tmp[i]=a[i];
for(int i=l,j=l;i<=mid;i++,j+=2) a[i]=tmp[j];
for(int i=mid+1,j=l+1;i<=r;i++,j+=2) a[i]=tmp[j];
UFFT(a,l,mid);
UFFT(a,mid+1,r);
int n=r-l+1;
comp res;
for(int i=l,j=0;i<=mid;i++,j++){
res=comp(cos(-2*pi*j/n),sin(-2*pi*j/n));
tmp[i]=a[l+j]+a[mid+1+j]*res;
}
for(int i=mid+1,j=0;i<=r;i++,j++){
res=comp(cos(-2*pi*(n/2+j)/n),sin(-2*pi*(n/2+j)/n));
tmp[i]=a[l+j]+a[i]*res;
}
for(int i=l;i<=r;i++) a[i]=tmp[i];
}
int main()
{
//freopen("2540_3.in","r",stdin);
//freopen("out1.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
for(int i=0;i<m;i++) scanf("%d",&b[i]);
int len=1;
while(len<m+n) len<<=1;
len<<=1;
for(int i=0;i<n;i++) A[i]=comp(a[i],0);
for(int i=0;i<m;i++) B[i]=comp(b[i],0);
FFT(A,0,len-1);
FFT(B,0,len-1);
for(int i=0;i<len;i++) A[i]=A[i]*B[i];
UFFT(A,0,len-1);
for(int i=0;i<n+m-1;i++) a[i]=A[i].a/len+0.5;
for(int i=0;i<n+m-1;i++) printf("%d%s",a[i],i==(n+m-2)?"\n":" ");
return 0;
}
多项式求逆 复杂度 nlogn
#include <cstdio>
#include <complex>
#include <cmath>
#include <algorithm>
#include <iostream>
using std::copy;
using std::fill;

const long long mod_v = 17ll * (1 << 27) + 1;


const int MaxN = 10010;
long long a[MaxN], b[MaxN], c[MaxN];
long long eps[MaxN], inv_eps[MaxN];
int tot;

long long power(long long x, long long p)


{
long long v = 1;
while(p)
{
if(p & 1) v = x * v % mod_v;
x = x * x % mod_v;
p >>= 1;
}

return v;
}

void init_eps(int n)
{
tot = n;
long long base = power(3, (mod_v - 1) / n);
long long inv_base = power(base, mod_v - 2);
eps[0] = 1, inv_eps[0] = 1;
for(int i = 1; i < n; ++i)
{
eps[i] = eps[i - 1] * base % mod_v;
inv_eps[i] = inv_eps[i - 1] * inv_base % mod_v;
}
}

long long inc(long long x, long long d)


{
x += d;
return x >= mod_v ? x - mod_v : x;
}

long long dec(long long x, long long d)


{
x -= d;
return x < 0 ? x + mod_v : x;
}

void transform(int n, long long *x, long long *w)


{
for(int i = 0, j = 0; i != n; ++i)
{
if(i > j) std::swap(x[i], x[j]);
for(int l = n >> 1; (j ^= l) < l; l >>= 1);
}

for(int i = 2; i <= n; i <<= 1)


{
int m = i >> 1;
for(int j = 0; j < n; j += i)
{
for(int k = 0; k != m; ++k)
{
long long z = x[j + m + k] * w[tot / i * k] % mod_v;
x[j + m + k] = dec(x[j + k], z);
x[j + k] = inc(x[j + k], z);
}
}
}
}

void polynomial_inverse(int deg, long long* a, long long* b, long long* tmp)
{
if(deg == 1)
{
b[0] = power(a[0], mod_v - 2);
} else {
polynomial_inverse((deg + 1) >> 1, a, b, tmp);

int p = 1;
while(p < deg << 1) p <<= 1;
copy(a, a + deg, tmp);
fill(tmp + deg, tmp + p, 0);
transform(p, tmp, eps);
transform(p, b, eps);
for(int i = 0; i != p; ++i)
{
b[i] = (2 - tmp[i] * b[i] % mod_v) * b[i] % mod_v;
if(b[i] < 0) b[i] += mod_v;
}
transform(p, b, inv_eps);
long long inv = power(p, mod_v - 2);
for(int i = 0; i != p; ++i)
b[i] = b[i] * inv % mod_v;
fill(b + deg, b + p, 0);

}
}

int main()
{
init_eps(2048);
std::cout<<mod_v<<std::endl;
int n;
std::cin >> n;
for(int i = 0; i != n; ++i)
std::cin >> a[i];
polynomial_inverse(n, a, b, c);
std::cout << "inverse: ";
for(int i = 0; i != n; ++i)
printf("%lld ", (b[i] + mod_v) % mod_v);
std::cout << std::endl;
return 0;
}

You might also like