P6797 「StOI-2」不朽的逃亡者

\(\mathcal Link\)

学长的题。

考虑到全都变成 \(0\) 相当于从矩形外的左上部分区域直接到达矩形中的位置。

将问题转化为:从 \((0,0)\)\((n,m)\),最多跳 \(w\) 步,最少危险值。

\(f(i,j,k)\) 表示到 \((i,j)\) 时经过 \(k\) 个矩形。

显然有两种转移:

  • \(f(i,j,k)=\min(f(i-1,j,k),f(i,j-1,k))+d_{i,j}\)
  • \(f(i,j,k)=\min\{f(i',j',k-1)\mid (i',j')\textbf{ 是矩形边框向外一格且该矩形包含 } (i,j)\}\)

只需要考虑左边框和上边框,因此用两个堆分别维护。

\(qx[i][k]\) 表示所有横坐标为 \(i\) 的竖直外框区域的 \(\min\{f(i,j,k)\}\) 的集合。

\(qy[j][k]\) 同理。

\(mn1[i][k]、mn2[i][k]\) 来表示第 \(i\) 个矩形外框的信息。

然后动态更新即可。

注意 \(k\) 要从大往小枚举,否则可能会导致 \(f(i,j,k)\) 被一个行为 \(i\) 的竖边框或列为 \(j\) 的横边框更新(因为只判断了下边界和右边界)。

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
char buf[1<<14],*p1=buf,*p2=buf;
#define GetC() ((p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<14,stdin),p1==p2)?EOF:*p1++)
struct Ios{}io;
template <typename _tp>
Ios &operator >>(Ios &in,_tp &x){
    x=0;int w=0;char c=GetC();
    for(;!isdigit(c);w|=c=='-',c=GetC());
    for(;isdigit(c);x=x*10+(c^'0'),c=GetC());
    if(w) x=-x;
    return in;
}
using ll=long long;
const int N=205,M=105;
int d[N][N];
ll dp[N][N][M];
int ax[N],ay[N],bx[N],by[N];
vector<ll> v1[N][N],v2[N][N];
#define pb push_back 
struct qwq{int lim;ll s;};
bool operator <(qwq x,qwq y){return x.s>y.s;}
priority_queue<qwq> qx[N][M],qy[N][M];
ll mn1[N][M],mn2[N][M];
int main(){
    int n,m,_,w;io>>n>>m>>_>>w;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            io>>d[i][j];
    memset(mn1,0x3f,sizeof(mn1));
    memset(mn2,0x3f,sizeof(mn2));
    for(int i=1;i<=_;++i){
        io>>ax[i]>>bx[i]>>ay[i]>>by[i];
        if(ax[i]==1&&ay[i]==1){
            for(int j=ax[i];j<=bx[i];++j)
                for(int k=0;k<=w;++k) qx[j][k].push((qwq){by[i],0});
            for(int j=ay[i];j<=by[i];++j)
                for(int k=0;k<=w;++k) qy[j][k].push((qwq){bx[i],0});
        }
        for(int j=ax[i];j<=bx[i];++j) v1[j][ay[i]-1].pb(i);
        for(int j=ay[i];j<=by[i];++j) v2[ax[i]-1][j].pb(i);
    }
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            for(int k=w;~k;--k){
                if(i!=1&&j!=1) dp[i][j][k]=d[i][j]+min(dp[i-1][j][k],dp[i][j-1][k]);
                else if(j!=1) dp[i][j][k]=d[i][j]+dp[i][j-1][k];
                else if(i!=1) dp[i][j][k]=d[i][j]+dp[i-1][j][k];
                else dp[i][j][k]=d[i][j];
                while(!qx[i][k-1].empty()&&qx[i][k-1].top().lim<j) qx[i][k-1].pop();
                while(!qy[j][k-1].empty()&&qy[j][k-1].top().lim<i) qy[j][k-1].pop();
                if(k>0){
                    if(!qx[i][k-1].empty()) dp[i][j][k]=min(dp[i][j][k],qx[i][k-1].top().s);
                    if(!qy[j][k-1].empty()) dp[i][j][k]=min(dp[i][j][k],qy[j][k-1].top().s);
                }
                for(auto tmp:v1[i][j]){
                    mn1[tmp][k]=min(mn1[tmp][k],dp[i][j][k]);
                    qx[i][k].push((qwq){by[tmp],mn1[tmp][k]});
                }
                for(auto tmp:v2[i][j]){
                    mn2[tmp][k]=min(mn2[tmp][k],dp[i][j][k]);
                    qy[j][k].push((qwq){bx[tmp],mn2[tmp][k]});
                }
            }
        }
    }
    ll ans=1e18;
    for(int i=0;i<=w;++i) ans=min(ans,dp[n][m][i]);
    printf("%lld\n",ans);
    return 0;
}
posted @ 2022-11-07 21:00  pref_ctrl27  阅读(32)  评论(0编辑  收藏  举报