hdu3698 Let the light guide us(dp+线段树)

题意:在每行上选一个点,每个点都要各自对应的代价,同时相邻两行的点要满足 |j-k|≤f(i,j)+f(i+1,k)。问最小代价是多少。

 

题解:

不难发现这是一道dp,状态转移方程如下$dp[i][j]=min\{dp[i-1][k]\}+t[i][j](|j-k|≤f(i,j)+f(i+1,k))$

然而如果直接进行转移是要T飞的

所以如何快速求$k$呢?

可以发现,$dp[i-1][k]$只会对一个区间的答案产生影响,而$dp[i][j]$的答案必定是一个区间中的最小值加上自己的时间

于是就是区间修改和区间查询了,之间上线段树

ps:因为$dp$数组每一行都会更新,实际上可以省掉第一维的空间

 1 //minamoto
 2 #include<cstdio>
 3 #include<iostream>
 4 using namespace std;
 5 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 6 char buf[1<<21],*p1=buf,*p2=buf;
 7 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
 8 inline int read(){
 9     #define num ch-'0'
10     char ch;bool flag=0;int res;
11     while(!isdigit(ch=getc()))
12     (ch=='-')&&(flag=true);
13     for(res=num;isdigit(ch=getc());res=res*10+num);
14     (flag)&&(res=-res);
15     #undef num
16     return res;
17 }
18 char sr[1<<21],z[20];int C=-1,Z;
19 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
20 inline void print(int x){
21     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
22     while(z[++Z]=x%10+48,x/=10);
23     while(sr[++C]=z[Z],--Z);sr[++C]='\n';
24 }
25 const int N=105,M=5005,inf=0x3f3f3f3f;
26 int t[N][M],f[N][M],dp[M],sum[M<<2],add[M<<2];
27 int n,m;
28 void pushdown(int p){
29     if(add[p]!=inf){
30         cmin(add[p<<1],add[p]),cmin(add[p<<1|1],add[p]);
31         cmin(sum[p<<1],add[p<<1]),cmin(sum[p<<1|1],add[p<<1|1]);
32         add[p]=inf;
33     }
34 }
35 void build(int l,int r,int p){
36     sum[p]=add[p]=inf;
37     if(l==r) return;
38     int mid=l+r>>1;
39     build(l,mid,p<<1),build(mid+1,r,p<<1|1);
40 }
41 void update(int ql,int qr,int x,int l,int r,int p){
42     if(ql<=l&&qr>=r){
43         cmin(add[p],x),cmin(sum[p],add[p]);return;
44     }
45     int mid=l+r>>1;
46     pushdown(p);
47     if(ql<=mid) update(ql,qr,x,l,mid,p<<1);
48     if(qr>mid) update(ql,qr,x,mid+1,r,p<<1|1);
49     sum[p]=min(sum[p<<1],sum[p<<1|1]);
50 }
51 int query(int ql,int qr,int l,int r,int p){
52     if(ql<=l&&qr>=r) return sum[p];
53     int mid=l+r>>1;
54     pushdown(p);
55     int res=inf;
56     if(ql<=mid) cmin(res,query(ql,qr,l,mid,p<<1));
57     if(qr>mid) cmin(res,query(ql,qr,mid+1,r,p<<1|1));
58     return res;
59 }
60 int main(){
61     //freopen("testdata.in","r",stdin);
62     while(true){
63         n=read(),m=read();
64         if(n==0&&m==0) break;
65         for(int i=1;i<=n;++i)
66         for(int j=1;j<=m;++j)
67         t[i][j]=read();
68         for(int i=1;i<=n;++i)
69         for(int j=1;j<=m;++j)
70         f[i][j]=read();
71         for(int i=1;i<=m;++i) dp[i]=t[1][i];
72         for(int i=2;i<=n;++i){
73             build(1,m,1);
74             for(int j=1;j<=m;++j)
75             update(j-f[i-1][j],j+f[i-1][j],dp[j],1,m,1);
76             for(int j=1;j<=m;++j)
77             dp[j]=query(j-f[i][j],j+f[i][j],1,m,1)+t[i][j];
78         }
79         int ans=inf;
80         for(int i=1;i<=m;++i) cmin(ans,dp[i]);
81         print(ans);
82     }
83     Ot();
84     return 0;
85 }

 

posted @ 2018-08-12 12:40  bztMinamoto  阅读(272)  评论(0编辑  收藏  举报
Live2D