洛谷P4157 [SCOI2006]整数划分 高精度乘法[FFT 快速傅里叶变换]

50 篇文章 0 订阅
26 篇文章 0 订阅

题目描述

从文件中读入一个正整数n(10≤n≤31000)。要求将n写成若干个正整数之和,并且使这些正整数的乘积最大。

例如,n=13,则当n表示为4+3+3+3(或2+2+3+3+3)时,乘积=108为最大。

输入格式

只有一个正整数:n (10≤n≤31000)

输出格式

第1行输出一个整数,为最大乘积的位数。

第2行输出最大乘积的前100位,如果不足100位,则按实际位数输出最大乘积。

(提示:在给定的范围内,最大乘积的位数不超过5000位)。

输入输出样例

输入 #1

13

输出 #1

3
108
#include <bits/stdc++.h>
using namespace std;

typedef double D;
const int N = 16500;
const D PI = acos(-1.0);

struct cox{
    D x, y;
    cox(D xx = 0, D yy = 0){x = xx; y = yy;}
}a[N], b[N];

cox operator +(const cox &u, const cox &v){
    return cox(u.x + v.x, u.y + v.y);
}

cox operator -(const cox &u, const cox &v){
    return cox(u.x - v.x, u.y - v.y);
}

cox operator *(const cox &u, const cox &v){
    return cox(u.x * v.x - u.y * v.y , u.x * v.y + u.y * v.x);
}

int n , rnk[N], c[N], len = 16384, cn = 13;

void fft(cox *t, int op){
    for (int i = 0; i < len; i++) if (i < rnk[i]) swap(t[i], t[rnk[i]]);
    for (int i = 1; i < len; i <<= 1){
        cox wn(cos(PI / i) , op * sin(PI / i));
        for (int j = 0, jj = i << 1; j < len; j += jj){
            cox w (1, 0);
            for (int k = 0; k < i; k++, w = w * wn){
                cox r = t[j + k], rr = w * t[i + j + k];
                t[j + k] = r + rr;
                t[i + j + k] = r - rr;
            }
        }
    }
}

//fft
void po(int op){
    if (op){
        fft(a, 1); fft(b, 1);
        for (int i = 0; i <= len; i++) a[i] = a[i] * b[i];
        for (int i = 0; i <= len; i++) b[i] = b[i] * b[i];
        fft(a, -1); fft(b, -1);

        for (int i = 0; i <= len; i++) c[i] = (int)(a[i].x / len + 0.5);
        for (int i = 0; i <= len; i++){
            if (c[i] >= 10) c[i + 1] += c[i] / 10, c[i] %= 10;
        }
        for (int i = 0; i <= len; i++) a[i].x = c[i], a[i].y = 0, c[i] = 0;
        for (int i = 0; i <= len; i++) c[i] = (int)(b[i].x / len + 0.5);
        for (int i = 0; i <= len; i++){
            if (c[i] >= 10) c[i + 1] += c[i] / 10, c[i] %= 10;
        }
        for (int i = 0; i <= len; i++) b[i].x = c[i], b[i].y = 0, c[i] = 0;
    }
    else{
        fft(b, 1);
        for (int i = 0; i <= len; i++) b[i] = b[i] * b[i];
        fft(b, -1);

        for (int i = 0; i <= len; i++) c[i] = (int)(b[i].x / len + 0.5);
        for (int i = 0; i <= len; i++){
            if (c[i] >= 10) c[i + 1] += c[i] / 10, c[i] %= 10;
        }
        for (int i = 0; i <= len; i++) b[i].x = c[i], b[i].y = 0, c[i] = 0;
    }
}

int main(){
    scanf("%d", &n);
    if (n == 1) {puts("1"); return 0;}
    if (n == 2) {puts("2"); return 0;}
    if (n % 3 == 1) a[0] = 4, n -= 4;
    else if (n % 3 == 2) a[0] = 2, n -= 2;
    else a[0] = 1;
    b[0] = 3; n /= 3;
    for (int i = 0; i < len; i++) rnk[i] = (rnk[i>>1] >> 1) | ((i&1)<<cn);
    for (; n; n >>= 1) po((n&1)?1:0);
    int i;
    for (i = len; a[i].x == 0;i--);
    printf("%d\n", i+1);
    if (i <= 99) for(; i>= 0;i--) printf("%d", (int)a[i].x);
    else for (int j = 100; j; j--, i--) printf("%d", (int)a[i].x);
    return 0;
}

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值