P4157 [SCOI2006]整数划分(FFT)

目录

Description

将一个数分解成多个数之和,使得这些数的乘积最大

State

\(10<=n<=31000\)

Input

13

Output

3
108

Solution

前置结论:将数 \(x\) 分解成尽可能多的 \(3\) 可以使得答案最大

最后要求的便是:\(3^n*res,\ res∈\{1,2,4\}\)\(3^n\) 可以通过 \(fft\) 和快速幂求解,只不过只将常数项置为 \(3\),这样形成的多项式就变成了 \(a[k]*10^k+a[k-1]*10^{k-1}...a[1]*10+a[0]\) 的形式了

Code

const int N = 4e6 + 5;

    ll n, m, _;
    int i, j, k;
    struct Complex
    {
        double x,y;
        Complex (double x = 0, double y = 0) : x(x), y(y){}
    }a[N],b[N];
Complex operator+(Complex a, Complex b){ return Complex(a.x + b.x ,a.y + b.y); }
Complex operator-(Complex a, Complex b){ return Complex(a.x - b.x ,a.y - b.y); }
Complex operator*(Complex a, Complex b){ return Complex(a.x * b.x - a.y * b.y ,a.x * b.y + a.y * b.x); }

int lim = 1, bit = 0, rev[N];
void init(int n)
{
    while(lim <= n) lim <<= 1, bit ++;
    for(int i = 0; i < lim; i ++){
        rev[i] = rev[i >> 1] >> 1 | ((i & 1) << (bit - 1));
    }
}

void fft(Complex *a, int type)
{
    for(int i = 0; i < lim; i ++){
        if(i >= rev[i]) swap(a[i], a[rev[i]]);
    }
    for(int mid = 1; mid < lim; mid *= 2){
        Complex wn(cos(pi / mid), sin(pi / mid) * type);
        for(int len = mid * 2, i = 0; i < lim; i += len){
            Complex w(1, 0);
            for(int j = 0; j < mid; j ++, w = w * wn){
                Complex x = a[i + j], y = a[i + j + mid] * w;
                a[i + j] = x + y;
                a[i + j + mid] = x - y;  
            }
        }
    }
    if(type == 1) return ;
    for(int i = 0; i < lim; i ++){
        a[i].x /= lim;
    }
}

void ksm(int x)
{
    while(x){
        if(x & 1){
            fft(a, 1); fft(b, 1);
            for(int i = 0; i < lim; i ++) a[i] = a[i] * b[i];
            fft(a, -1); fft(b, -1);
            for(int i = 0; i < lim; i ++){
                int ava = (a[i].x + 0.5) / 10, eva = (b[i].x + 0.5) / 10;
                a[i] = Complex(int(a[i].x + 0.5) % 10, 0);
                b[i] = Complex(int(b[i].x + 0.5) % 10, 0);
                a[i + 1].x += ava, b[i + 1].x += eva;
            }
        }

        fft(b, 1);
        for(int i = 0; i < lim; i ++) b[i] = b[i] * b[i];
        fft(b, -1);
        for(int i = 0; i < lim; i ++){
            int ava = (b[i].x + 0.5) / 10;
            b[i] = Complex(int(b[i].x + 0.5) % 10, 0);
            b[i + 1].x += ava;
        }

        x >>= 1;
    }
}

signed main()
{
    //IOS;
    while(~ sd(n)){
        if(n % 3 == 0) a[0] = 1;
        else if(n % 3 == 1) a[0] = 4, n -= 4;
        else a[0] = 2, n -= 2;
        b[0] = 3;
        init(n / 3);
        ksm(n / 3);
        while(a[lim].x == 0) lim --;
        pd(lim + 1);
        for(int i = lim, j = 0; ~ i && j <= 99; i --, j ++){
            printf("%d", int(a[i].x + 0.5));
        }
    }
    //PAUSE;
    return 0;
}
posted @ 2021-09-12 17:02  Bcoi  阅读(73)  评论(0)    收藏  举报