$题目链接
A.Interview(Codeforces 631A)
思路
显然,根据兼或和的性质,当 l 和
代码
#include <bits/stdc++.h>
using namespace std;
long long n, a, b, sa, sb;
int main() {
scanf("%d", &n);
sa = sb = 0;
for(int i = 0; i < n; i++) {
scanf("%I64dd", &a);
sa |= a;
}
for(int i = 0; i < n; i++) {
scanf("%I64d", &b);
sb |= b;
}
printf("%I64d\n", sa + sb);
return 0;
}
B.Print Check(Codeforces 631B)
大意
有一个所有格子的颜色都是白色的网格。每次操作能将网格某行或某列的所有格子全部涂成某种颜色,问最后网格中每个格子的颜色是什么。
思路
显然,这题直接暴力是不行的。在不算主算法的情况下,输入的复杂度是 O(k) ,输出的复杂度是 O(nm) 。这就表示本题仅允许我们在输入的同时维护一些量,然后在输出的时候,对矩阵的每一个元素,根据这些量来决定元素的值。对于一个元素 (i,j) 而言,若要知道它最终的值是多少,仅需知道它最终被刷上什么颜色,也就是说,仅需知道它所在的行的最终颜色,它所在的列的最终颜色,以及这两个颜色出现的先后顺序。总而言之,我们需要对每一行,每一列维护最后被涂上的颜色和被涂上的时间。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e3 + 5;int n, m, k, a, b, c;
int cr[maxn], cc[maxn], pr[maxn], pc[maxn];
int G[maxn][maxn];
int main() {
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= k; i++) {
scanf("%d%d%d", &a, &b, &c);
if(a == 1) {
cr[b] = c;
pr[b] = i;
}
else {
cc[b] = c;
pc[b] = i;
}
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
G[i][j] = pr[i] > pc[j] ? cr[i] : cc[j];
}
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
printf("%d ", G[i][j]);
}
puts("");
}
return 0;
}
C.Report(Codeforces 631C)
大意
有一个由 n 个数字组成的序列,每次可以指定序列的某个前缀,然后按照非增序或非减序为这个前缀排序。问
思路
本题用暴力的方法肯定也是不行的了(复杂度为 O(mnlog(n)) )。既然题目给的每次排序的区间是前缀,那么就应该充分利用前缀的性质。不难发现,对 [0,r] 这个前缀排序以后,在这次排序之前的对长度小于 r 的前缀的排序都无效了。所以有效的前缀的长度应该是递减的。根据单调队列能够动态维护单调序列的性质,我们可以按照输入的顺序将命令序列插入单调队列,输入结束后就能得到有效的前缀序列了。接着对这些前缀依次排序就可以比暴力方法稍快地得到答案序列。不过可惜的是,这样的优化仍然不够。假设已经对长度为