/**//* 题意:n行m列 n<=100 , m<=5000 每一个位置有值T[i][j] , F[i][j] 现要在每一行都找一个点来建站,其需要花费的时间为T[i][j] 有一个要求: if we build a tower in cell (i,j) and another tower in cell (i+1,k), then we shall have |j-k|≤f(i,j)+f(i+1,k). 求最少时间 dp[i,j] = min{dp[i+1,k]} +T[i,j] O(nm^2)是不行的 |j-k| ≤ f(i,j)+f(i+1,k) 等价于 j-f(i,j) <= k + f(i+1,k) 且 j+f(i,j) >= k - f(i+1,k) 对于行i可先按照j+f(i,j)排序,然后检查每个j,把所有满足j+f(i,j) >= k - f(i+1,k)的k都加进去 对这些k找出满足 j-f(i,j) <= k + f(i+1,k)的最小的dp[i+1,k]即可 找最小,用线段树(需要离散化) 对于一行,每个k只会加进去一次 总的复杂度是O(nmlogm) */ #include<iostream> #include<cstring> #include<algorithm>
using namespace std;
const int INF = 1000000000; const int MAX = 5000;
//#define G(i,x) ((x)-F[i][x]) //#define H(i,x) ((x)+F[i][x])
int T[100][5000],F[100][5000]; int dp[2][5000]; int G[5000] , H[5000] , index1[5000] , index2[5000]; int N , M;
bool cmpG(const int &a , const int &b) { return G[a] < G[b]; } bool cmpH(const int &a , const int &b) { return H[a] < H[b]; }
int Min[MAX*4];
void insert(int p , int left , int right , int pos , int val) { if(Min[p] > val)Min[p] = val; if(left == right)return; int mid = (left+right)>>1; if(pos <= mid)insert(2*p , left , mid , pos , val); else insert(2*p+1 , mid+1 , right , pos , val); }
int query(int p , int left , int right , int l , int r) { if(l <= left && right <= r)return Min[p]; int mid = (left+right)>>1; if(r <= mid)return query(2*p , left , mid , l , r); if( l > mid )return query(2*p+1 , mid+1 , right , l , r); return min(query(2*p , left , mid , l , mid) , query(2*p+1, mid+1 , right , mid+1 , r)); }
#define getPos(x) (lower_bound(compress,compress+num,(x))-compress)
int main() { while(scanf("%d%d",&N,&M),N||M) { for(int i = 0 ; i < N ; i++) for(int j = 0 ; j < M ; j ++) { scanf("%d",&T[i][j]); } for(int i = 0 ; i < N ; i++) for(int j = 0 ; j < M ; j ++) { scanf("%d",&F[i][j]); }
int pre = 0 , now = 1; for(int j = 0 ; j < M ; j++) { dp[pre][j] = T[N-1][j]; } for(int i = N - 2 ; i >= 0 ; i --) { for(int j = 0 ; j < M ; j ++) { H[j] = j + F[i][j]; index1[j] = j; } sort(index1 , index1 + M , cmpH);
for(int k = 0 ; k < M ; k ++) { G[k] = k - F[i+1][k]; index2[k] = k; } sort(index2 , index2 + M , cmpG); //离散化 static int compress[5000]; for(int k = 0 ; k < M ; k ++) compress[k] = k + F[i+1][k]; sort(compress,compress+M); int num = unique(compress , compress+M) - compress;
fill(Min,Min+num*4 , INF);
for(int jj = 0 , kk = 0; jj <M ; jj++) { int j = index1[jj] , k; // j + F[i,j] >= k - F[i+1][k] while(kk < M && G[k=index2[kk]] <= H[j] ) { kk++; insert(1 ,0 , num , getPos(k+F[i+1][k]) , dp[pre][k] ); } //j-F[i,j] <= k+F[i+1,k] dp[now][j] = query(1 , 0 , num , getPos(max(0,j-F[i][j])) , num) + T[i][j]; } swap(pre,now); } printf("%d\n",*min_element(dp[pre],dp[pre]+M)); } return 0; }
|