HDU - 1402 A * B Problem Plus (快速傅里叶变化-FFT)

题目链接

题意:给出一个a和b,长度不超过5e4,输出a*b的结果

题解:直接上一波快速傅里叶变化-FFT即可~

//以下模板为结构体内为快速傅里叶变换模板

//结构体外为借助该模板实现的高精度乘法计算

//以下为多项式相乘(高精度可以看作x=10的多项式相乘)的快速傅里叶变换的使用简述:

//设一个a的正傅里叶变换为DEFa),逆傅里叶变换为IDFTa

//并且有:多项式a和多项式b的多项式相乘的中间结果=IFDFTDFTa*DFTb))

//其中*运算为数组中的对应项进行复数乘法运算

//多项式a和多项式b相乘的结果等于中间结果除以多项式的长度n

//注意所有的数都必须使用浮点数,并且不能太大(浮点数会出现误差)

//注意长度要足够大并且为2的幂,不足长度补0

//高精度乘法还必须将运算结果进行进位

代码如下:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int maxn = 4e5 + 500;
#define PI acos(-1.0)
struct Complex //复数类
{
	double a, b;//b(i)+a
	Complex() {}
	Complex(double aa, double bb) :a(aa), b(bb) {}
	Complex operator +(Complex p)
	{
		double c = p.a, d = p.b;
		return Complex(a + c, b + d);
	}
	Complex operator *(Complex p)
	{
		double c = p.a, d = p.b;
		return Complex(a*c - b*d, b*c + a*d);
	}
	Complex operator -(Complex p)
	{
		double c = p.a, d = p.b;
		return Complex(a - c, b - d);
	}
};
struct FFT
{
	Complex _P[maxn];
	void build(Complex P[], int n, int m, int curr, int &cnt)
	{
		if (m == n) _P[curr] = P[cnt++];
		else
		{
			build(P, n, m * 2, curr, cnt);
			build(P, n, m * 2, curr + m, cnt);
		}
	}
	void solve(Complex P[], int n, int oper)//对数组P做一次快速傅里叶变换
	{                                       //P为待变换的数组,n为长度,oper为1则为正变换,-1为负变换
		int cnt = 0;
		build(P, n, 1, 0, cnt);
		for (int i = 0; i < n; i++)
			P[i] = _P[i];
		for (int d = 0; (1 << d) < n; d++)
		{
			int m = 1 << d;
			int m2 = m * 2;
			double p0 = PI / m*oper;
			Complex unit_p0 = Complex(cos(p0), sin(p0));
			for (int i = 0; i < n; i += m2)
			{
				Complex unit = Complex(1, 0);
				for (int j = 0; j < m; j++)
				{
					Complex &P1 = P[i + j + m];
					Complex &P2 = P[i + j];
					Complex t = unit*P1;
					P1 = P2 - t;
					P2 = P2 + t;
					unit = unit*unit_p0;
				}
			}
		}
	}
}F;
Complex p1[maxn], p2[maxn];
char s1[maxn], s2[maxn];
int main()
{
	while (~scanf("%s%s", s1, s2))
	{
		memset(p1, 0, sizeof(p1));
		memset(p2, 0, sizeof(p2));
		int len1 = strlen(s1), len2 = strlen(s2);
		if (len1 == 1 && s1[0] == '0' || len2 == 1 && s2[0] == '0') //注意0的情况
		{
			cout << 0 << endl; continue;
		}
		for (int i = 0; i < len1; i++)
			p1[i].a = (s1[len1 - i - 1] - '0');
		for (int i = 0; i < len2; i++)
			p2[i].a = (s2[len2 - i - 1] - '0');
		int anslen = 1;   //anslen为给ans留的长度,不足补0
		while (anslen < len1 * 2 || anslen < len2 * 2)
			anslen <<= 1;
		F.solve(p1, anslen, 1);
		F.solve(p2, anslen, 1);
		for (int i = 0; i < anslen; i++)
			p1[i] = p1[i] * p2[i];
		F.solve(p1, anslen, -1);
		int p = 0;
		for (int i = 0; i < anslen; i++)
		{
			p1[i].a /= anslen;
			int d = p1[i].a;
			//避免浮点数转整数的精度误差
			if (d - p1[i].a > 0.5)d--;
			if (p1[i].a - d > 0.5)d++;
			d += p;
			p = d / 10;
			d %= 10;
			p1[i].a = d;
		}
		bool flag = false;
		for (int i = anslen; i >= 0; i--)
		{
			if (p1[i].a >= 0.5)flag = true;
			if (flag)printf("%.0lf", p1[i].a);
		}
		cout << endl;
	}
	return 0;
}





 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值