設$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(nm\log 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; }