题解 | 变化的数组

变化的数组

https://www.nowcoder.com/practice/bfb7f9b9f6704892b4b1792edb13a9f0

"""
import sys

MOD = 10 ** 9 + 7

# 了解了一下快速幂算法,二进制取幂能省下不少时间
def fast_pow(base, exp, mod):
    result = 1  # 初始结果
    while exp > 0:  # 当指数还没处理完
        if exp & 1:  # 检查 exp 的最低位是不是 1
            result = (result * base) % mod  # 是 1 就乘上去
        base = (base * base) % mod  # 底数平方(准备下一位)
        exp >>= 1  # 指数右移一位(去掉最低位)
    return result


def solve():
    line = sys.stdin.readline().split()
    n = int(line[0])
    m = int(line[1])
    k = int(line[2])

    line2 = sys.stdin.readline().split()
    a = []
    for i in range(n):
        a.append(int(line2[i]))

    S = 0
    for i in range(n):
        S = S + a[i]
    S = S % MOD

    T = 0
    for i in range(n):
        T = T + (a[i] & m)
    T = T % MOD


    # 计算 2^k mod MOD
    k_M = fast_pow(2, k, MOD)

    inv_k_M = fast_pow(k_M, MOD - 2, MOD) # MMP...这个逆元给我整麻了,华为机考总不能还带数学竞赛知识把...

    result = (S + (T * (k_M - 1) % MOD) * inv_k_M) % MOD #整体概率是1/2,但轮次不独立,所以得按照1/2+....1/(2^k)也就是1-1/(2^k)

    print(result)


if __name__ == "__main__":
    solve()

"""

MOD = 10 ** 9 + 7


def modinv(a):
    return pow(a, MOD - 2, MOD)


def solve():
    import sys

    input = sys.stdin.read
    data = input().split()
    n = int(data[0])
    m = int(data[1])
    k = int(data[2])
    a = list(map(int, data[3 : 3 + n]))

    # 预处理组合数系数,因为i很小,我们可以直接计算C(k,i) mod MOD
    # 由于k很大,需要循环乘
    # 先计算 inv2^k
    inv2 = modinv(2)
    inv2k = pow(inv2, k, MOD)

    # 预计算组合数 C(k, i) 对于 i=0..30
    comb = [0] * 31
    comb[0] = 1
    # 计算 C(k, i) = k*(k-1)*...*(k-i+1) / i!
    # 需要分母的逆元,可以预处理阶乘逆元
    # 由于i很小,直接乘除
    # 注意:k可能小于i?但i≤30,k≥1,所以没问题
    fact = [1] * 31
    for i in range(1, 31):
        fact[i] = fact[i - 1] * i % MOD
    inv_fact = [1] * 31
    inv_fact[30] = modinv(fact[30])
    for i in range(29, -1, -1):
        inv_fact[i] = inv_fact[i + 1] * (i + 1) % MOD

    # 计算组合数
    # 由于k很大,我们直接用公式,注意取模
    # 注意:k可能大于MOD,但组合数公式在模意义下需要小心,因为k可能不是小于MOD,但这里k ≤ 1e9 < MOD,所以没问题
    comb[0] = 1
    for i in range(1, 31):
        # C(k,i) = C(k,i-1) * (k-i+1) / i
        comb[i] = comb[i - 1] * (k - i + 1) % MOD
        comb[i] = comb[i] * modinv(i) % MOD

    # 现在对于每个数,计算迭代序列
    ans = 0
    for x in a:
        seq = []
        cur = x
        while True:
            y = cur & m
            if y == 0:
                break
            seq.append(cur)
            cur = cur + y
        # 循环结束时,cur 是稳定值(即cur & m == 0)
        # seq 记录了每一步的值,长度记为 t
        t = len(seq)
        # 计算概率
        p_rest = 1
        exp_val = 0
        for i in range(t):
            p_i = comb[i] * inv2k % MOD
            exp_val = (exp_val + seq[i] * p_i) % MOD
            p_rest = (p_rest - p_i) % MOD
        exp_val = (exp_val + cur * p_rest) % MOD
        ans = (ans + exp_val) % MOD

    print(ans)


if __name__ == "__main__":
    solve()

不说了,给我整抑郁了....真有你的HW

全部评论

相关推荐

上周组里招人,我面了六个候选人,回来跟同事吃饭的时候聊起一个让我挺感慨的现象。前三个候选人,算法题写得都不错。第一道二分查找,五分钟之内给出解法,边界条件也处理得干净。第二道动态规划,状态转移方程写对了,空间复杂度也优化了一版。我翻他们的简历,力扣刷题量都在300以上。后三个呢,就有点参差不齐了。有的边界条件没处理好,有的直接说这道题没刷过能不能换个思路讲讲。其中有一个女生,我印象特别深——她拿到题之后没有马上写,而是先问我:“面试官,我能先跟你确认一下我对题目的理解吗?”然后她把自己的思路讲了一遍,虽然最后代码写得不是最优解,但整个沟通过程非常顺畅。这个女生的代码不是最优的,但当我问她“如果这里是线上环境,你会怎么设计’的时候,她给我讲了一套完整的方案——异常怎么处理、日志怎么打、怎么平滑发布。她对这是之前在实习的时候踩过的坑。”我在想LeetCode到底在筛选什么?我自己的经历可能有点代表性。我当年校招的时候,也是刷了三百多道题才敢去面试。那时候大家都刷,你不刷就过不了笔试关。后来工作了,前三年基本没再打开过力扣。真正干活的时候,没人让你写反转链表,也没人让你手撕红黑树。更多的是:这个接口为什么慢了、那个服务为什么OOM了、线上数据对不上了得排查一下。所以后来我当面试官,慢慢调整了自己的评判标准。算法题我还会出,但目的变了。我出算法题,不是想看你能不能背出最优解。而是想看你拿到一个陌生问题的时候,是怎么思考的。你会先理清题意吗?你会主动问边界条件吗?你想不出来的时候会怎么办?你写出来的代码,变量命名乱不乱、结构清不清楚?这些才是工作中真正用得到的能力。LeetCode是一个工具,不是目的。它帮你熟悉数据结构和常见算法思路,这没问题。但如果你刷了三百道题,却说不清楚自己的项目解决了什么问题、遇到了什么困难、你是怎么解决的,那这三百道题可能真的白刷了。所以还要不要刷LeetCode?要刷,但别只刷题。刷题的时候,多问自己几个为什么:为什么用这个数据结构?为什么这个解法比那个好?如果换个条件,解法还成立吗?把刷题当成锻炼思维的方式,而不是背答案的任务。毕竟面试官想看到的,从来不是一台背题机器,而是一个能解决问题的人。
牛客51274894...:意思是光刷力扣还不够卷
AI时代还有必要刷lee...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务