Codeforces Round 903 (Div. 3)C题perfect square

文章讲述了在CodeforcesRound903(Div.3)D题中,关于n*n方阵内元素的顺时针和逆时针旋转问题,涉及如何计算将所有元素旋转回原位置所需的最小操作次数。关键在于定义f(i)和f(j)函数来表示旋转操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题源:Codeforces Round 903 (Div. 3)D题

题目

title

输入输出范例
输入:

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 这里涉及到了nn方阵内元素的旋转问题,可以总结一下。令这个nn方阵的二维数组是a[n][n]那么,如果a[i][j]如果是按照顺时针方向旋转四次回到原位置,他的四个位置分别是:a[i][j]a[j][n1i]a[n1i][n1j]a[n1j][i]如果他是逆时针旋转4次回到原位置,他的四个位置分别是:a[i][j]a[n1j][i]a[n1i][n1j]a[j][n1i]简单的进行一个总结,令对于i或者j进行n1i/n1j的操作称为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循环就是遍历了nn方阵左上角(ij<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 这里涉及到了nn方阵内元素的旋转问题,可以总结一下。令这个nn方阵的二维数组是a[n][n]那么,如果a[i][j]如果是按照顺时针方向旋转四次回到原位置,他的四个位置分别是:a[i][j]a[j][n1i]a[n1i][n1j]a[n1j][i]如果他是逆时针旋转4次回到原位置,他的四个位置分别是:a[i][j]a[n1j][i]a[n1i][n1j]a[j][n1i]简单的进行一个总结,令对于i或者j进行n1i/n1j的操作称为f(i)f(j),那么顺时针就是不断地x=y,y=f(x)逆时针就是不断地进行y=x,x=f(y)操作,适用于任意n

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值