首页 > 其他分享 >CF1753D 题解

CF1753D 题解

时间:2024-02-01 14:58:47浏览次数:22  
标签:格子 get int 题解 ll CF1753D ans dis

因为最后要找的是“腾出空位”的最小代价。

所以不妨把“障碍的移动”转化为“空位的移动”。

令 \(f_{x,y}\) 为:使得 \((x,y)\) 为空,至少需要多少代价。

下面来找转移方程,显然转移方程与空格子移动有关。所以观察空格子移动的规律。

若当前格子 \((x,y)\) 为 L

  • 以 \((x,y+1)\) 为顶点顺时针或逆时针旋转当前障碍,就可以使 \((x,y)\) 格子变为空。

上图中,粉色格子为当前障碍,白色格子为空。如果按逆时针旋转90度,粉色障碍就会发生如上的变化,那么右下角的空格子就会移动到左上角。所以从有 \(f_{x,y}=f_{x+1,y+1}+p\)。同理,如果按顺时针旋转90度,\((x+1,y-1)\) 的空格子可以移动到 \((x,y)\)(读者不妨在草稿本上自己画一下图)。所以有 \(f_{x,y}=f_{x+1,y-1}+p\)。

  • 如果把当前障碍整体向右平移一格,那么 \((x,y+2)\) 的格子可以移动到 \((x,y)\),所以有式子 \(f_{x,y}=f_{x,y+2}+q\)。

现在把三个式子合并起来,取最小值,就是 \(f_{x,y}=\min(f_{x+1,y-1}+p,f_{x+1,y+1}+p,f_{x,y+2})\)。我们现在就已经得到了当前格子为 L 的转移。

另外三种障碍的情况也差不多,画一画图就能写出式子。注意 # 的情况设为 \(inf\),. 的情况设为 \(0\).


好了我们已经 DP 式子了,但是怎我们找不到一个合适的顺序取遍历所有格子呀?一个常见的 trick 是把 DP 转化成图论问题。

如果有 \(f_{x,y}=f_{x',y'}+v\)。那么就从 \((x',y')\) 向 \((x,y)\) 连一条值为 \(v\) 的边,最后在整个图上跑最短路就可以了。

一个小细节,在实现代码时可以建立虚拟源点 \(s\)。如果我们把 \(f_{x,y}\) 设为 \(0\),就从 \(s\) 向 \((x,y)\) 连接一条值为 \(0\) 的边。

Code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=3e5+5;
int n,m,p,q;
struct node{int to;ll w;};
bool operator <(const node &x,const node &y){return x.w>y.w;}
vector<node> G[MAXN];
ll dis[MAXN];
bool vis[MAXN];
void dij(){
    priority_queue<node> q;
    q.push({0,0});
    memset(dis,0x3f,sizeof(dis));
    dis[0]=0;
    while(!q.empty()){
        int u=q.top().to;q.pop();
        if(vis[u])  continue;
        vis[u]=1;
        for(node t:G[u]){
            int v=t.to;
            if(dis[v]>dis[u]+t.w){
                dis[v]=dis[u]+t.w;
                q.push({v,dis[v]});
            }
        }
    }
}
int dir[8][2]={{0,1},{0,-1},{1,0},{-1,0}};
const ll INF=0x3f3f3f3f3f3f3f3f;
int main(){
    #ifndef ONLINE_JUDGE
        freopen(".in","r",stdin);
        freopen(".out","w",stdout);
    #endif
    scanf("%d%d%d%d\n",&n,&m,&p,&q);
    vector<string> mp(n);
    for(int i=0;i<n;i++)   cin>>mp[i];
    auto get=[&](int x,int y)->int {return x*m+y+1;};
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            
            auto link=[&](int x,int y,int w)->void {
                if(x<0||y<0||x>=n||y>=m)    return;
                G[get(x,y)].push_back({get(i,j),1ll*w});
                // cerr<<get(i,j)<<" "<<get(x,y)<<" "<<w<<endl;
            };

            if(mp[i][j]=='L')   link(i-1,j+1,p),link(i+1,j+1,p),link(i,j+2,q);
            if(mp[i][j]=='R')   link(i-1,j-1,p),link(i+1,j-1,p),link(i,j-2,q);
            if(mp[i][j]=='U')   link(i+1,j-1,p),link(i+1,j+1,p),link(i+2,j,q);
            if(mp[i][j]=='D')   link(i-1,j-1,p),link(i-1,j+1,p),link(i-2,j,q);
            if(mp[i][j]=='.')   G[0].push_back({get(i,j),0});
        }
    }
    dij();
    ll ans=INF;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            for(int k=0;k<4;k++){
                int di=i+dir[k][0],dj=j+dir[k][1];
                if(di<0||di>=n||dj<0||dj>=m)    continue;
                ans=min(ans,dis[get(i,j)]+dis[get(di,dj)]);
            }
        }
    }
    if(ans==INF)    ans=-1;
    printf("%lld",ans);
    return 0;
}

标签:格子,get,int,题解,ll,CF1753D,ans,dis
From: https://www.cnblogs.com/bwartist/p/18001194

相关文章

  • P7031 [NWRRC2016] Anniversary Cake 题解
    作者还在想,居然没什么人写红题题解???咳咳。言归正传。本题没有想象中的那么复杂,咱分类讨论就行了。·若在属于蛋糕的平面直角坐标系中,两支蜡烛的横、纵轴不同,就会有多种切法。如图:           这样,我们随便找一种情况输出就行,反正有SpecialJudge......
  • A+B problem 题解
    先把一个单项式理解为:符号,系数的绝对值,字母,指数。为了方便操作,一口气读完整个字符串(数组),然后去扫描。因为如果第一项为整数的话没有符号,判一判。读入系数的绝对值像快读。如果有\(\texttt{^}\)这个符号,读一下之后的指数。由于只有三个字母,所以可以复制粘贴,不用写冗余的......
  • CEIT算法训练-双指针部分题解(T1-3)
    AnagramSearch题意简述两个字符串\(s\)和\(t\)相似的定义为:\(s\)可以打乱之后重新排列成为\(t\)。题目给出\(a\)和\(b\),问\(a\)中有多少子串(连续的一段)与\(b\)相似。同时,\(a\)中还含有\(?\)字符,他可以等价于任何字符(可以变成任何字符)解题思路实际上,根据题......
  • 题解 P6491 [COCI2010-2011#6] ABECEDA
    传送门。分析两个字符大小关系不变,并且具有传递性,我们可以联想到拓扑排序来解决。因此,我们就通过字符串的大小关系,推断出一些字符的大小关系,然后拓扑排序即可。#include<bits/stdc++.h>#include<vector>#include<string>#include<queue>//#defineintlonglongusing......
  • [ARC154E] Reverse and Inversion 题解
    题目链接点击打开链接题目解法\(\sumj-i\)是不好维护的,考虑把\(j-i\)拆成之和\(i,j\)相关的项可以得到:\(\sum\limits_{i<j}[p_i>p_j](j-i)=\sum\limits_{i=1}^ni(\sum\limits_{j=1}^{i-1}[p_j>p_i]-\sum\limits_{j=i+1}^n[p_j<p_i])=\sum\limits_{i=1}^ni(i-1-\sum\......
  • [AGC024E] Sequence Growing Hard 题解
    题目链接点击打开链接题目解法考虑如何添加数,使得\(\{a_1,...,a_i\}\)到\(\{a_1,...,x,a_j,...,a_i\}\)是合法的需要手玩一会才能发现合法条件很简单:\(x>a_j\)考虑对这个进行计数一个一个添元素是难维护的,现在假设有最终的序列,每个位置有\((v,dfn)\),分别为值和添加的次......
  • CF813E Army Creation 题解
    题目链接:CF或者洛谷并不是很难的题,关于颜色数量类问题,那么很显然,沿用经典的"HH的项链"思想去思考问题。由于涉及到了\(k\)个数的限制,我们观察到如果一个数在一个区间上有区间贡献:其中\(x_k\)表示为当前\(x\)的第前\(k+1\)个数,换句话来讲,\(x_k\)到当前的\(x\)所......
  • The XOR-longest Path 题解
    我们观察题干知道此题为单调递增(节点),这样我们就不用跑dfs了很显然的一件事是两点间的权值只与子节点有关所以我们用w1[v]=w1[u]*w就能更新v到根节点的权值然后我们循环放入字典树,再取最大的(由于这题数据特别水,所以没算v-u的w1)#include<bits/stdc++.h>usingnamespacestd;in......
  • 题解 P7309 [COCI2018-2019#2] Kocka
    传送门。题意一个$N\timesN$的矩形,有从四周往内望去的第一个位置的距离,问是否存在一个矩形满足我们的观察。分析先说说我这个蒟蒻想出来的巨麻烦的方法。首先先判断最简单的矛盾,就是左右穿插,上下穿插,这是第一步。//-1变成nfor(inti=1;i<=n;++i)if(L[i]+R[i]>=n)......
  • 题解 P6548 [COCI2010-2011#2] IGRA
    传送门。题意有\(A\),\(B\)两个人,有一个含\(n\)个字符的字符串。\(A\)始终取最右侧的字符,\(B\)可以取任意一个字符,问\(B\)所取的字符串能否胜过\(A\),以及\(B\)能取的最大字符串。分析首先,我们\(A\)肯定会选择当前的最小的字符,我们就可以先把字符按大小排序,字符相......