2022.2.10 解题报告
1.异或
题目描述:
思路:
直接打擂台找最大值然后异或一下即可。
代码:
#include <iostream>
using namespace std;
const int N = 20;
int n, a[N], maxx;
int main() {
scanf("%d", &n);
for (int i = 1 ; i <= n ; i ++ ) {
scanf("%d", a + i);
maxx = max(maxx, a[i]);
}
printf("%d\n", maxx ^ a[n]);
return 0;
}
2.国际象棋
题目描述:
思路:
由于马和马之间是互相攻击的,所以只要保证第二个马不放在第一个马的攻击范围上即可保证无法攻击到第一个马。
而对于车来说,只需要把车当作马,再标出它为马和为车时各自的攻击范围,保证第二个马不放在它的攻击范围内即可。
代码:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 9;
string h, c;
bool g[N][N];
int dx[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
int dy[8] = {1, 2, 2, 1, -1, -2, -2, -1};
int main()
{
cin >> h >> c;
int t1 = h[0] - 'a' + 1 , t2 = h[1] - '0', t3 = c[0] - 'a' + 1, t4 = c[1] - '0';
g[t1][t2] = g[t3][t4] = 1;
for(int i = 0 ; i < 8 ; i ++ ) //标记第一个马的攻击范围
{
int xx = t3 + dx[i], yy = t4 + dy[i];
if(xx < 1 || xx > 8 || yy < 1 || yy > 8) continue;
g[xx][yy]=1;
}
for(int i = 0 ; i < 8 ; i ++ ) //把车当作马,标记其攻击范围
{
int xx = t1 + dx[i], yy = t2 + dy[i];
if(xx < 1 || xx > 8 || yy < 1 || yy > 8) continue;
g[xx][yy] = 1;
}
for(int i = 1 ; i <= 8 ; i ++ ) //标记车的攻击范围
for(int j = 1 ; j <= 8 ; j ++ )
if(i == t1 || j == t2)
g[i][j] = 1;
int res = 0;
for(int i = 1 ; i <= 8 ; i ++ ) //计算答案
for(int j = 1 ; j <= 8 ; j ++ )
if(!g[i][j]) res ++ ;
cout << res;
return 0;
}
3.习题册
题目描述:
思路:
由于数据大小为20万,所以我们的代码时间复杂度应约为O(n*logn)。
所以我们要用数据结构来优化代码。
我们来看所有的练习册,将它们分成三堆,分别代表包含知识点1、2和3的练习册:
那么对于每一个同学来说,我们要做的操作就是在c[i]那一堆中取出一个最小的数,并将这个数在所有堆中删除。
显然,这就是小根堆的操作,而堆的操作的时间复杂度也恰好为O(logn),因此我们可以用堆来解决这道题目。
注意:
由于三个集合会有重叠部分,所以在删除时要在所有集合中删除。而又由于这个数不一定在所有集合中都是最小值,所以我们要用到“懒操作”(延迟删除),用一个bool数组来标记某一个数是否已经被删除。
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#define x first
#define y second
using namespace std;
const int N = 2e5 + 10;
typedef pair<int, int> PII;
int n, m;
int p[N], a[N], b[N], c[N];
priority_queue<PII, vector<PII>, greater<PII> > h[3]; //开三个堆
bool st[N]; //延迟删除数组
int main() {
scanf("%d", &n);
for (int i = 1 ; i <= n ; i ++ )
scanf("%d", p + i);
for (int j = 1 ; j <= 2 ; j ++ )
for (int i = 1 ; i <= n ; i ++ ) {
int a;
scanf("%d", &a);
h[a - 1].push({p[i], i}); //a - 1是因为要用0、1、2表示三个集合
}
scanf("%d", &m);
while (m -- ) {
int c;
scanf("%d", &c);
c -- ; //换成0、1、2
while (h[c].size() && st[h[c].top().y]) //删除上次标记为要删除的数
h[c].pop();
if (h[c].empty()) //如果c堆中已经没有数了,即已经卖光了
printf("-1 ");
else {
auto t = h[c].top(); //取出最小的数,即最便宜的练习册
h[c].pop();
printf("%d ", t.x);
st[t.y] = true; //标记为要删除的数
}
}
return 0;
}