试题 算法训练 数的潜能 简单的数学推导

试题 算法训练 数的潜能

资源限制

时间限制:1.0s 内存限制:256.0MB

问题描述

将一个数N分为多个正整数之和,即N= a 1 + a 2 + a 3 + … + a k a_1+a_2+a_3+…+a_k a1+a2+a3++ak,定义 M = a 1 ∗ a 2 ∗ a 3 ∗ … ∗ a k M=a_1*a_2*a_3*…*a_k M=a1a2a3ak为N的潜能。
  给定N,求它的潜能M。
  由于M可能过大,只需求M对5218取模的余数。

输入格式

输入共一行,为一个正整数N。

输出格式

输出共一行,为N的潜能M对5218取模的余数。

样例输入

10

样例输出

36

数据规模和约定

1 < = N < 1 0 18 1<=N<10^{18} 1<=N<1018

题解

分析一下题目的意思,其实就是要求我们把一个数N分成任意个正整数,使得这些数的积最大

这道题,leetcode也有相同的题目:

343.整数拆分

首先,我们根据高中基本不等式的知识: a + b > = 2 a b a+b>=2{\sqrt{ab}} a+b>=2ab

通过一系列推导可以得出: n 1 + n 2 + n 3 + . . . + n i > = i n 1 n 2 n 3 . . . n i i n_1+n_2+n_3+...+n_i>=i\sqrt[i]{n_1n_2n_3...n_i} n1+n2+n3+...+ni>=iin1n2n3...ni (当且仅当 n 1 = n 2 = n 3 = . . . . . = n i n_1=n_2=n_3=.....=n_i n1=n2=n3=.....=ni时等号成立)

(具体推导过程我忘了,好像是根柯西不等式什么的有关系的,太久了遗忘了…)

由上面的式子我们又可以推导出:

n 1 n 2 n 3 . . . n i < = ( n 1 + n 2 + n 3 + . . . + n i i ) i = ( n i ) i n_1n_2n_3...n_i<=(\frac{n_1+n_2+n_3+...+n_i}{i})^i=(\frac{n}{i})^i n1n2n3...ni<=(in1+n2+n3+...+ni)i=(in)i

那么我们现在肯定要先把 ( n i ) i (\frac{n}{i})^i (in)i的最大值求出来,当然,变量应该是 i i i,也就就是我们要求出分多少份时,能够使 ( n i ) i (\frac{n}{i})^i (in)i值最大,那我们就求个导?
令 f ( i ) = ( n i ) i 则 f ′ ( i ) = d f ( i ) d i = − ( n i ) i n i 2 l n ( n i ) 令f(i)=(\frac{n}{i})^i\\ 则f'(i)=\frac{df(i)}{di}=-(\frac{n}{i})^i\frac{n}{i^2}ln(\frac{n}{i})\\ f(i)=(in)if(i)=didf(i)=(in)ii2nln(in)
emmmm….这个导数有点难求,那我们不妨换个元,令 x = n i x=\frac{n}{i} x=in,此时 i = n x i=\frac{n}{x} i=xn
令 y = x n x 则 l n y = 1 x l n x d y y = 1 − l n x x 2 d x y ′ = d y d x = 1 − l n x x 2 y = 1 − l n x x 2 x n x 令 y ′ = 0 , 则 得 到 驻 点 x 0 = e 令y=x^\frac{n}{x}\\ 则lny=\frac{1}{x}lnx\\ \frac{dy}{y}=\frac{1-lnx}{x^2}dx\\ y'=\frac{dy}{dx}=\frac{1-lnx}{x^2}y=\frac{1-lnx}{x^2}x^\frac{n}{x}\\ 令y'=0,则得到驻点x_0=e y=xxnlny=x1lnxydy=x21lnxdxy=dxdy=x21lnxy=x21lnxxxny=0,x0=e
注意一下,我们换元以后,x表示的就是使得乘机最大的均分的每个数的大小,由于是整数,我们分别取2和3比较:
y ( 2 ) = 2 n 2 y ( 3 ) = 3 n 3 y(2)=2^\frac{n}{2}\\ y(3)=3^\frac{n}{3} y(2)=22ny(3)=33n
大致用计算器比较一下,发现取3时更大一些

综上所述,我们得出结论,当我们把每个数尽可能的取3时所得的结果是最大的,但是如果不能恰好取3,而剩余一个1的话,就把1加到最后一个3上,使其更大,剩余2的话,直接保留即可,因为我们刚刚式子中求出,最大值最优取值为3,其次未2

接下来进入算法部分

这里我们注意到数据范围为long型,于是我们想到这道题大概是要用快速幂来求解的,我们根据上面的推算,能够知道,我们现在要求的就是要把一个数分成多少个3,然后把分出来的数全部相乘,得到最后的结果

代码

package com.lanqiao.topic;

import java.util.Scanner;

/**
 * @author 王宇哲
 * @date 2022/3/10 下午10:23
 **/
public class 数的潜能 {

    /**
     * 快速幂算法
     * @param n 基底
     * @param m 幂数
     * @return n
     */
    static long quickPow(long n, long m){

        long res = 1;

        //负数幂不进行运算了
        while (m > 0){
            if((m & 1)==1){
                res *= n;
                res %= 5218;
            }

            n *= n;
            n %= 5218;
            m >>= 1;

        }

        return res;

    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        long N = scanner.nextLong();

        //3的个数
        long num;

        long result;

        //正好能被3整除
        if(N % 3 == 0){

            //求出3的个数
            num = N/3;

            result = quickPow(3,num);

        }else if(N % 3 == 1){
            //除完以后的余数为1,把1加到其中一个3中,变为4,所以3的个数少了一个

            num = N / 3 - 1;

            result = quickPow(3,num);

            //这里没有看着的那么恐怖
            //就是说,当除出来,3的个数等于0,说明N是小于3的,那么num的值就是-1,此时根本没法按照原先的算法计算
            //说白了,就是对1这个情况进行特殊化操作了
            result = (( 1 + ((num >= 0) ? 3 : 0) ) * result) % 5218;

        }else{
            //除完以后余数为2,直接把2乘进去

            num = N/3;

            result = quickPow(3,num);

            result = (2 * result) % 5218;

        }

        System.out.println(result);

    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个老蒟蒻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值