试题 算法训练 数的潜能
资源限制
时间限制: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=a1∗a2∗a3∗…∗ak为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也有相同的题目:
首先,我们根据高中基本不等式的知识: 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)i则f′(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=xxn则lny=x1lnxydy=x21−lnxdxy′=dxdy=x21−lnxy=x21−lnxxxn令y′=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);
}
}