leetcode每日一题1969

时间:2024-03-28 20:30:58

目录

一.题目原型:

二思路解析:

三.代码实现:


一.题目原型:

 

二思路解析:

灵神的做法非常让人惊叹:

理解就是,如果一个数大于另一个数要交换的1的权重,那么他们的乘积就变小。

那么一个大的数不断变大,小的数不断变小,乘积不也就越来越小吗?

在看个例子。 

注意点一:交换后所有数字的和不变,因为只是某一个数 +2^k,另一个数 -2^k,和不变.

注意点二:然后在和不变的基础上,差大积小,假如能形成 1 1 1 1 1 …… 1 n,那肯定积最小,但是,这种情况是达咩的,这就是注意点二:交换是交换,上限不会超过2^p-1,数字的上限已经决定了

回头看示例3:

注意点3:接着继续考虑,尽可能的形成1这个思路没错了,问题是最多有多少个1可以形成,接着我看示例3:我先是疑惑了一下,为什么是 1 1 1 6 6 6 7呢,和不变的情况下,差大积小,为什么不是 1 1 1 5 6 7 7呢,明显积更小啊,之后就被我发现了注意点三:在二进制位上的0、1数量是相对不变的,p=3举例,每个二进制位上都是4个1,3个0;p=4的时候 都是8个1,7个0

最关键的是: 

很完美的思路:灵神太厉害了! 

快速幂的知识总结下来就是一句话:x的n次方就是不断缩小n,扩大x的时候找出所有奇次方底数的积,还有本题数字太大,也需要将快速幂的模的方法搬过来。

三.代码实现:

class Solution {
    const int mod = 1'000'000'007;

    long long pow(long long x, long long m) {
        x %= mod;
        long long res = 1;
        while (m>0) {
            if(m&1){
            res = res * x % mod;
            }
            m>>=1;
            x = (x%mod * x % mod)%mod;
        }
        return res;
    }

public:
    int minNonZeroProduct(int p) {
        long long k = (1LL << p) - 1;  //k=2^p -1
        long long m=(1LL<<(p-1))-1;
        return k % mod * pow(k - 1, m) % mod;
    }
};