蓝桥杯 算法训练 数的潜能(Java)

问题描述:

将一个数N分为多个正整数之和,即N=a1+a2+a3+…+ak,定义M=a1*a2*a3*…*ak为N的潜能。

  给定N,求它的潜能M。

  由于M可能过大,只需求M对5218取模的余数。

输入格式:

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

输出格式:

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

样例输入:

10

样例输出:

36

数据规模和约定:

1<=N<10^18

思路:

观察题目我们可以举出如下几个例子:

N = 4 = 2 + 2 N = 5 = 3 + 2 N = 6 = 3 + 3 N = 7 = 3 + 2 + 2

N = 8 = 3 + 3 + 2 + 2 .... N= 10 = 3 + 3 + 2 + 2 N = 11 = 3 + 3 + 3 + 2 + 2

不难发现,我们可以从中总结出规律来:

  1. 当N <= 2 时,最大的M其实就是自己本身,即使题目提到说一个正整数可以分解为多个,但是对二来说如果分解成为1+1的话,那么其M将不会是最大的那个值。

  1. 当 N >= 3时,N % 3 == 0, 其可以分解为 N / 3 个 3 相乘。

N % 3 == 1, 其可以分解为 (N / 3 - 1)个 3与 两个 2 相乘。

N % 3 == 2, 其可以分解为 N / 3 个 3与 以一个 2 相乘。

注解:而为什么不分解成为其他数相乘呢,首先其他数可以分解成2和3的形式,其次2和3相同项相乘,其实就是幂的乘积,初中知识我们可以直到幂的乘积可以达到很大的值的,但是如果分解成为含有1的相乘的话,那就没有太大的意义了。反而导致整体的乘积变小。

  1. 关于求幂之积,我首先就想到了java内置包中的Math类的pow方法,但是他实际返回的是一个double类型的数据,如果强制转换成为int行,也会损失精度。(此时你可能回想,都是正整数相乘,不会出先小数点后不是0的想象,转换也没有什么关系,但是题目实际也说到了,如果相乘的结果才去取模的话,数值可能会很大,甚至出现数据溢出的情况,毕竟你调试是没有反馈回来的,哪怕你用到java中的BigInteger类的话,也可能会出现运算超时 的情况了,因此我们应该采用,每累乘一次就对当前数值进行取模,这样运算效率就会大大的提高了)

  1. 说到运算的效率,就不得不提及到快速幂的算法了

不清楚什么是快速幂算法的小伙伴可以看看这个:http://t.csdn.cn/Wl4NV

快速幂的相关代码:

public static long fastPower(long  base, long  power) {
        long  result = 1;
        while (power > 0) {
            if ((power & 1) == 1) {
                result = result * base % 5218;
            }
            power >>= 1;
            base = (base * base) % 5218;
        }
        return result;
    }

base:底数 power :指数 result : 用来存储当前的数值的取模值

power & 1:这个是位运算符,表示power转换成2进制的形式与1的二进制数:00000001相与,如果为1则说明power为奇数,如果为0则说明power为偶数。

power >>= 1: 表示power转换成2进制的形式后向右移动1位,相当于原十进制数除2

当指数为奇数时,抽底数相同的一类组合出来,然后指数边为原来的一半(9 / 2 = 4)

如:3^10 = 3*3*3*3*3*3*3*3*3*3 10个3

=(3*3)*(3*3)*(3*3)*(3*3)*(3*3) 5 个(3*3)= 9^5

=(3*3*3*3)*(3*3*3*3) 因为这个时候指数变成奇数,所以又提出了一个(3*3)出去 因此 2个(3*3*3*3) = 81 ^ 2

= (3*3*3*3*3*3*3*3) = 6561^1

完整代码:

import java.util.Scanner;

/**
 * @author Qik~
 * @create 2023-01-15 12:58
 */
public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        long N = scan.nextLong();
        int goal = 0;
        long M = 0;
        if (N <= 2) {
            System.out.println(N);
        } else {
            goal = (int) (N % 3);
            if (goal == 0) {
                M = fastPower(3,(N / 3));
                System.out.println(M);

            } else if (goal == 1) {
                M = fastPower(3,(N / 3 - 1)) * 4 % 5218;
                System.out.println(M);
            } else if (goal == 2) {
                M = fastPower(3,(N / 3)) * 2 % 5218;
                System.out.println(M);
            }



        }
    }

    public static long fastPower(long  base, long  power) {
        long  result = 1;
        while (power > 0) {
            if ((power & 1) == 1) {
                result = result * base % 5218;
            }
            power >>= 1;
            base = (base * base) % 5218;
        }
        return result;
    }

}

测试结果:

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Luca-s-

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

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

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

打赏作者

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

抵扣说明:

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

余额充值