题源:Codeforces Round 903 (Div. 3)D题
题目
输入输出范例
输入:
5
4
abba
bcbb
bccb
abba
2
ab
ba
6
codefo
rcesco
deforc
escode
forces
codefo
4
baaa
abba
baba
baab
4
bbaa
abba
aaba
abba
题意解析
可以把每一个图形都分成四部分,只有一个部分是元始天尊,其他的都是由这个部分,围绕那个虚无的中心点旋转而生成的。
这样看来元始天尊的每一个字母通过旋转可以到达另外三个字母的位置,因此元始天尊那部分的每一个字母背后实际上都有四个位置。
因此问题就简化成了遍历元始天尊的每一个字母的四个位置,并取出四个位置上的字母最大值然后计算把这四个位置上的字母全部变成这个字母需要多少步。
代码总结
这里涉及到了 n ∗ n 方阵内元素的旋转问题,可以总结一下。令 这个 n ∗ n 方阵的二维数组是 a [ n ] [ n ] 那么,如果 a [ i ] [ j ] 如果是按 照顺时针方向旋转四次回到原位置,他的四个位置分别是: a [ i ] [ j ] , a [ j ] [ n − 1 − i ] , a [ n − 1 − i ] [ n − 1 − j ] , a [ n − 1 − j ] [ i ] 如果他是逆时针旋转 4 次回到原位置,他的四个位置分别是: a [ i ] [ j ] , a [ n − 1 − j ] [ i ] , a [ n − 1 − i ] [ n − 1 − j ] , a [ j ] [ n − 1 − i ] 简单的进行一个总结,令对于 i 或者 j 进行 n − 1 − i / n − 1 − j 的操作称为 f ( i ) 或 f ( j ) ,那么顺时针就是不断地 x = y , y = f ( x ) 逆时针就是不断地进行 y = x , x = f ( y ) 操作,适用于任意 n 这里涉及到了n*n方阵内元素的旋转问题,可以总结一下。令\\这个n*n方阵的二维数组是a[n][n]那么,如果a[i][j]如果是按\\照顺时针方向旋转四次回到原位置,他的四个位置分别是:\\a[i][j],a[j][n-1-i],a[n-1-i][n-1-j],a[n-1-j][i]\\如果他是逆时针旋转4次回到原位置,他的四个位置分别是:\\a[i][j],a[n-1-j][i],a[n-1-i][n-1-j],a[j][n-1-i]\\简单的进行一个总结,令对于i或者j进行n-1-i/n-1-j\\的操作称为f(i)或f(j),那么顺时针就是不断地x=y,y=f(x)\\逆时针就是不断地进行y=x,x=f(y)操作,适用于任意n 这里涉及到了n∗n方阵内元素的旋转问题,可以总结一下。令这个n∗n方阵的二维数组是a[n][n]那么,如果a[i][j]如果是按照顺时针方向旋转四次回到原位置,他的四个位置分别是:a[i][j],a[j][n−1−i],a[n−1−i][n−1−j],a[n−1−j][i]如果他是逆时针旋转4次回到原位置,他的四个位置分别是:a[i][j],a[n−1−j][i],a[n−1−i][n−1−j],a[j][n−1−i]简单的进行一个总结,令对于i或者j进行n−1−i/n−1−j的操作称为f(i)或f(j),那么顺时针就是不断地x=y,y=f(x)逆时针就是不断地进行y=x,x=f(y)操作,适用于任意n
代码展示与分析
这里借用一下jiangly的代码,代码非常清晰干脆
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n;
std::cin >> n;
std::vector<std::string> s(n);
for (int i = 0; i < n; i++) {
std::cin >> s[i];
}
int ans = 0;
for (int i = 0; i < n / 2; i++) {
for (int j = 0; j < n / 2; j++) {
int sum = s[i][j] + s[j][n - 1 - i] + s[n - 1 - i][n - 1 - j] + s[n - 1 - j][i];
int max = std::max({s[i][j], s[j][n - 1 - i], s[n - 1 - i][n - 1 - j], s[n - 1 - j][i]});
ans += max * 4 - sum;
}
}
std::cout << ans << "\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t;
std::cin >> t;
while (t--) {
solve();
}
return 0;
}
关键代码部分解析
for (int i = 0; i < n / 2; i++) {
for (int j = 0; j < n / 2; j++) {
int sum = s[i][j] + s[j][n - 1 - i] + s[n - 1 - i][n - 1 - j] + s[n - 1 - j][i];
int max = std::max({s[i][j], s[j][n - 1 - i], s[n - 1 - i][n - 1 - j], s[n - 1 - j][i]});
ans += max * 4 - sum;
}
}
std::cout << ans << "\n";
这一部分两层 f o r 循环就是遍历了 n ∗ n 方阵左上角 ( i 与 j 均 < n 2 ) 的部分的每一个元素,然后针对这些字母访问他们其他的所有 位置的字母大小,同时计算出如果想要统一,需要操作的次数 这一部分两层for循环就是遍历了n*n方阵左上角(i与j均<\frac{n}2)\\的部分的每一个元素,然后针对这些字母访问他们其他的所有\\位置的字母大小,同时计算出如果想要统一,需要操作的次数 这一部分两层for循环就是遍历了n∗n方阵左上角(i与j均<2n)的部分的每一个元素,然后针对这些字母访问他们其他的所有位置的字母大小,同时计算出如果想要统一,需要操作的次数
重要的事情再讲一遍
这个结论还是很不错的
这里涉及到了
n
∗
n
方阵内元素的旋转问题,可以总结一下。令
这个
n
∗
n
方阵的二维数组是
a
[
n
]
[
n
]
那么,如果
a
[
i
]
[
j
]
如果是按
照顺时针方向旋转四次回到原位置,他的四个位置分别是:
a
[
i
]
[
j
]
,
a
[
j
]
[
n
−
1
−
i
]
,
a
[
n
−
1
−
i
]
[
n
−
1
−
j
]
,
a
[
n
−
1
−
j
]
[
i
]
如果他是逆时针旋转
4
次回到原位置,他的四个位置分别是:
a
[
i
]
[
j
]
,
a
[
n
−
1
−
j
]
[
i
]
,
a
[
n
−
1
−
i
]
[
n
−
1
−
j
]
,
a
[
j
]
[
n
−
1
−
i
]
简单的进行一个总结,令对于
i
或者
j
进行
n
−
1
−
i
/
n
−
1
−
j
的操作称为
f
(
i
)
或
f
(
j
)
,那么顺时针就是不断地
x
=
y
,
y
=
f
(
x
)
逆时针就是不断地进行
y
=
x
,
x
=
f
(
y
)
操作,适用于任意
n
这里涉及到了n*n方阵内元素的旋转问题,可以总结一下。令\\这个n*n方阵的二维数组是a[n][n]那么,如果a[i][j]如果是按\\照顺时针方向旋转四次回到原位置,他的四个位置分别是:\\a[i][j],a[j][n-1-i],a[n-1-i][n-1-j],a[n-1-j][i]\\如果他是逆时针旋转4次回到原位置,他的四个位置分别是:\\a[i][j],a[n-1-j][i],a[n-1-i][n-1-j],a[j][n-1-i]\\简单的进行一个总结,令对于i或者j进行n-1-i/n-1-j\\的操作称为f(i)或f(j),那么顺时针就是不断地x=y,y=f(x)\\逆时针就是不断地进行y=x,x=f(y)操作,适用于任意n
这里涉及到了n∗n方阵内元素的旋转问题,可以总结一下。令这个n∗n方阵的二维数组是a[n][n]那么,如果a[i][j]如果是按照顺时针方向旋转四次回到原位置,他的四个位置分别是:a[i][j],a[j][n−1−i],a[n−1−i][n−1−j],a[n−1−j][i]如果他是逆时针旋转4次回到原位置,他的四个位置分别是:a[i][j],a[n−1−j][i],a[n−1−i][n−1−j],a[j][n−1−i]简单的进行一个总结,令对于i或者j进行n−1−i/n−1−j的操作称为f(i)或f(j),那么顺时针就是不断地x=y,y=f(x)逆时针就是不断地进行y=x,x=f(y)操作,适用于任意n