●UOJ 34 多项式乘法

题链:

http://uoj.ac/problem/34

题解:

FFT入门题。

(终于接触到迷一样的FFT了)

初学者在对复数和单位根有简单了解的基础上,可以直接看《再探快速傅里叶变换》(毛啸)

(主要用于求两个序列的卷积)

代码:

递归版:

#include<bits/stdc++.h>
#define MAXN 300000
using namespace std;
const double Pi=acos(-1);
struct Z{
	double real,image;
	Z(double _real=0,double _image=0):real(_real),image(_image){}
	Z operator - ()const {return Z(-real,-image);}
	friend Z operator + (const Z &A,const Z &B){return Z(A.real+B.real,A.image+B.image);};
	friend Z operator - (const Z &A,const Z &B){return A+(-B);}
	friend Z operator * (const Z &A,const Z &B){return Z(A.real*B.real-A.image*B.image,A.image*B.real+A.real*B.image);}
};
void FFT(int n,Z *Y,int sn){
	if(n==1) return;
	Z L[n>>1],R[n>>1];
	for(int k=0;k<n;k+=2)
		L[k>>1]=Y[k],R[k>>1]=Y[k+1];
	FFT(n/2,L,sn); FFT(n/2,R,sn);
	Z dw=Z(cos(2*Pi/n),sin(sn*2*Pi/n)),w=Z(1,0),tmp;
	for(int k=0;k<n/2;k++,w=w*dw)
		tmp=w*R[k],Y[k]=L[k]+tmp,Y[k+n/2]=L[k]-tmp;
}
int main(){
	static Z A[MAXN],B[MAXN];
	int n,m; scanf("%d%d",&n,&m); n++; m++;
	for(int i=0,x;i<n;i++) scanf("%d",&x),A[i]=Z(x,0);
	for(int i=0,x;i<m;i++) scanf("%d",&x),B[i]=Z(x,0);
	m=n+m-1; for(n=1;n<m;n<<=1);
	FFT(n,A,1); FFT(n,B,1);
	for(int i=0;i<n;i++) A[i]=A[i]*B[i];
	FFT(n,A,-1);
	for(int i=0;i<m;i++) printf("%d ",(int)(A[i].real/n+0.5));
	return 0;
}

  

非递归版:

#include<bits/stdc++.h>
#define MAXN 300000
using namespace std;
const double Pi=acos(-1);
struct Z{
	double real,image;
	Z(double _real=0,double _image=0):real(_real),image(_image){}
	Z operator - ()const {return Z(-real,-image);}
	friend Z operator + (const Z &A,const Z &B){return Z(A.real+B.real,A.image+B.image);};
	friend Z operator - (const Z &A,const Z &B){return A+(-B);}
	friend Z operator * (const Z &A,const Z &B){return Z(A.real*B.real-A.image*B.image,A.image*B.real+A.real*B.image);}
};
int order[MAXN];
void FFT(int n,Z *Y,int sn){
	for(int i=0;i<n;i++) if(i<order[i]) swap(Y[i],Y[order[i]]);
	for(int d=2;d<=n;d<<=1){
		Z dw=Z(cos(2*Pi/d),sin(sn*2*Pi/d)),w,tmp;
		for(int i=0;w=Z(1,0),i<n;i+=d)
			for(int k=i;k<i+d/2;k++,w=w*dw)
				tmp=w*Y[k+d/2],Y[k+d/2]=Y[k]-tmp,Y[k]=Y[k]+tmp;
	}
}
int main(){
	static Z A[MAXN],B[MAXN];
	int n,m,len; scanf("%d%d",&n,&m); n++; m++;
	for(int i=0,x;i<n;i++) scanf("%d",&x),A[i]=Z(x,0);
	for(int i=0,x;i<m;i++) scanf("%d",&x),B[i]=Z(x,0);
	m=n+m-1; for(len=0,n=1;n<m;n<<=1) len++;
	for(int i=1;i<n;i++) order[i]=(order[i>>1]>>1)|((i&1)<<(len-1));
	FFT(n,A,1); FFT(n,B,1);
	for(int i=0;i<n;i++) A[i]=A[i]*B[i];
	FFT(n,A,-1);
	for(int i=0;i<m;i++) printf("%d ",(int)(A[i].real/n+0.5));
	return 0;
}

  

原文地址:https://www.cnblogs.com/zj75211/p/8341072.html

时间: 2024-10-08 01:29:13

●UOJ 34 多项式乘法的相关文章

UOJ #34 多项式乘法

题目链接:多项式乘法 保存一发FFT与NTT板子. 学习链接:从多项式乘法到快速傅里叶变换 FFT NTT 注意差值回来的时候不取反也是可以的,只不过需要把数组\(reverse\)一下(根据单位复数根的性质应该不难理解) 代码(FFT): #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<co

UOJ #34 多项式乘法 FFT快速傅立叶变换

题目大意:这是一道模板题. CODE: #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 1000010 using namespace std; const double PI = acos(-1.0); struct Complex{ double x,y; Complex(dou

[UOJ 0034] 多项式乘法

#34. 多项式乘法 统计 描述 提交 自定义测试 这是一道模板题. 给你两个多项式,请输出乘起来后的多项式. 输入格式 第一行两个整数 nn 和 mm,分别表示两个多项式的次数. 第二行 n+1n+1 个整数,分别表示第一个多项式的 00 到 nn 次项前的系数. 第三行 m+1m+1 个整数,分别表示第一个多项式的 00 到 mm 次项前的系数. 输出格式 一行 n+m+1n+m+1 个整数,分别表示乘起来后的多项式的 00 到 n+mn+m 次项前的系数. 样例一 input 1 2 1

UR#34. 多项式乘法

#34. 多项式乘法 统计 描述 提交 自定义测试 这是一道模板题. 给你两个多项式,请输出乘起来后的多项式. 输入格式 第一行两个整数 nn 和 mm,分别表示两个多项式的次数. 第二行 n+1n+1 个整数,分别表示第一个多项式的 00 到 nn 次项前的系数. 第三行 m+1m+1 个整数,分别表示第一个多项式的 00 到 mm 次项前的系数. 输出格式 一行 n+m+1n+m+1 个整数,分别表示乘起来后的多项式的 00 到 n+mn+m 次项前的系数. 样例一 input 1 2 1

【UOJ】【34】多项式乘法

快速傅里叶变换模板题 算法理解请看<算法导论>第30章<多项式与快速傅里叶变换>,至于证明插值唯一性什么的看不懂也没关系啦-只要明白这个过程是怎么算的就ok. 递归版:(4252ms  23468kb) 1 //UOJ 34 递归版 2 #include<cmath> 3 #include<vector> 4 #include<cstdio> 5 #include<cstring> 6 #include<cstdlib>

[uoj#34] [洛谷P3803] 多项式乘法(FFT)

新技能--FFT. 可在 \(O(nlogn)\) 时间内完成多项式在系数表达与点值表达之间的转换. 其中最关键的一点便为单位复数根,有神奇的折半性质. 多项式乘法(即为卷积)的常见形式: \[ C_n=\sum\limits_{i=0}^n A_iB_{n-i} \] 基本思路为先将系数表达 -> 点值表达 \(O(nlogn)\) 随后点值 \(O(n)\) 进行乘法运算 最后将点值表达 -> 系数表达 \(O(nlogn)\) 代码 #include<cstdio> #inc

求幂运算、多项式乘法及Horner法则的应用

一,两种不同的求幂运算 求解x^n(x 的 n 次方) ①使用递归,代码如下: 1 private static long pow(int x, int n){ 2 if(n == 0) 3 return 1; 4 if(n == 1) 5 return x; 6 if(n % 2 == 0) 7 return pow(x * x, n / 2); 8 else 9 return pow(x * x, n / 2) * x; 10 } 分析: 每次递归,使得问题的规模减半.2到6行操作的复杂度为

多项式乘法快速算法

多项式乘法优化算法: 设有如下两个多项式: 把它们的系数分别做成向量X=[x0,x1,x2,x3,......]的形式,得 F=[2,3,1] G=[5,2,0] 那么根据卷积公式 可以求得向量F和G的卷积S=[10,19,11,2] 而由多项式乘法可算出 各项系数和上面的卷积结果正好一一对应. 所以说,多项式相乘,相当于系数向量的卷积. 再仔细观察一下这个多项式:每个系数正好对应的就是频域 Reference: http://www.cnblogs.com/bigcat/archive/200

poj 3046 Ant Counting 多项式乘法解可重组合数

题意: 裸的求可重组合数. 分析: 多项式乘法求系数的应用啊,不用dp. 代码: //poj 3046 //sep9 #include <iostream> using namespace std; const int maxN=1024; const int maxL=100024; const int mod=1000000; int num[maxN]; int coef[maxL]; int tmp[maxL]; int l1; void mul(int l2) { for(int i