【剑指offer】80.剪绳子(进阶版)
总目录:
1.问题描述
给你一根长度为 n 的绳子,请把绳子剪成整数长的 m 段( m 、 n 都是整数, n > 1 并且 m > 1 , m <= n ),每段绳子的长度记为 k[1],...,k[m] 。请问 k[1]*k[2]*...*k[m] 可能的最大乘积是多少?例如,当绳子的长度是 8 时,我们把它剪成长度分别为 2、3、3 的三段,此时得到的最大乘积是 18 。
由于答案过大,请对 998244353 取模。
数据范围:2≤n≤1014
进阶:空间复杂度 O(1), 时间复杂度 O(logn)
2.问题分析
快速幂
因为n的取值比较大,用普通版剪绳子问题中的数学分析贪心算法或动态规划算法都会导致超时,需要更快的计算。
分析可知普通版剪绳子中的方法耗时在逐次*3的计算上,需要将3的联乘改为指数运算来加快速度。
快速幂+快速乘法
暂未看懂,实测确实比只有快速幂节省50%的时间。
3.代码实例
快速幂
1 class Solution { 2 public: 3 long long get3Square(long long base) { 4 if (base < 1) { 5 return 1; 6 } 7 8 long long half = get3Square(base / 2) % 998244353; 9 long long res = half * half % 998244353; 10 if (base % 2 != 0) { 11 res = (res * 3) % 998244353; 12 } 13 14 return res; 15 } 16 17 long long cutRope(long long number) { 18 if (number <= 3) //不超过3直接计算 19 return number - 1; 20 long long res = 1; 21 long long x = number / 3; 22 long long y = number % 3; 23 if (y == 1) {//不允许裁出长度为1的段,最后4米需要裁为2*2 24 x--; 25 } 26 27 //如何快速计算pow(3,x)且不溢出? 28 res = get3Square(x); 29 if (y == 1) {//剩余2*2 30 res = (res * 4) % 998244353; 31 } else if (y == 2) { 32 res = (res * 2) % 998244353; 33 } 34 35 return res; 36 } 37 };
快速幂+快速乘法
1 class Solution { 2 public: 3 long long mod = 998244353; 4 //快速乘法 5 long long fast(long long x, long long y){ 6 long long res = 0; 7 x %= mod; 8 y %= mod; 9 while(y){ 10 if(y & 1){ 11 //加法代替乘法,防止越界 12 res += x; 13 if(res >= mod) 14 res -= mod; 15 } 16 y = y >> 1; 17 x = x << 1; 18 if(x >= mod) 19 x -= mod; 20 } 21 return res; 22 } 23 //快速幂 24 long long Pow(long long x, long long y){ 25 long long res = 1; 26 while(y){ 27 //可以再往上乘一个 28 if(y & 1) 29 res = fast(res, x); 30 //叠加 31 x = fast(x, x); 32 //减少乘次数 33 y = y >> 1; 34 } 35 return res; 36 } 37 long long cutRope(long long number) { 38 //不超过3直接计算 39 if(number <= 3) 40 return number - 1; 41 //能整除3 42 if(number % 3 == 0) 43 return Pow(3, number / 3); 44 //最后剩余1 45 else if(number % 3 == 1) 46 //4*3^{n-1} 47 return fast(Pow(3, number / 3 - 1), 4); 48 //最后剩余2 49 else 50 //2*3^n 51 return fast(Pow(3, number / 3), 2); 52 } 53 };