CF1700E Serega the Pirate 解题报告
作者:互联网
CF1700E Serega the Pirate 解题报告
Sol
参考了SA的做法。
转换一下题意,如果存在题目要求的路径,则每个点的上下左右应至少有一个点的值是小于它本身的。
我们定义一个点的 度 为它的上下左右小于它的个数,若该点的度大于等于1,则该点合法;反之则不合法。
即:\(\texttt{交换任一点对,使图中所有点的度大于等于1(都合法)}\)
如果都合法,直接输出0;
易知交换2个点,最多影响到\((4 + 1) \times 2 = 10\)个点,即它的上下左右和它自己,所以不合法的点的数目若超过10个,就不是交换一次能解决的问题,特判为2输出即可。
大部分题解都是枚举所有不合法的点去和其他点挨个比较,但实际上可以挑 任意一个不合法点的上下左右及其本身 作为起始点。因为改变这五个位置可能让它变得合法,而若想满足题目要求,需要保证所有点都合法,其中就包括这个点,所以它一定得合法,因此只择一个不合法点作为起点就行。
有一个细节是交换的两个点的贡献不要算重了,就特判一下,其一 不要踩到枚举过作为起点的点 ,其二 特判一个点的横纵坐标减去另一个点的横纵坐标的差的绝对值的和是否大于1(形象理解就是两点是否在同一个\(6 \times 6\)的大方块中)即可 。
时间复杂度 \(O(nm)\)。
Code
#include <bits/stdc++.h>
using namespace std;
const int MN = 4e5 + 5;
const int dx[5] = {0, -1, 1, 0, 0}, dy[5] = {0, 0, 0, -1, 1};
int n, m, sum, X, Y, ans;
int a[MN];
bool vis[MN], bhf[MN];
inline int g(int x, int y) {
return (x - 1) * m + y;
}
int calc(int x, int y) {
if (a[g(x, y)] == 1) return 0;
bool flag = false;
for (int i = 1; i < 5; ++i) {
int xx = x + dx[i], yy = y + dy[i];
if (xx >= 1 && xx <= n && yy >= 1 && yy <= m && a[g(xx, yy)] < a[g(x, y)]) {
flag = true;
break;
}
}
if (flag == true && bhf[g(x, y)]) return 1;
else if (flag == false && !bhf[g(x, y)]) return -1;
else return 0;
}
void solve(int x, int y) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (vis[g(i, j)]) continue;
swap(a[g(i, j)], a[g(x, y)]);
int tot = 0;
for (int k = 0; k < 5; ++k) {
int xx = i + dx[k], yy = j + dy[k];
if (xx >= 1 && xx <= n && yy >= 1 && yy <= m) tot += calc(xx, yy);
}
for (int k = 0; k < 5; ++k) {
int xx = x + dx[k], yy = y + dy[k];
if (xx >= 1 && xx <= n && yy >= 1 && yy <= m)
if (abs(xx - i) + abs(yy - j) > 1) tot += calc(xx, yy); //特判2
}
if (tot == sum) ans++;
swap(a[g(i, j)], a[g(x, y)]);
}
}
}
signed main() {
ios::sync_with_stdio(false), cin.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
cin >> a[g(i, j)];
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (a[g(i, j)] == 1) continue;
int cnt = 0;
for (int k = 1; k < 5; ++k) {
int xx = i + dx[k], yy = j + dy[k];
if (xx >= 1 && xx <= n && yy >= 1 && yy <= m) cnt += a[g(xx, yy)] < a[g(i, j)];
}
if (cnt == 0) {
// cout << i << ' ' << j << '\n';
bhf[g(i, j)] = true;
sum++;
X = i, Y = j;
}
}
}
if (sum == 0) {
puts("0");
return 0;
}
if (sum > 10) {
puts("2");
return 0;
}
for (int i = 0; i < 5; ++i) {
int xx = X + dx[i], yy = Y + dy[i];
if (xx >= 1 && xx <= n && yy >= 1 && yy <= m) {
vis[g(xx, yy)] = true; //特判1
solve(xx, yy);
}
}
if (ans) cout << 1 << ' ' << ans << '\n';
else puts("2");
return 0;
}
标签:Serega,int,特判,合法,yy,xx,CF1700E,&&,Pirate 来源: https://www.cnblogs.com/zjsqwq/p/16437571.html