[北大集训 2021] 随机游走 题解
前言
又是随机游走?
题目链接:洛谷。
题目分析
看到加边,可能性太多了。但是为了让步数最大化,我们可以贪心地想,肯定要往前面连,而且越前面要走的期望步数肯定越大。并且,我们不会浪费边在终点上。于是,题目转变成了
那要如何分配这
从
推到
再推到
找到一些规律,尝试去证明。假设对于
显然该式对于
所以上式对于所有
解方程。
于是我们可以很方便地求出期望步数,即
首先,
略证:
,考虑原先的 有 不妨交换
和 。 显然,因为
,所以交换后的 更优。我们可以不断进行这个过程,直到 有序,即单调不降, 最大。 证毕。
其次……没其次了,打表吧。
while True: n, m = map(int, input().split()) res = [0] * n ans = [0] * n maxx = 0 def dfs(now, tot, x): global maxx, ans if now == n - 1: res[n - 1] = tot tmp = 0 mul = 1 for i in range(n - 1, 0, -1): mul *= res[i] + 1 tmp += mul if tmp > maxx: maxx = tmp ans = res[::] return i = x while i * (n - now) <= tot: res[now] = i dfs(now + 1, tot - i, i) i += 1 dfs(1, m, 0) print(' '.join(map(str, ans[1:])))
以上是打表程序。考虑
m = 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 m = 2: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 ...... m = 18: 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 m = 19: 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 m = 20: 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 ...... m = 35: 0 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 m = 36: 0 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 m = 37: 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 m = 38: 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 ...... m = 54: 1 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 m = 55: 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 m = 56: 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 m = 57: 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 ......
发现,当 感性理解,具体证明交给读者。
Update on 2024.6.20 更新了进一步的证明
下证任意相邻两数之差不超过
证明:
,证明 后不劣。容易发现这样操作是合法的。 对于原先的
: 后来的
,记作 : 那么考虑作差:
由于
,所以 。考虑到 里至少有一个 ,则 ,那么有 ,也就是 是不劣于 的。
如此操作,直至。
有了如上证明,发现 (中考考完再来补坑)
那么,我们分别考虑两种情况即可。
情况一
当
快速幂单次
情况二
当
其中,
代码
注意特判
def fpow(a, b, mod): if b < 0: return 1 res = 1 base = a % mod while b: if b & 1: res = res * base % mod base = base * base % mod b >>= 1 return res def inv(x, mod): return fpow(x, mod - 2, mod) def main(): n, m, mod = map(int, input().split()) if n == 1: print(0) return if m < n - 1: pr = fpow(2, m, mod) print((pr * (n - m + 1) + mod - 2) % mod) return d1 = (m - (n - 2)) // (n - 1) M = m - (n - 2) - (n - 1) * d1 S1 = (d1 + 1) * fpow(d1 + 2, n - M - 2, mod) * fpow(d1 + 3, M, mod) S2 = fpow(d1 + 3, M, mod) * (fpow(d1 + 2, n - 1 - M, mod) - (d1 + 2) + mod) * inv(d1 + 1, mod) S3 = (fpow(d1 + 3, M + 1, mod) - (d1 + 3) + mod) * inv(d1 + 2, mod) S1 %= mod S2 %= mod S3 %= mod print((S1 + S2 + S3) % mod) if __name__ == '__main__': t = int(input()) for i in range(t): main()
后记
用 python
写的目的是因为教练讲题时用 python
打表唤起了我的回忆?
本文作者:XuYueming,转载请注明原文链接:https://www.cnblogs.com/XuYueming/p/18156803。
若未作特殊说明,本作品采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】