我的答案在下面。
国际象棋中的象是攻击同一对角线上(两条对角线上)所有方格的棋子。
Shakhriyar在大小为n * n的棋盘上放置了m个主教。现在他想数一下没有被主教攻击的方格的数量。在这件事上帮助Shahriyar。
输入数据第一行包含两个整数:棋盘的大小n(1 ≤ n ≤ 10^6)和主教的数量m(1 ≤ m ≤ 10^5)。接下来的m行中的每一行都包含一对整数:r[i] и c[i](1 ≤ r[i],c[i] ≤ n)-主教数i所在的行和列的数目。主教从1到m编号。所有的主教都位于不同的广场。
输出数据打印未被象攻击的方格数。
https://www.eolymp.com/en/problems/9630
输入示例#1
106
四七
八五
八七
六二
九七
八四
输出示例#1
33
我解决了这里:
(图片凌乱抱歉)
对角线=2n-1
d-对角线数
(i;j)-点(y,x)的坐标
图片1:
1:(6;1)
2:(5;1);(6; 2)
3:(4;1);(5; 2);(6;3)
4:(3;1);(4; 2);(5;3);(6;四、
...
10:(1;5);(2; 6)
11:(1;6)
d=n-(i-j);
图片2:
1:(1;1)
2:(1;2);(2;第一章
3:(1;3);(3; 1);(2;2)
4:(1;4)(4;1)(2; 3)(3;2)
...
d=i+j-1;
对角线交点:
| 图1(2)中的对角线|图片2(1)中的对角线|
| - -----|- -----|
| 1、11|六|
| 二、十|五、六、七|
| 三、九|四五六七八|
| 四、八|三四五六七八九|
| 五、七|二三四五六七八九十|
| 六|一二三四五六七八九十一|
在查找点数时,交叉点阻止了我。我该怎么解决这个问题?
我的代码(C++):
#include<iostream>
#include<set>
using namespace std;
int main(){
set<int> hit_diagonals1,hit_diagonals2;
int n,m;
cin>>n>>m;
for(int k=0,i,j; k<m; k++){///O(m)-->1e5
cin>>i>>j;
hit_diagonals1.insert(n-(i-j));
hit_diagonals2.insert(i+j-1);
}
int cnt=0;//hit_points_number
//.....
cout<<n*n-cnt<<'\n';
return 0;
}
2条答案
按热度按时间afdcj2ne1#
你可以使用对角sweep-line算法在O(m log m)时间内解决这个问题。
首先,让我们将x+y为常数的对角线称为“反斜线对角线”,而“斜线”对角线将是x-y为常数的对角线。
现在我们可以考虑反斜杠对角线从0到2 m +1(最大x+y)的顺序。
首先,列出“事件”清单。对于每个象位置(x,y),记录:
创建一个最初为空的字典
slashes
,以跟踪覆盖每个斜线对角线的象的数量。在修改此Map时,您还将确保可以跟踪非零条目的数量。现在,按反斜线对角线对事件进行排序,并按顺序处理它们,按反斜线对角线分组。
对于每个反斜杠组<=(m-1)+(m-1):- 累计自上一个反斜线组事件以来未被攻击的方块数。因为这些反斜线中没有事件,这意味着你可以用一个简单的公式来计算未被攻击的方块的数量。- 处理'enter'和'exit'事件以更新
slashes
Map。- 如果有一个‘掩护‘事件,那么只需转到下一组,因为反斜杠中没有未被攻击的方块。- 否则,使用slashes
中的非零条目数来计算反斜杠中未被攻击的方块数。它是反斜杠对角线的长度减去非零项的数量。最后,如果你没有处理反斜杠2(m-1),最后一个,然后使用在所有未处理的反斜杠中添加方块的数量-它们不会被攻击。
注意,问题中的约束表明期望的算法为O(m2)、O(m + n)或O(m + n log n)。这是O(m log m),比他们预期的要好。
nue99wik2#
由于对角线具有在小范围内的标识数字,因此可以使用矢量来代替集合。索引是对角线数字,并且对应的值指示对角线是否被攻击(0或1)。
该算法可以首先迭代前向对角线(f),并且只有当它发现对角线未被攻击时,它才可以迭代相关的交叉对角线以计数那些也未被攻击的对角线。请注意,交叉对角线的数量取决于所考虑的正向对角线,并且这些交叉对角线的数量总是相隔2步(对于给定的正向对角线,它们要么全是奇数,要么全是偶数)。
下面是它的编码方式: