> For the complete documentation index, see [llms.txt](https://nataliekung.gitbook.io/ladder_code/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://nataliekung.gitbook.io/ladder_code/meta-2024/the-sum-of-legal-set.md).

# The Sum of Legal Set

{% embed url="<https://blog.csdn.net/qq_46105170/article/details/104338070>" %}

给定一个长n nn的数组A AA和一个整数k kk，问A AA有多少个子集使得其最大最小值之和是小于等于k kk的。答案模1 0 9 + 7 10^9+710 9 +7后返回。空子集不算。

先对A AA排序，接着用对撞双指针，枚举最小最大值。设指针i ≤ j i\le ji≤j，如果A \[ i ] + A \[ j ] ≤ k A\[i]+A\[j]\le kA\[i]+A\[j]≤k，说明以A \[ i ] A\[i]A\[i]为最小值，A \[ i : j ] A\[i:j]A\[i:j]为最大值的子集都是满足条件的，这样的子集的个数就是2 j − i 2^{j-i}2 j−i 个，计算完这样的子集之后，将i ii右移；否则如果A \[ i ] + A \[ j ] > k A\[i]+A\[j]> kA\[i]+A\[j]>k，则左移j jj。至于求2 k 2^k2 k ，可以用快速幂来做，时间复杂度可以降到O ( log ⁡ k ) O(\log k)O(logk)，具体参考<https://blog.csdn.net/qq\\_46105170/article/details/104338070。代码如下：> ————————————————

原文链接：<https://blog.csdn.net/qq\\_46105170/article/details/110621205>

```
import java.util.Arrays;

public class Solution {
    /**
     * @param a: the array
     * @param k: the target
     * @return: the sum of the legal set
     */
    public int theSumofLegalSet(int[] a, int k) {
        // Write your code here.
        Arrays.sort(a);
        
        long res = 0, MOD = (long) (1E9 + 7);
        for (int i = 0, j = a.length - 1; i <= j; ) {
            if (a[i] + a[j] <= k) {
                res += pow2(j - i, MOD);
                res %= MOD;
                i++;
            } else {
                j--;
            }
        }
        
        return (int) res;
    }
    
    private long pow2(int n, long MOD) {
        long res = 1, p = 2;
        while (n > 0) {
            if ((n & 1) == 1) {
                res *= p;
                res %= MOD;
            }
            
            p *= p;
            p %= MOD;
            
            n >>= 1;
        }
        
        return res;
    }
}

```

pow(x,n)

算x n x^nx n 。

思路是快速幂（exponentiating by squaring）。主要思路是对n nn做二进制展开，然后对这些二进制位从右向左扫描，用一个变量来保存到当前这个二进制位，x xx的那么多次次方的结果是多少。

设r rr是答案。举个例子来说，如果要算x 13 x^{13}x 13 ，由于13 = ( 1101 ) 2 13=(1101)\_213=(1101) 2 ​ ，x xx首先保存的是x 2 0 x^{2^0}x 2 0

是多少，也就是x 1 x^1x 1 ，那其实就是x xx。接着开始从右向左扫描1101 11011101，扫描到第0 00位时遇到1 11，就给r rr乘上x 2 0 x^{2^0}x 2 0

，同时x xx需要平方一下，这样就保存了x 2 1 x^{2^1}x 2 1

这个值，扫描到第1 11位时遇到0 00，r rr保持原样，而x xx继续平方一下，得到了x 2 2 x^{2^2}x 2 2

，继续扫描到1 11，这时r rr乘一下x 2 2 x^{2^2}x 2 2

，如此下去r rr又乘了x 2 3 x^{2^3}x 2 3

，扫描结束。我们统计一下会发现，r = x 2 0 × x 2 2 × x 2 3 = x 2 0 + 2 2 + 2 3 = x 13 r=x^{2^0}\times x^{2^2}\times x^{2^3}=x^{2^0+2^2+2^3}=x^{13}r=x 2 0

×x 2 2

×x 2 3

\=x 2 0 +2 2 +2 3

\=x 13 ，正好是所求结果。代码如下： ————————————————

原文链接：<https://blog.csdn.net/qq\\_46105170/article/details/104338070>

```

class Solution {
 public:
  double myPow(double x, int m) {
    double res = 1.0;
    long long n = m;
    if (n < 0) x = 1.0 / x;
    n = abs(n);
    while (n) {
      if (n & 1) res *= x;
      x *= x;
      n >>= 1;
    }
    return res;
  }
};

```
