昨天熬夜到一点半还是没写出来,一直死盯着屏幕,感觉眼球都要炸了,再加上熬夜对身体不好的焦虑,带着愤怒与无奈还是去睡了。早上起来又想了一个半小时,终于有了新的思路:
利用对角线的定值,计算出这一行与对角线相交的点的纵坐标,横坐标自然是这个点的行数,于是这个点的横纵坐标也就知道了。
题目链接:K皇后
题目大意:n行m列,给出k个皇后的位置,问棋盘上哪些位置不会被攻击到。
1 <= n, m <= 2e4, 1 <= k <= 500.
因为这题空间的限制实在是太严格,开二维数组要炸空间。而时间限制也仅是1s,O(N * M)的复杂度过不了。而O(N * (M + K) )的复杂度是可以的。
具体的做法是:
遍历每一行,如果这一行有皇后,那么ans -= m,并且continue。
如果这一行没有皇后,那么遍历每个皇后,检查当前的皇后是否能攻击到这一行中的某个点。
如果可以攻击到这一行中的某个点,则标记一下这个点的纵坐标。
记得要清空flag数组。
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 4e4 + 5;
bool hang[maxn], flag[maxn];
int n, m;
struct node {
int x, y;
} G[maxn];
int main ()
{
int k;
cin >> n >> m >> k;
for (int i = 1; i <= k; i++) {
int x, y;
scanf("%d%d", &x, &y);
G[i].x = x; G[i].y = y;
hang[x] = 1;
}
int ans = n * m;
int ma = max(n, m);
for (int i = 1; i <= n; i++) {
if (hang[i] == 1) {
ans -= m;
continue;
}
memset(flag, 0, sizeof(flag));
for (int j = 1; j <= k; j++) {
int x = G[j].x, y = G[j].y;
int y1 = -(x - y + ma) + i + ma; //顺对角线定值
int y2 = x + y - i; //烦对角线定值
if (flag[y] == 0) flag[y] = true,ans--;
if (y1 >= 1 && y1 <= m && flag[y1] == 0) flag[y1] = true, ans--;
if (y2 >= 1 && y2 <= m && flag[y2] == 0) flag[y2] = true, ans--;
}
}
cout << ans;
return 0;
}
这段代码还能小小的优化一下,flag数组可以开成int型的,然后用当前行数作为标记,如果flag[i]不等于当前行数那就是没有攻击过,然后把这个位置的值赋成当前行的行数。
如果还要优化的话,用快读的话应该还能再快一点。
O(N * M)的做法,如果开O2优化,也是能过的。。