UVA 1490 Let the light guide us 题解
题意
有一个
思路
朴素 DP
首先,显然
然后可以设计出一个状态:
时间复杂度
优化
这个状态基本上已经无法优化了(反正我不会),所以我们要在转移上下手。
我们看这个式子:
显然右边大于
化简得:
接下来就比较神奇了。(鬼知道这是怎么想到的)
我们记
类似的,记
(显然
那么上面的式子就可以写成:
那么这个式子和「
证明:
区间
与 不相交 等价于 或 ,所以 与 相交 等价于:
这与原式相同。
然后就简单了。现在的问题是对于每个格子有一个区间
做法显然是对于每一行开一个线段树,将上一行的
时间复杂度
代码
// UVA1490
#include <cstdio>
#include <algorithm>
#include <cstring>
const int N = 100 + 5;
const int M = 5000 + 5;
const int ARR_V = 7000 + 5;
const int V_MAX = 6000;
const int INF = 0x3f3f3f3f;
int a[N][M], b[N][M];
int n, m;
int f[N][M];
struct SegmentTree {
int t[ARR_V << 3], lazy[ARR_V << 3];
void reset() {
memset(t, 0, sizeof(t));
memset(lazy, INF, sizeof(lazy));
}
void build() {
memset(t, INF, sizeof(t));
memset(lazy, INF, sizeof(lazy));
}
void set_lazy(int x, int v) { t[x] = std::min(t[x], v), lazy[x] = std::min(lazy[x], v); }
void lazy_down(int x) {
set_lazy(x << 1, lazy[x]), set_lazy(x << 1 | 1, lazy[x]);
lazy[x] = INF;
}
int query(int ql, int qr, int x = 1, int l = 1, int r = V_MAX << 1) {
if(ql > qr) return INF;
if(ql <= l && r <= qr) return t[x];
int mid = (l + r) >> 1, ret = INF;
lazy_down(x);
if(ql <= mid) ret = std::min(ret, query(ql, qr, x << 1, l, mid));
if(qr > mid) ret = std::min(ret, query(ql, qr, x << 1 | 1, mid + 1, r));
return ret;
}
void modify(int ql, int qr, int qv, int x = 1, int l = 1, int r = V_MAX << 1) {
if(ql > qr) return;
if(ql <= l && r <= qr) { set_lazy(x, qv); return; }
int mid = (l + r) >> 1;
lazy_down(x);
if(ql <= mid) modify(ql, qr, qv, x << 1, l, mid);
if(qr > mid) modify(ql, qr, qv, x << 1 | 1, mid + 1, r);
t[x] = std::min(t[x << 1], t[x << 1 | 1]);
}
} seg;
int main() {
while(scanf("%d%d", &n, &m) == 2 && (n | m)) {
for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) scanf("%d", &a[i][j]);
for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) scanf("%d", &b[i][j]), b[i][j] = std::min(b[i][j], 5000);
seg.reset();
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++)
f[i][j] = seg.query(j - b[i][j] + V_MAX, j + b[i][j] + V_MAX) + a[i][j];
seg.build();
for(int j = 1; j <= m; j++)
seg.modify(j - b[i][j] + V_MAX, j + b[i][j] + V_MAX, f[i][j]);
}
int ans = INF;
for(int j = 1; j <= m; j++) ans = std::min(ans, f[n][j]);
printf("%d\n", ans);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】