Description
Input
Output
题目大意:一个n*m的矩阵,每个点有两个属性T和F,然后每行选出一个点,要求相邻两行选的点x、y满足abs(x - y) ≤ F(x) + F(y),求min(sum(T))。
思路:dp[i][j]代表选第 i 行第 j 列能得到的最小值,朴素的DP复杂度为O(nm²),数据范围无法承受。观察发现对于每一行,它上一行的每一个点只能影响一个区间(可以假设下一行的都是0),而当前行也只能取一个区间的最小值(假设上一行全部是0)。或者说,我们思考的时候可以考虑在每一行之间插入一行0(两个参数都是0),这样做并不影响结果。这种区间赋值取区间最小值的东东,线段树正合适。复杂度降为O(nmlog(m))。
PS:这题的n有可能等于1,题目坑爹,为了这个我居然调了好久……
代码(1562MS):
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 using namespace std; 6 7 const int MAXN = 110; 8 const int MAXM = 5010; 9 const int INF = 0x3f3f3f3f; 10 11 int high[MAXN][MAXM], siz[MAXN][MAXM]; 12 int n, m; 13 14 int tree[MAXM * 4], mint[MAXM * 4]; 15 16 inline void update_min(int &a, const int &b) { 17 if(a > b) a = b; 18 } 19 20 inline void pushdown(int x) { 21 int ll = x << 1, rr = ll ^ 1; 22 update_min(tree[ll], tree[x]); 23 update_min(tree[rr], tree[x]); 24 update_min(mint[ll], tree[ll]); 25 update_min(mint[rr], tree[rr]); 26 } 27 28 inline void update(int x) { 29 int ll = x << 1, rr = ll ^ 1; 30 mint[x] = min(mint[ll], mint[rr]); 31 } 32 33 void update(int x, int left, int right, int L, int R, int val) { 34 if(L <= left && right <= R) { 35 update_min(tree[x], val); 36 update_min(mint[x], val); 37 } 38 else { 39 pushdown(x); 40 int ll = x << 1, rr = ll ^ 1; 41 int mid = (left + right) >> 1; 42 if(L <= mid) update(ll, left, mid, L, R, val); 43 if(mid < R) update(rr, mid + 1, right, L, R, val); 44 update(x); 45 } 46 } 47 48 int query(int x, int left, int right, int L, int R) { 49 if(L <= left && right <= R) return mint[x]; 50 else { 51 pushdown(x); 52 int ll = x << 1, rr = ll ^ 1; 53 int mid = (left + right) >> 1, ret = INF; 54 if(L <= mid) update_min(ret, query(ll, left, mid, L, R)); 55 if(mid < R) update_min(ret, query(rr, mid + 1, right, L, R)); 56 return ret; 57 } 58 } 59 60 int solve() { 61 for(int i = 2; i <= n; ++i) { 62 memset(tree, 0x3f, sizeof(tree)); 63 memset(mint, 0x3f, sizeof(mint)); 64 for(int j = 1; j <= m; ++j) 65 update(1, 1, m, max(1, j - siz[i - 1][j]), min(m, j + siz[i - 1][j]), high[i - 1][j]); 66 for(int j = 1; j <= m; ++j) 67 high[i][j] += query(1, 1, m, max(1, j - siz[i][j]), min(m, j + siz[i][j])); 68 } 69 int ret = INF; 70 for(int i = 1; i <= m; ++i) update_min(ret, high[n][i]); 71 return ret; 72 } 73 74 int main () { 75 while(scanf("%d%d", &n, &m) != EOF) { 76 if(n == 0 && m == 0) break; 77 for(int i = 1; i <= n; ++i) 78 for(int j = 1; j <= m; ++j) scanf("%d", &high[i][j]); 79 for(int i = 1; i <= n; ++i) 80 for(int j = 1; j <= m; ++j) scanf("%d", &siz[i][j]); 81 printf("%d\n", solve()); 82 } 83 }