CF1753D The Beach
题目简意
一个 \(n\times m\) 的网格图,有的格子有障碍,有的格子为空,有的格子上有床(床占上下左右相邻的两格)。现在你可以执行两种操作:
-
将一个床旋转一格,操作代价为 \(p\)。
-
将一个床沿它的方向平移一格,操作代价为 \(q\) 。
形式化地定义旋转一格和平移一格:设床所占的两格坐标是 \(\{(x_1,y_1),(x_2,y_2)\}(|x_1-x_2|+|y_1-y_2|=1)\) ,旋转一格后床所占的两格坐标是 \(\{(x_1,y_1),(x_3,y_3)\}(|x_1-x_3|+|y_1-y_3|=1,|x_2-x_3|=1,|y_2-y_3|=1)\),平移一格后床所占的两格坐标是 \(\{(x_1,y_1),(x_3,y_3)\}(|x_1-x_3|+|y_1-y_3|=1,\max(|x_2-x_3|,|y_2-y_3|)=2)\)。需要保证每次操作后,床所在的格子没有障碍。
现在你要再往网格图里加一张床,问最少的操作代价是多少,若无解输出 \(-1\)。
\(1\le n, m\le 3\times10^5,1\le n\times m\le 3\times10^5,1\le p,q\le 10^9\)
题解
要加一张床,无非是通过一些操作使得空格凑在一起,那可以想到一个 dp :\(f_{i,j}\) 表示把 \((i,j)\) 这个格子变成空格子的最小代价。如果 \((i,j)\) 初始为空,那么 \(f(i,j)=0\) ;如果是障碍,那么 \(f(i,j)=+\infty\);如果是床,那么需要通过操作挪床。两个操作的本质都是固定床的一端,移动另一端,所以 \((i,j)\) 一定是挪动的一端,那转移就只有 \(3\) 种情况,分类讨论即可。
dp 顺序怎么办呢?容易发现这个 dp 相当于是一个最短路,直接以所有空格子为起点,跑多源 dij 即可。
答案就是 \(\min_{|x_1-x_2|+|y_1-y_2|=1}\{f_{x_1,y_1}+f_{x_2,y_2}\}\)。
直接实现就可以通过此题,但是有一个问题,这个题是要凑出两个空格子,而跑最短路的时候是跑的一个空格,那会不会出现最后的答案里,同一张床被操作两次的情况呢(显然是不合法的操作)?答案是否定的,因为一旦出现了这种情况,这张床周围至少有 \(2\) 个空格,那么最多只需要操作这张床一次就可以把两个空格挪到一起。即不合法的答案一定不优。
代码
#include <bits/stdc++.h>
#define re(i, x, y) for (int i = (x); i < (y); ++i)
#define rep(i, x, y) for (int i = (x); i <= (y); ++i)
#define repp(i, x, y, d) for (int i = (x); i <= (y); i += (d))
#define reep(i, x, y) for (int i = (x); i <= (y); i <<= 1)
#define pe(i, x, y) for (int i = (x) - 1; i >= (y); --i)
#define per(i, x, y) for (int i = (x); i >= (y); --i)
#define rep_e(i, u) for (int i = head[(u)]; i; i = e[i].nxt)
#define vi vector<int>
#define vL vector<LL>
#define vii vector<pii>
#define viL vector<piL>
#define vLi vector<pLi>
#define vLL vector<pLL>
#define eb emplace_back
#define pb pop_back
#define mp make_pair
#define pii pair<int, int>
#define piL pair<int, LL>
#define pLi pair<LL, int>
#define pLL pair<LL, LL>
#define lowbit(x) ((x) & (-(x)))
#define fi first
#define se second
#define all(x) x.begin(), x.end()
#define debug(x) cout << #x << " = " << x << endl
using namespace std;
typedef unsigned int ui;
typedef long long LL;
typedef unsigned long long ULL;
typedef double db;
#define getchar() (SB == TB && (TB = (SB = BB) + fread(BB, 1, 1 << 16, stdin), SB == TB) ? EOF : *SB++)
char BB[1 << 16], *SB = BB, *TB = BB;
template<typename T> void read(T &n) {
T w = 1;
n = 0;
char ch = getchar();
for ( ; !isdigit(ch); ch = getchar()) {
if (ch == '-') {
w = -1;
}
}
for ( ; isdigit(ch); ch = getchar()) {
n = n * 10 + (ch & 15);
}
n *= w;
}
template<typename T> void chkmn(T &a, const T &b) {
a = a > b ? b : a;
}
template<typename T> void chkmx(T &a, const T &b) {
a = a < b ? b : a;
}
int MOD;
int adt(const LL &a) {
return (a % MOD + MOD) % MOD;
}
int inc(const int &a, const int &b) {
return a + b >= MOD ? a + b - MOD : a + b;
}
int dec(const int &a, const int &b) {
return a - b < 0 ? a - b + MOD : a - b;
}
int mul(const int &a, const int &b) {
return 1LL * a * b % MOD;
}
int sqr(const int &a) {
return 1LL * a * a % MOD;
}
void Adt(LL &a) {
a = (a % MOD + MOD) % MOD;
}
void Inc(int &a, const int &b) {
a = a + b >= MOD ? a + b - MOD : a + b;
}
void Dec(int &a, const int &b) {
a = a - b < 0 ? a - b + MOD : a - b;
}
void Mul(int &a, const int &b) {
a = 1LL * a * b % MOD;
}
void Sqr(int &a) {
a = 1LL * a * a % MOD;
}
int fsp(int a, int x = MOD - 2) {
int res = 1;
for ( ; x; x >>= 1, Sqr(a)) {
if (x & 1) {
Mul(res, a);
}
}
return res;
}
const int maxn = 3e5 + 5, dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1};
const LL INF = 1e18;
int n, m, p, q;
LL dis[maxn];
bool vis[maxn];
string s[maxn];
struct node {
LL d;
int x, y;
node(LL d = 0, int x = 0, int y = 0) : d(d), x(x), y(y) {}
} d[maxn];
bool operator < (node x, node y) {
return x.d > y.d;
}
priority_queue<node> pq;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m >> p >> q;
auto id = [&] (int x, int y) {
return (x - 1) * m + y;
};
memset(dis, 0x3f, sizeof(dis));
rep(i, 1, n) {
cin >> s[i];
re(j, 0, m) {
if (s[i][j] == '.') {
dis[id(i, j + 1)] = 0;
pq.emplace(0, i, j + 1);
}
}
}
for ( ; !pq.empty(); ) {
int x = pq.top().x, y = pq.top().y;
pq.pop();
if (vis[id(x, y)]) {
continue ;
}
vis[id(x, y)] = 1;
re(i, 0, 4) {
int xx = x + dx[i], yy = y + dy[i];
if (xx >= 1 && yy >= 1 && xx <= n && yy <= m) {
if (s[xx][yy - 1] == 'L') {
int c = i < 2 ? p : q;
if (dis[id(xx, yy + 1)] > dis[id(x, y)] + c) {
dis[id(xx, yy + 1)] = dis[id(x, y)] + c;
pq.emplace(dis[id(xx, yy + 1)], xx, yy + 1);
}
}
else if (s[xx][yy - 1] == 'R') {
int c = i < 2 ? p : q;
if (dis[id(xx, yy - 1)] > dis[id(x, y)] + c) {
dis[id(xx, yy - 1)] = dis[id(x, y)] + c;
pq.emplace(dis[id(xx, yy - 1)], xx, yy - 1);
}
}
else if (s[xx][yy - 1] == 'D') {
int c = i < 2 ? q : p;
if (dis[id(xx - 1, yy)] > dis[id(x, y)] + c) {
dis[id(xx - 1, yy)] = dis[id(x, y)] + c;
pq.emplace(dis[id(xx - 1, yy)], xx - 1, yy);
}
}
else if (s[xx][yy - 1] == 'U') {
int c = i < 2 ? q : p;
if (dis[id(xx + 1, yy)] > dis[id(x, y)] + c) {
dis[id(xx + 1, yy)] = dis[id(x, y)] + c;
pq.emplace(dis[id(xx + 1, yy)], xx + 1, yy);
}
}
}
}
}
LL ans = INF;
rep(i, 1, n) {
rep(j, 1, m) {
if (i < n) {
chkmn(ans, dis[id(i, j)] + dis[id(i + 1, j)]);
}
if (j < m) {
chkmn(ans, dis[id(i, j)] + dis[id(i, j + 1)]);
}
}
}
printf("%lld\n", ans == INF ? -1 : ans);
return 0;
}

浙公网安备 33010602011771号