本文主要是介绍leetcode1969--数组元素的最小非零乘积,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1. 题意
给定一个非零的二进制位排列;
允许交换其中两个数的二进制位任意次。
求交换后得到数组的最小非零乘积。
如:
p = 3 a = [ 001 010 011 100 101 110 111 ] p=3\\ a=[001\ 010\ 011\ 100\ 101\ 110\ 111]\\ p=3a=[001 010 011 100 101 110 111]
将010
与101
交换位置得到110
与001
将011
与100
交换位置得到110
与001
得到答案
1x7x1x6x1x6=1512
2. 题解
首先题目中的数组一定是在 [ 1 , 2 p − 1 ] [1,2^{p}-1] [1,2p−1]之间;
交换二进制位意味着什么呢?
其实就是将
x + y → x ′ + y ′ x + y = x ′ + y ′ x+y \rightarrow x'+y'\\ x+y=x'+y' x+y→x′+y′x+y=x′+y′
由于求得的是最小的非0
乘积,所以我们最少要保留最低位为1
。
对于两个数交换后乘积最大实际上是求
m i n ( x y ) , s . t . x + y = k min(xy),s.t. x+y=k min(xy),s.t.x+y=k
所以我们需要尽量将两个数的差值变大。
所以我们分解的形式应为:
a & b = 0 a ⊕ b = 2 p − 1 a\&b=0\\ a \oplus b=2^p-1 a&b=0a⊕b=2p−1
所以对于数组 [ 1 , . . . , 2 p − 1 ] [1,...,2^p-1] [1,...,2p−1]的乘积为
1 × ( 2 p − 1 ) × ( 2 p − 2 ) 2 p − 1 − 1 1 \times(2^p-1) \times (2^p-2)^{2^{p-1}-1} 1×(2p−1)×(2p−2)2p−1−1
由于 2 2 p − 1 − 1 2^{2^p-1}-1 22p−1−1很大,所以需要使用快速幂。
- 代码
class Solution {
public:long long fast_pow(long long a,unsigned long long b) {long long MOD = 1e9+7;long long base = a%MOD;long long ans = 1;while (b) {if (b & 1) ans = ans * base % MOD; b >>= 1;if (b)base = base * base % MOD;}return ans % MOD ;}int minNonZeroProduct(int p) {long long ans = ((unsigned long long)1 << p) - 1;
int MOD = 1e9+7;long long base = ans - 1;long long cnt = ((unsigned long long)1 << (p -1)) - 1;// std::cout << "base:" << base << " cnt: " << cnt << std::endl; ans = ans%MOD * fast_pow(base, cnt) %MOD;return ans % MOD;}
};
这篇关于leetcode1969--数组元素的最小非零乘积的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!