BZOJ1481 : Navigation Game

设$f[i][j][k]$表示从最后一行某个$H$走到$(i,j)$且在第$i$行只经过了$(i,j)$,途中经过了$k$次$F$的最小代价。

$A[i][j][k]$表示从下一行$leq i$的某个$f[old][x][j]$且前$x-1$个有$k$个$F$的位置走过来的最小代价。

$B[i][j][k]$表示从下一行$geq i$的某个$f[old][x][j]$且前$x$个有$k$个$F$的位置走过来的最小代价。

$A$和$B$的转移都具有决策单调性,分治求解即可。然后用$A$和$B$计算当前行的$f$。

时间复杂度$O(nmlog m)$。

#include<cstdio>
const int N=1010,inf=~0U>>1;
int n,m,M,i,j,k,x,y,f[N][N][2],v[N][N],ans=inf;
int A[N][2][2],B[N][2][2],g[N][2],so[N],sf[N],s1[N],s2[N];
char a[N][N];
inline void up(int&x,int y){if(x>y)x=y;}
void getA(int l,int r,int dl,int dr){
  int m=(l+r)>>1,dm=m,&ret=A[m][x][y];
  if(dm<dl)dm=dl;
  if(dm>dr)dm=dr;
  ret=inf;
  for(int i=dl;i<=dr&&i<=m;i++){
    if(g[i][x]==inf||sf[i-1]!=y||so[m]>so[i-1])continue;
    int t=g[i][x]+s1[m]-s1[i-1]-(s2[m]-s2[i-1])*i;
    if(t<ret)ret=t,dm=i;
  }
  if(l<m)getA(l,m-1,dl,dm);
  if(r>m)getA(m+1,r,dm,dr);
}
void getB(int l,int r,int dl,int dr){
  int m=(l+r)>>1,dm=m,&ret=B[m][x][y];
  if(dm<dl)dm=dl;
  if(dm>dr)dm=dr;
  ret=inf;
  for(int i=dr;i>=dl&&i>=m;i--){
    if(g[i][x]==inf||sf[i]!=y||so[i]>so[m-1])continue;
    int t=g[i][x]-s1[i]+s1[m-1]+(s2[i]-s2[m-1])*i;
    if(t<ret)ret=t,dm=i;
  }
  if(l<m)getB(l,m-1,dl,dm);
  if(r>m)getB(m+1,r,dm,dr);
}
int main(){
  scanf("%d%d",&n,&m);M=m;
  for(i=1;i<=n;i++)scanf("%s",a[i]+1);
  for(j=1;j<=m;j++){
    if(a[1][j]=='.')a[1][j]='O';
    if(a[n][j]=='.')a[n][j]='O';
  }
  for(i=1;i<=n;i++)for(j=1;j<=m;j++){
    v[i][j]=1;
    if(a[i][j]=='B')v[i][j]=0;
    if(a[i][j]=='S')v[i][j]=2;
  }
  for(i=1;i<=n;i++)for(j=1;j<=m;j++)for(k=0;k<2;k++)f[i][j][k]=inf;
  for(j=1;j<=m;j++)if(a[n][j]=='H')f[n][j][0]=0;
  for(i=n-1;i;i--){
    for(j=1;j<=m;j++){
      so[j]=so[j-1]+(a[i+1][j]=='O');
      sf[j]=sf[j-1]^(a[i+1][j]=='F');
      s1[j]=s1[j-1]+j*v[i+1][j];
      s2[j]=s2[j-1]+v[i+1][j];
      for(k=0;k<2;k++)g[j][k]=f[i+1][j][k];
    }
    for(x=0;x<2;x++)for(y=0;y<2;y++)getA(1,m,1,m);
    for(x=0;x<2;x++)for(y=0;y<2;y++)getB(1,m,1,m);
    for(j=1;j<=m;j++)if(a[i][j]!='O')for(x=0;x<2;x++)for(y=0;y<2;y++){
      up(f[i][j][x^y^sf[j]],A[j][x][y]);
      up(f[i][j][x^y^sf[j-1]],B[j][x][y]);
    }
    for(j=1;j<=m;j++)for(k=0;k<2;k++)if(f[i][j][k]<inf)f[i][j][k]+=v[i][j];
  }
  for(j=1;j<=m;j++)up(ans,f[1][j][1]);
  if(ans<inf)printf("%d",ans);else puts("Victory of Darkness");
  return 0;
}

  

原文地址:https://www.cnblogs.com/clrs97/p/5790857.html