整数划分(重载运算符)

因为今天周……,所以我决定给亲爱的读者一份惊喜

目录

目录

因为今天周……,所以我决定给亲爱的读者一份惊喜

目录

题目描述

输入

输出

样例输入

样例输出

解析

正解

代码

代码 + 重载


题目描述

读入一个正整数n。要求将n写成若干个正整数之和,并且使这些正整数的乘积最
大。例如,n=13,则当n表示为4+3+3+3(或2+2+3+3+3)时,乘积=108为最大。

输入

一个整数,n。

输出

第1行输出一个整数,为最大乘积的位数。第2行输出最大乘积的前100位,如果
不足100位,则按实际位数输出最大乘积。(提示:在给定的范围内,最大乘积的
位数不超过5000位)。

样例输入

13

样例输出

3
108

解析

此题的思路其实还是蛮好想的,考试时想了一个二分,分着分着,发现 “8” 这个数据过不了,本来应是 2 * 3 * 3 = 18,我却输出了 16,以此也能反映出我的二分思路:不断二分,直到两个数的差值不能减小为止,换句话说,就是让分出的数尽量相邻。

正解

做此题时,你得知道任意一个大于 2 的整数一定能被 2 或 3 整分,及 n = 2x + 3y

然后你又得明白,一个数尽量分成 3,其次分成 2 是最优的,多举几个例子不就出来了嘛……(考试时,我举了几个数答案就出来了)

证明如下:

  1. 6 = 3 * 3 = 2 * 2 * 2 \rightarrow 9 > 8(大家都知道分到 1 是最不划算的,所以 6 也就这两种分法了)

  2. 一个数 n % 6 则只会余下 1 2 3 4 5

  3. 1,2 , 3,4 ,5 其实都没什么好讲的,只会分出 2 和 3 ,不然会分到 1 嘛

代码

#include<cstdio>
#define M 31000 + 5
#define reg register
 
int a[M],c[M] = {0,1},len = 1;
int n;
 
void gj(int f){
    int x = 0;
    for (reg int i = 1;i <= len; ++ i){
        c[i] = c[i] * f + x;
        x = c[i] / 10;
        c[i] %= 10;
    }
    while(x){
        c[ ++ len] = x;
        x = c[len] / 10;
        c[len] %= 10;
    }
}
 
int main(){
    scanf("%d",&n);
    int f = n / 3;
    int h = n % 3;
    while (h % 2){
        h += 3;
        -- f;
    }
    h /= 2;
    for (reg int i = 1;i <= f; ++ i)
        gj(3);
    for (reg int i = 1;i <= h; ++ i)
        gj(2);
    int eb = ( len >= 100 ? len - 99 : 1 );
    printf("%d\n",len);
    for (reg int i = len;i >= eb; -- i)
        printf("%d",c[i]);
    printf("\n");
    return 0;
}
 

然而你会发现,此题可以用 快速幂 进行优化,用快速幂就得用重载嘛……(方便)

对于重载的话大家看一遍代码及懂,也不是太难

代码 + 重载

#include<cstdio>
#include<cstring>
#define M 5000 + 5
#define reg register
  
struct node{
    int len,a[M];
    inline void cl(){
        len = 0;
        memset(a,0,sizeof(a));
    }
    inline  int siz(){
        while ( ! a[len] && len > 1)
            -- len;
        return len;
    }
}ans,t,one,two,three;
int n;
  
node operator * (const node x,node y){
    t.cl();
    int jw = 0;
    for (reg int i = 1;i <= x.len; ++ i){
        int j = 1;
        for (;j <= y.len; ++ j){
            t.a[i + j - 1] = t.a[i + j - 1] + x.a[i] * y.a[j] + jw;
            jw = t.a[i + j - 1] / 10;
            t.a[i + j - 1] %= 10;
        }
        j = i + j - 1;
        while (jw){
            t.a[j] = jw;
            jw = t.a[j] /10;
            t.a[j] %= 10;
            ++ j;
        }
    }
    t.len = y.len + x.len;
    t.len = t.siz();
    return t;
}
node qkpow(int x,node f){
    node Point = one;
    while(x){
        if (x % 2)
            Point = Point * f;
        f = f * f;
        x /= 2;
    }
    return Point;
}
  
inline void ycl(){
    three.len = 1;
    three.a[1] = 3;
    two.len = 1;
    two.a[1] = 2;
    one.len = 1;
    one.a[1] = 1;
}
int main(){
    ycl();
    scanf("%d",&n);
    int siz_three = n / 3;
    int remainder = n % 3;
    while (remainder % 2){
        remainder += 3;
        -- siz_three;
    }
    remainder /= 2;
    ans = qkpow(siz_three,three) * qkpow(remainder,two);
    int endd = ans.len <= 100 ? 1 : ans.len - 99;
    printf("%d\n",ans.len);
    for (reg int i = ans.len;i >= endd; -- i)
        putchar('0' + ans.a[i]);
    putchar('\n');
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值