标签:
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