P5372 题解
namelessgugugu · · 题解
做完之后有人告诉我这题上界卡的很死,除了官解做法都很难通过,我寻思这都给了两倍常数了还能卡属实是有点厉害。
哦什么,原来是我爆标了,那没事了。
题意
懒得写了,直接看链接吧。
题解
注意到对图进行黑白交替染色(认为
而对于一个
想象一下,操作的过程大概相当于空点在黑点上借积木实现移动,所以可以如此建模:把黑格子当作点,白格子当作边,把空点当作在图上游走的棋子。
具体地,对于一个积木,设其初始位置为
而最后要做的就是让棋子把所有边都访问一遍,由于这张图除了起点终点每个点的入度出度都为
但是事情并没有那么简单,很显然这张图并没有保证连通,我们需要先对这张图做一些调整使其连通。
能做的调整其实就是让某个积木不一定被操作仅一次,而是有可能先被操作到一个中间态,再被操作到终态。如果让某个积木被操作正好两次,设中间态为
事实上,这样的调整已经足够解决这个问题,而且做法相当简单粗暴:
如果当前有一个
由于加中间态只会让
这同样也要求在代码实现时不能无脑调整,一定需要等到有必要调整时再调,所以实现应该是:对起点所在连通块进行遍历,如果遇到上述所说的可以调整的情况,则调整完后需要先遍历
显然操作次数为总边数,而一个白格子至多贡献两条边,所以至多操作
代码
写的时候在 int,pair<int, int> 和 int x, y 之间来回转化,所以比较屎山。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <utility>
#include <vector>
#include <array>
#define FILEIO(filename) (freopen(filename ".in", "r", stdin), freopen(filename ".out", "w", stdout))
typedef long long ll;
typedef unsigned long long ull;
using std::pair, std::vector, std::array;
const int N = 2005, M = 4000005;
const int dx[8] = {1, 0, -1, 0, 1, 1, -1, -1}, dy[8] = {0, 1, 0, -1, 1, -1, 1, -1};
int n, m;
char a[2][N][N];
int edg[N][N];
inline int id(int x, int y)
{
return (x - 1) * m + y;
}
inline pair<int, int> getp(int x)
{
return {(x - 1) / m + 1, (x - 1) % m + 1};
}
inline pair<int, int> getpt(int x, int y, int o)
{
if(a[o][x][y] == '<')
return {x, y + 1};
else if(a[o][x][y] == '>')
return {x, y - 1};
else if(a[o][x][y] == 'n')
return {x + 1, y};
else if(a[o][x][y] == 'u')
return {x - 1, y};
return {-1, -1};
}
inline int findedg(pair<int, int> f, pair<int, int> t)
{
if(f == t)
return -1;
int d1 = t.first - f.first, d2 = t.second - f.second;
for (int o = 0; o < 8;++o)
if (d1 == dx[o] * (o < 4 ? 2 : 1) && d2 == dy[o] * (o < 4 ? 2 : 1))
return o;
return -2;
}
inline void addedg(pair<int, int> x, int o)
{
edg[x.first][x.second] |= 1 << o;
return;
}
int que[M], hd, tl;
bool vis[N][N];
void dfs(int x, int y)
{
vis[x][y] = 1;
que[++tl] = id(x, y);
for (int o = 0; o < 8; ++o)
if((edg[x][y] >> o) & 1)
{
int nx = x + dx[o] * (o < 4 ? 2 : 1), ny = y + dy[o] * (o < 4 ? 2 : 1);
if(!vis[nx][ny])
dfs(nx, ny);
}
return;
}
void bfs(int s)
{
hd = 1, tl = 0;
auto [sx, sy] = getp(s);
dfs(sx, sy);
while (hd <= tl)
{
auto [x, y] = getp(que[hd++]);
for (int o = 0; o < 4;++o)
{
int nx = x + dx[o], ny = y + dy[o];
if(nx < 1 || nx > n || ny < 1 || ny > m)
continue;
auto f = getpt(nx, ny, 1), t = getpt(nx, ny, 0);
if(!vis[f.first][f.second])
{
dfs(f.first, f.second);
int e1 = findedg(f, t);
int e2 = findedg(f, {x, y}), e3 = findedg({x, y}, t);
if(e1 != -1)
edg[f.first][f.second] ^= 1 << e1;
if(e2 != -1)
addedg(f, e2);
if(e3 != -1)
addedg({x, y}, e3);
}
}
}
return;
}
int res[M << 1], tt;
void getans(int x, int y)
{
for (int o = 0; o < 8;++o)
if ((edg[x][y] >> o) & 1)
{
int nx = x + dx[o] * (o < 4 ? 2 : 1), ny = y + dy[o] * (o < 4 ? 2 : 1);
edg[x][y] ^= 1 << o;
getans(nx, ny);
}
res[++tt] = id(x, y);
}
char ans[M << 1];
inline char operate(pair<int, int> f, pair<int, int> t)
{
pair<int, int> ky = getpt(t.first, t.second, 0);
int d1 = ky.first - f.first, d2 = ky.second - f.second;
for (int o = 0; o < 4;++o)
if(d1 == dx[o] && d2 == dy[o])
{
a[0][ky.first][ky.second] = "u>n<"[o];
a[0][f.first][f.second] = "n<u>"[o];
a[0][t.first][t.second] = 'o';
return "DRUL"[o];
}
return 0;
}
int main(void)
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n;++i)
scanf("%s", a[0][i] + 1);
for (int i = 1; i <= n;++i)
scanf("%s", a[1][i] + 1);
int s = 0;
for (int i = 1; i <= n;++i)
for (int j = (i & 1 ? 2 : 1); j <= m;j += 2)
{
auto f = getpt(i, j, 1), t = getpt(i, j, 0);
if(f != t)
addedg(f, findedg(f, t));
}
for (int i = 1; i <= n;++i)
for (int j = 1; j <= m;++j)
if(a[0][i][j] == 'o')
{
s = id(i, j);
break;
}
bfs(s);
getans((s - 1) / m + 1, (s - 1) % m + 1);
std::reverse(res + 1, res + 1 + tt);
for (int i = 1; i < tt;++i)
ans[i] = operate(getp(res[i]), getp(res[i + 1]));
puts(ans + 1);
return 0;
}