P10141 [USACO24JAN] Merging Cells P
题解
正难则反
- 正着,设
为合并出 的概率,枚举大区间两端点合并(区间DP)- 复杂度
- 复杂度
- 反着,设
表示由 分裂出 的概率- 设大区间为
,中间点为 - 若
, (一共有 个空隙,选择其中一个的概率是 ) - 反之,
- 这里
的比较规则见题意
- 设大区间为
- 如果
固定,使得 的 单点递减 - 同样,如果
固定,使得 的 单调递增 - 所以可以采用双指针的方法,维护前/后缀和,把复杂度降到
- 此时
代码
-
小细节
-
为什么不是
- 因为此时
的编号本身就 ,所以只要值 就可以 - 而上面
的编号 ,如果值相等,那就会取后者而不是
- 因为此时
-
前后缀和的
具体是谁
-
# include <bits/stdc++.h> # define int long long using namespace std; const int MOD = 1e9 + 7; const int N = (int)5e3 + 10; int n; int s[N]; int dp[N][N], pre[N][N], suf[N][N]; int inv[N], ll[N], rr[N]; int Q_pow(int a, int b){ int ans = 1, p = a; while(b){ if(b & 1){ ans = (ans * p) % MOD; } p = (p * p) % MOD; b >>= 1; } return ans; } signed main(){ cin >> n; inv[0] = 1; for(int i = 1; i <= n; i++){ cin >> s[i]; s[i] += s[i - 1]; inv[i] = Q_pow(i, MOD - 2); ll[i] = 1, rr[i] = n; } dp[1][n] = pre[1][n] = suf[1][n] = inv[n - 1]; for(int i = n - 1; i >= 1; i--){ for(int l = 1, r = i; r <= n; l++, r++){ while(s[r] - s[l - 1] <= s[rr[l]] - s[r]){ rr[l]--; } // l, r + 1 (dp[l][r] += (suf[l][r + 1] - suf[l][rr[l] + 1] + MOD) % MOD) %= MOD; while(s[r] - s[l - 1] < s[l - 1] - s[ll[r] - 1]){ // 为什么不是 <= ! ll[r]++; } // l - 1, r (dp[l][r] += (pre[l - 1][r] - pre[ll[r] - 1][r] + MOD) % MOD) %= MOD; (dp[l][r] *= inv[r - l]) %= MOD; suf[l][r] = suf[l][r + 1]; (suf[l][r] += dp[l][r]) %= MOD; pre[l][r] = pre[l - 1][r]; (pre[l][r] += dp[l][r]) %= MOD; } } for(int i = 1; i <= n; i++){ cout << dp[i][i] << "\n"; } cout << "\n"; }
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话