ACM学习历程—51NOD1028 大数乘法V2(FFT)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1028

题目大意就是求两个大数的乘法。

但是用普通的大数乘法,这个长度的大数肯定不行。

大数可以表示点值表示法,然后卷积乘法就能用FFT加速运算了。

这道题是来存模板的。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <string>
#define LL long long

using namespace std;

//多项式乘法运算
//快速傅里叶变换
//FFT
//用于求两个多项式的卷积,但有精度损失
//时间复杂度nlogn
const int maxN = 400005;
const double PI = acos(-1.0);

struct Complex
{
    double r, i;

    Complex(double rr = 0.0, double ii = 0.0)
    {
        r = rr;
        i = ii;
    }

    Complex operator+(const Complex &x)
    {
        return Complex(r+x.r, i+x.i);
    }

    Complex operator-(const Complex &x)
    {
        return Complex(r-x.r, i-x.i);
    }

    Complex operator*(const Complex &x)
    {
        return Complex(r*x.r-i*x.i, i*x.r+r*x.i);
    }
};

//雷德算法--倒位序
//Rader算法
//进行FFT和IFFT前的反转变换。
//位置i和 (i二进制反转后位置)互换
void Rader(Complex y[], int len)
{
    int j = len>>1;
    for(int i = 1; i < len-1; i++)
    {
        if (i < j) swap(y[i], y[j]);
        int k = len >> 1;
        while (j >= k)
        {
            j -= k;
            k >>= 1;
        }
        if (j < k) j += k;
    }
}

//FFT实现
//len必须为2^k形式,
//on==1时是DFT,on==-1时是IDFT
void FFT(Complex y[], int len, int on)
{
    Rader(y, len);
    for (int h = 2; h <= len; h<<=1)//分治后计算长度为h的DFT
    {
        Complex wn(cos(-on*2*PI/h), sin(-on*2*PI/h)); //单位复根e^(2*PI/m)用欧拉公式展开
        for (int j = 0; j < len; j += h)
        {
            Complex w(1, 0);//旋转因子
            for (int k = j; k < j+h/2; k++)
            {
                Complex u = y[k];
                Complex t = w*y[k+h/2];
                y[k] = u+t;//蝴蝶合并操作
                y[k+h/2] = u-t;
                w = w*wn;//更新旋转因子
            }
        }
    }
    if (on == -1)
        for (int i = 0; i < len; i++)
            y[i].r /= len;
}

//求卷积
void Conv(Complex a[], Complex b[], int ans[], int len)
{
    FFT(a, len, 1);
    FFT(b, len, 1);
    for (int i = 0; i < len; i++)
        a[i] = a[i]*b[i];
    FFT(a, len, -1);
    //精度复原
    for(int i = 0; i < len; i++)
        ans[i] = a[i].r+0.5;
}

//进制恢复
//用于大数乘法
void turn(int ans[], int len, int unit)
{
    for(int i = 0; i < len; i++)
    {
        ans[i+1] += ans[i]/unit;
        ans[i] %= unit;
    }
}

char str1[maxN], str2[maxN];
Complex za[maxN],zb[maxN];
int ans[maxN];
int len;

void init(char str1[], char str2[])
{
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    len = 1;
    while (len < 2*len1 || len < 2*len2) len <<= 1;

    int i;
    for (i = 0; i < len1; i++)
    {
        za[i].r = str1[len1-i-1]-‘0‘;
        za[i].i = 0.0;
    }
    while (i < len)
    {
        za[i].r = za[i].i = 0.0;
        i++;
    }
    for (i = 0; i < len2; i++)
    {
        zb[i].r = str2[len2-i-1]-‘0‘;
        zb[i].i = 0.0;
    }
    while (i < len)
    {
        zb[i].r = zb[i].i = 0.0;
        i++;
    }
}

void work()
{
    Conv(za, zb, ans, len);
    turn(ans, len, 10);
    while (ans[len-1] == 0) len--;
    for (int i = len-1; i >= 0; i--)
        printf("%d", ans[i]);
    printf("\n");
}

int main()
{
    //freopen("test.in", "r", stdin);
    while (scanf("%s%s", str1, str2) != EOF)
    {
        init(str1, str2);
        work();
    }
    return 0;
}

时间: 2024-08-09 21:59:28

ACM学习历程—51NOD1028 大数乘法V2(FFT)的相关文章

ACM学习历程—HDU 4726 Kia&#39;s Calculation( 贪心&amp;&amp;计数排序)

DescriptionDoctor Ghee is teaching Kia how to calculate the sum of two integers. But Kia is so careless and alway forget to carry a number when the sum of two digits exceeds 9. For example, when she calculates 4567+5789, she will get 9246, and for 12

ACM学习历程—HDU 5023 A Corrupt Mayor&#39;s Performance Art(广州赛区网赛)(线段树)

Problem Description Corrupt governors always find ways to get dirty money. Paint something, then sell the worthless painting at a high price to someone who wants to bribe him/her on an auction, this seemed a safe way for mayor X to make money. Becaus

51 Nod 1028 大数乘法 V2【Java大数乱搞】

1028 大数乘法 V2 基准时间限制:2 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 给出2个大整数A,B,计算A*B的结果. Input 第1行:大数A 第2行:大数B (A,B的长度 <= 100000,A,B >= 0) Output 输出A * B Input示例 123456 234567 Output示例 28958703552 题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemI

ACM学习历程—UESTC 1226 Huatuo&#39;s Medicine(数学)(2015CCPC L)

题目链接:http://acm.uestc.edu.cn/#/problem/show/1226 题目就是构造一个对称的串,除了中间的那个只有1个,其余的两边都是对称的两个,自然答案就是2*n-1. 代码: #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> #

ACM学习历程—HDU5585 Numbers(数论 || 大数)(BestCoder Round #64 (div.2) 1001)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5585 题目大意就是求大数是否能被2,3,5整除. 我直接上了Java大数,不过可以对末尾来判断2和5,对所有位的和来判断3. 代码就不粘了.

ACM学习历程—HDU 3092 Least common multiple(数论 &amp;&amp; 动态规划 &amp;&amp; 大数)

hihoCoder挑战赛12 Description Partychen like to do mathematical problems. One day, when he was doing on a least common multiple(LCM) problem, he suddenly thought of a very interesting question: if given a number of S, and we divided S into some numbers

ACM学习历程—HDU1041 Computer Transformation(递推 &amp;&amp; 大数)

Description A sequence consisting of one digit, the number 1 is initially written into a computer. At each successive time step, the computer simultaneously tranforms each digit 0 into the sequence 1 0 and each digit 1 into the sequence 0 1. So, afte

ACM学习历程—NPU1045 2015年陕西省程序设计竞赛网络预赛(热身赛)C题 Graph Theory(递推 &amp;&amp; 组合数学 &amp;&amp; 大数)

Description In graph theory, a matching or independent edge set in a graph G = (V , E) is a set of edges ME such that no two edges in the matching M share a common vertex. The Nobel Prize in XiXiHaHa was awarded to Jerryxf team, amongst other things,

ACM学习历程—HDU 5446 Unknown Treasure(数论)(2015长春网赛1010题)

Problem Description On the way to the next secret treasure hiding place, the mathematician discovered a cave unknown to the map. The mathematician entered the cave because it is there. Somewhere deep in the cave, she found a treasure chest with a com