天天看點

LA5106: Let the light guide usLA5106: Let the light guide us

LA5106: Let the light guide us

Dp·樹狀數組

題解:

裸方程:

當 |j−k|<=magic[i−1][k]+magic[i][j] 時,

f[i][j]=min{f[i−1][k]}+cost[i][j]

時間複雜度: O(nm2) .

優化一下。像這種有絕對值的一定是規定大小,把絕對值去掉,然後正反做兩遍。

k<=j,k−magic[i−1][k]<=j+magic[i][j]

然後用bit維護最小值即可。詳見代碼。

時間複雜度: O(nmlogm) .

說一下我犯的zz錯誤:

1.先正着跑完所有行在反着跑所有行。。。

2.reverse沒寫足,有的沒reverse回來。。。

Code:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
//#define debug
#ifdef debug
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
#else
    #define D(x)
    #define E
#endif
using namespace std;
const int N = ;
const int mxn = ;
const int INF = ;

int n,m,cost[][N],magic[][N],f[N],g[N],res[N],ans; 

struct BIT{
    int c[mxn+], sz;
    void init(int _sz){ sz=_sz; memset(c,,sizeof(c)); }
    void ins(int x,int d){ if(x<)x=; while(x<=sz){ c[x]=min(c[x],d); x+=x&(-x); } }
    void clear(int x){ if(x<)x=; while(x<=sz){ c[x]=INF; x+=x&(-x); } }
    int mn(int x){ int ans=INF; while(x>){ ans=min(ans,c[x]); x-=x&(-x); } return ans; }
} bit;


void dp(int i,int f[N]){
//  printf("dp: \n");
    for(int j=m;j>=;j--){
        D(i); D(j); E;
//      printf("ins: pos=%d  d=%d\n",j-magic[i-1][j],res[j]);
        bit.ins(j-magic[i-][j],res[j]);
        D(j+magic[i][j]); D(bit.mn(j+magic[i][j])); E;
        f[j]=bit.mn(j+magic[i][j])+cost[i][j];
        D(f[j]); E;
    }
    for(int j=;j<=m;j++) bit.clear(j-magic[i-][j]);
}

int main(){
    freopen("a.in","r",stdin);
#ifndef debug
    freopen("a.out","w",stdout);
#endif
    while(scanf("%d%d",&n,&m), n||m){
        D(n); D(m); E;
        for(int i=;i<=n;i++)for(int j=;j<=m;j++) scanf("%d",&cost[i][j]);
        for(int i=;i<=n;i++)for(int j=;j<=m;j++) scanf("%d",&magic[i][j]);
        bit.init(mxn); for(int i=;i<=m;i++)res[i]=cost[][i];
        for(int i=;i<=n;i++){
            memset(f,,sizeof(f)); memset(g,,sizeof(g));
            dp(i,f); 
            reverse(cost[i]+,cost[i]++m); 
            reverse(magic[i]+,magic[i]++m);
            reverse(magic[i-]+,magic[i-]++m);
            reverse(res+,res++m);
            dp(i,g);
            reverse(magic[i]+,magic[i]++m);
            reverse(res+,res++m);
            for(int j=;j<=m;j++)res[j]=min(f[j],g[m-j+]);
        }
        ans=INF; for(int j=;j<=m;j++) ans=min(ans,res[j]);
        printf("%d\n",ans); 
    }
}