2022.10.09 总结
1. 逐月 P5005
题意
有一个为 \(1 \sim n\) 的序列 \(a\),给定 \(a_1, a_2, b_1, b_2\),每次操作先翻转 \(a_1 \sim a_2\),再翻转 \(b_1 \sim b_2\),总共有 \(k\) 次操作,请你输出 \(k\) 次操作后的序列。
思路
52 分
暴力模拟 \(k\) 次操作。
时间复杂度
有 \(k\) 次操作,每次操作 \(O(n)\)。
总时间复杂度 \(O(k \times n)\)。
空间复杂度
用一个长度为 \(n\) 的数组来存储答案,\(O(n)\)。
100 分
求出每个 \(a_i\) 的循环节,记录最终答案,输出。
时间复杂度
枚举每个元素,\(O(n)\)。
每个循环节最多长度为 \(n\),\(O(n)\)。
总时间复杂度为 \(O(n ^ 2)\)。
空间复杂度
用一个长度为 \(n\) 的数组来记录循环节,\(O(n)\)。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int n, k, a1, a2, b1, b2, c[N], f[N];
int F(int p){ // 求循环节
int i = 0;
while (p != f[1]) {
f[++i] = p; // 记录循环节
if (a1 <= p && p <= a2) {
p = a1 + a2 - p;
}
if (b1 <= p && p <= b2) {
p = b1 + b2 - p;
}
}
return f[k % i + 1];
}
int main(){
cin >> n >> k >> a1 >> a2 >> b1 >> b2;
for (int i = 1; i <= n; i++) {
f[1] = -1;
c[F(i)] = i;
}
for (int i = 1; i <= n; i++) {
cout << c[i] << endl;
}
return 0;
}
2. 逐月 P5038
题意
有一个\(N \times N\) 的画布。在画布上,有不超过 \(9\) 个矩形,每个矩形的颜色用一个数字来表示,所有颜色都只能被使用一次。每个矩形都可以覆盖在别的矩形上。请你求出画布上仍然可见的颜色中有多少种是第一次绘制上去的。
思路
100 分
求出每种元素的矩形的左上角和右下角,判断在这个矩形中,是否存在别的颜色,如果存在,则那个颜色不可能是第一次绘制上去的。
时间复杂度
枚举颜色,\(O(9)\)。
枚举每种颜色对应的矩形,\(O(n ^ 2)\)。
总时间复杂度为 \(O(n ^ 2)\)。
空间复杂度
记录 \(n \times n\) 的矩阵,\(O(n ^ 2)\)。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 15;
int n, w[N][N], cnt, x[2][10], y[2][10];
char l;
bool f[10], v[10];
int main(){
cin >> n;
for (int i = 0; i < 10; i++) { // 初始化
x[1][i] = y[1][i] = INT_MIN;
x[0][i] = y[0][i] = INT_MAX;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> l;
w[i][j] = l - '0';
f[w[i][j]] = 1;
// 记录左上角和右下角
x[0][w[i][j]] = min(x[0][w[i][j]], i), x[1][w[i][j]] = max(x[1][w[i][j]], i);
y[0][w[i][j]] = min(y[0][w[i][j]], j), y[1][w[i][j]] = max(y[1][w[i][j]], j);
}
}
for (int i = 1; i <= 9; i++) {
for (int j = x[0][i]; j <= x[1][i]; j++) {
for (int k = y[0][i]; k <= y[1][i]; k++) {
// 枚举矩阵
if (w[j][k] != i) { // 如果有别的颜色
v[w[j][k]] = 1; // 标记颜色
}
}
}
}
for (int i = 1; i <= 9; i++) {
if (!v[i] && f[i]) {
cnt++;
}
}
cout << cnt;
return 0;
}
3. 逐月 P5053
题意
给定 \(n\) 头奶牛的坐标,有一条 \(x = a\) 的无限长的栅栏和一条 \(y = b\) 的无限长的栅栏,它们在点 \((a, b)\) 相交,将农场分为四个部分,\(M\) 代表 \(4\) 个部分中包含奶牛数量的最大值,请你求出 \(M\) 的最小值。
思路
70 分
枚举行和列的坐标,再枚举每头奶牛,求出 \(M\) 的最小值。
时间复杂度
枚举坐标,\(O(b ^ 2)\)。
枚举每头奶牛,\(O(n)\)。
总时间复杂度为 \(O(b ^ 2 \times n)\)。
空间复杂度
用 \(4\) 个临时变量记录四个部分的奶牛数量,\(O(1)\)。
用一个变量记录 \(M\) 的最小值,\(O(1)\)。
空间复杂度 \(O(1)\)。
100 分
枚举两头奶牛,将行和列 \(+1\) 求出 \((a, b)\),再枚举 \(n\) 头奶牛,求出最小值。
时间复杂度
枚举两头奶牛求出 \((a, b)\),\(O(n ^ 2)\)。
枚举每头奶牛,\(O(n)\)。
总时间复杂度为 \(O(n ^ 3)\)。
空间复杂度
用 \(4\) 个临时变量记录四个部分的奶牛数量,\(O(1)\)。
用一个变量记录 \(M\) 的最小值,\(O(1)\)。
空间复杂度 \(O(1)\)。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int n, b, cnt = INT_MAX;
struct C{
int x, y;
} a[N];
int main(){
cin >> n >> b;
for (int i = 1; i <= n; i++) {
cin >> a[i].x >> a[i].y;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
int x = a[i].x + 1, y = a[j].y + 1; // 枚举行和列
int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
for (int k = 1; k <= n; k++) {
if (a[k].x > x) { // 判断属于哪个部分
if (a[k].y > y) {
c2++;
} else {
c1++;
}
} else {
if (a[k].y > y) {
c4++;
} else {
c3++;
}
}
}
cnt = min(cnt, max(c1, max(c2, max(c3, c4)))); // 更新答案
}
}
cout << cnt;
return 0;
}