标签:
http://acm.hdu.edu.cn/showproblem.php?pid=3698
3 5 9 5 3 8 7 8 2 6 8 9 1 9 7 8 6 0 1 0 1 2 1 0 2 1 1 0 2 1 0 2 0 0
10
题意:就是每行选一个,上下两行需满足|j-k|≤f(i,j)+f(i+1,k).,问最小的cell和值。
分析:明显的dp,dp[i][j]表示到第i行选第j个的值,可是这样转移复杂度须要n*m*m,肯定会超时。
我们注意到|j-k|<=f(i,j)+f(i-1,k),那么对于i-1行的第k个我们更新[k-f(i-1,k),k+f(i-1,k)],对于第i行查询[j-f(i,j),j+f(i,j)],这样刚好满足的是要求的条件。
所以就用线段树维护一下查询区间最小值更新区间值就好。这样复杂度就是n*m*log(m)。。
/** * @author neko01 */ //#pragma comment(linker, "/STACK:102400000,102400000") #include <cstdio> #include <cstring> #include <string.h> #include <iostream> #include <algorithm> #include <queue> #include <vector> #include <cmath> #include <set> #include <map> using namespace std; typedef long long LL; #define min3(a,b,c) min(a,min(b,c)) #define max3(a,b,c) max(a,max(b,c)) #define pb push_back #define mp(a,b) make_pair(a,b) #define clr(a) memset(a,0,sizeof a) #define clr1(a) memset(a,-1,sizeof a) #define dbg(a) printf("%d\n",a) typedef pair<int,int> pp; const double eps=1e-8; const double pi=acos(-1.0); const int INF=0x7fffffff; const LL inf=(((LL)1)<<61)+5; const int N=105; const int M=5005; int a[N][M]; int f[N][M]; int dp[N][M]; struct node{ int l,r; int Min; int col; }tree[M*4]; void build(int x,int l,int r) { tree[x].l=l,tree[x].r=r; tree[x].Min=INF; tree[x].col=INF; if(l==r) return; int mid=(l+r)>>1; build(x<<1,l,mid); build(x<<1|1,mid+1,r); } inline void push_down(int x) { if(tree[x].col!=INF) { tree[x<<1].col=min(tree[x].col,tree[x<<1].col); tree[x<<1|1].col=min(tree[x<<1|1].col,tree[x].col); tree[x<<1].Min=min(tree[x].col,tree[x<<1].Min); tree[x<<1|1].Min=min(tree[x].col,tree[x<<1|1].Min); tree[x].col=INF; } } void update(int x,int l,int r,int val) { if(tree[x].l==l&&tree[x].r==r) { tree[x].Min=min(tree[x].Min,val); tree[x].col=min(tree[x].col,val); return; } push_down(x); int mid=(tree[x].l+tree[x].r)>>1; if(r<=mid) update(x<<1,l,r,val); else if(l>mid) update(x<<1|1,l,r,val); else { update(x<<1,l,mid,val); update(x<<1|1,mid+1,r,val); } tree[x].Min=min(tree[x<<1].Min,tree[x<<1|1].Min); } int query(int x,int l,int r) { if(tree[x].l==l&&tree[x].r==r) return tree[x].Min; push_down(x); int mid=(tree[x].l+tree[x].r)>>1; if(r<=mid) return query(x<<1,l,r); else if(l>mid) return query(x<<1|1,l,r); else return min(query(x<<1,l,mid),query(x<<1|1,mid+1,r)); } int main() { int n,m; while(~scanf("%d%d",&n,&m)) { if(n==0&&m==0) break; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { scanf("%d",&a[i][j]); if(i==1) dp[1][j]=a[i][j]; } } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&f[i][j]); for(int i=2;i<=n;i++) { build(1,1,m); for(int j=1;j<=m;j++) { int l=max(1,j-f[i-1][j]); int r=min(m,j+f[i-1][j]); update(1,l,r,dp[i-1][j]); } for(int j=1;j<=m;j++) { int l=max(1,j-f[i][j]); int r=min(m,j+f[i][j]); dp[i][j]=query(1,l,r)+a[i][j]; } } int ans=INF; for(int i=1;i<=m;i++) ans=min(ans,dp[n][i]); printf("%d\n",ans); } return 0; }
hdu3698 Let the light guide us dp+线段树优化
标签:
原文地址:http://www.cnblogs.com/gcczhongduan/p/4296295.html