《小S的子序列平均数之和》和 《小U的数列因子挑战》| 豆包MarsCode刷题挑战

122 阅读4分钟

今天我们将在豆包MarsCode AI刷题平台上,完成《小S的子序列平均数之和》和 《小U的数列因子挑战》算法问题, 都是考验的数学计算逻辑, 一起看看吧

小S的子序列平均数之和

image.png

分析
  1. 要知道不同的子序列可能, 对于i处,它能形成长度为l的子序列可以通过i-1形成长度为l-1的子序列去计算, 使用DP动态规划解决最适合不过了:
dp[i] = dp[i-1]+ arr[i]   //长度为i的子序列的总和, 后面统一除以i,方便计算
  1. 根据样例2我们知道, 需要快速求得x能够 xb (mod p) =a , 转化为: x = ab^(-1) (mod p)
    • 根据费马小定理: 如果p是一个质数,而整数a不是p的倍数,则有 a^(p-1)=1 (mod p)
    • 得到x = a * b^(p-2) (mod p)
具体实现
public static long solution(int n, int[] arr) {
    int mod = 1000000007;
    long result = 0;
    //记录当前处节点为末尾, 长度为i的 [i][0]平均值总和 [i][1]可能的情况数总和
    long[][] dp = new long[n + 1][2];
    dp[0][1] = 1;//长度为0的可能有一种
    for (int i = 1; i <= n; i++) {
        for (int j = i; j > 0; j--) {
            dp[j][0] = (dp[j][0] + dp[j - 1][0] + arr[i - 1] * dp[j - 1][1]) % mod;
            dp[j][1] += dp[j - 1][1];
        }
    }
    for (int i = 1; i <= n; i++) {
        //考虑浮点数的问题, 如例子2
        result = (result + dp[i][0] / i) % mod;
        if (dp[i][0] % i != 0) {
            //x*b= a (mod p)  => x = a/b (mod p)
            //通过费马小定理优化 : 如果p是一个质数,而整数a不是p的倍数,则有 a^(p-1)=1 (mod p)
            //这里需要求得 b^(-1) (mod p) = b^(p-2) (mod p)  至于如何求得b^(p-2) 快速幂
            long val = 1;
            long base = i;
            int exp = mod - 2;  // 根据费马小定理
            while (exp > 0) {
                if (exp % 2 == 1) {
                    val = (val * base) % mod;
                }
                base = (base * base) % mod;
                exp >>= 1;
            }
            result = (result + (dp[i][0] % i) * val) % mod;
        }
    }
    return result;
}

如果对费马小定理不了解, 可以使用下面代码替代

long val = mod + dp[i][0] % i;
while (val % i != 0) {
    val += mod;
}
result = (result + val / i) % mod;

小U的数列因子挑战

image.png

分析
  1. 题目中的 c^d 并非代表异或, 而是c的d次方!!!
  2. 总结归纳. 可以得到第n项时, 使用a的个数, b的个数以及c^d的个数
  3. 对a,b,c因式分解. 相同的质因子共同计数, 能够获取到不同质因子的个数, 题目就回到了多个质因子不同的数量,有多少种取值
    • 质因子k的数量为h 那么它的挑选可能为h+1 (+1代表都不选), 那么所有可能为 (h1+1)(h2+1)(h3+1).. -1, 最终减去1,代表不能每个因子都不选
具体实现
public static int solution(int a, int b, int c, int d, int n) {
    //相当于是将a, b, c 因式分解. 等到不同个数的因子
    int mod = 1000000007;
    //对a进行因式分解
    Map<Integer, Integer> factor; //质因子,不包含1
    if (n == 1) {
        factor = metaFactor(a);
    } else if (n == 2) {
        factor = metaFactor(b);
    } else {
        factor = new HashMap<>();
        Map<Integer, Integer> factorA = metaFactor(a);
        Map<Integer, Integer> factorB = metaFactor(b);
        Map<Integer, Integer> factorC = metaFactor(c);
        int countA = 0;
        int countB = 1;
        int countC = 0; //c的d次方
        //前一个值
        int _countA = 1;
        int _countB = 0;
        int _countC = 0;
        int tmp;
        for (int i = 3; i <= n; i++) { //归纳总结下就知道
            tmp = _countA;
            _countA = countA;
            countA = countA + tmp;

            tmp = _countB;
            _countB = countB;
            countB = countB + tmp;

            tmp = _countC;
            _countC = countC;
            countC = countC + tmp + 1;
        }
        int t_countA = countA;
        factorA.forEach((k, v) -> factor.put(k, v * t_countA + factor.getOrDefault(k, 0)));
        int t_countB = countB;
        factorB.forEach((k, v) -> factor.put(k, v * t_countB + factor.getOrDefault(k, 0)));
        int t_countC = d * countC; //这里的c^d 是代表c的d次方. 不是异或
        factorC.forEach((k, v) -> factor.put(k, v * t_countC + factor.getOrDefault(k, 0)));
    }
    // 有m个x0 有m1个x1.....有mi个xi , 在这些个质因子中随意选择. 但每组不能重复 x0>1
    long result = 1; //因子为1
    if (!factor.isEmpty()) {
        //不包含1的质因子的选择的可能性
        long multi = 1;
        for (Integer value : factor.values()) {
            multi = (multi * (value + 1)) % mod;
        }
        multi--;//减去1 (每个因子至少选择一种)
        result = (result + multi) % mod;
    }
    return (int) result;
}

private static Map<Integer, Integer> metaFactor(int v) {
    Map<Integer, Integer> factor = new HashMap<>();
    int i = 2;
    while (i * i <= v) {
        int count = 0;
        while (v % i == 0) {
            count++;
            v /= i;
        }
        factor.put(i, count);
        i++;
    }
    if (v > 1) {
        factor.put(v, 1);
    }
    return factor;
}

这道题不能单纯的算最终值, 因为fn一旦超过1000000007,那么取模后的因子数就变化了