图解 Codeforces 1353C Board Moves

原创文章: https://www.huilon.net.cn/article/14

Codeforces 1353C

Description

题意

现有一个 n × n n × n n×n (n是奇数) 的空间, 共 n 2 n^2 n2 个格子, 在初始的时候, 每个各自有一个人. 人可以在相邻8个格子之间移动一个格子. 每次只能移动一个格子
示意图:
人物可以移动的范围
现在需要把 n × n n × n n×n 空间内所有人都召集在一个格子内, 求所有人走到一个格子内, 总共需要的最少移动的步骤数. 共 t t t 组数据输入

范围:

1 ≤ n ≤ 5 ⋅ 1 0 5 1≤ n ≤ 5 \cdot 10^5 1n5105

n n n是指所有测试样例的n加起来的数

Tutorial

题解

我们拿样例 n = 5 n=5 n=5 来看看, 需要指定最少移动的步骤, 易证: 把所有人召集在最中间的格子, 所有人移动的步骤肯定最少.

现在不妨先把8个方向的人先召集过来, 如下图, 先把深灰色的两个人召集到 13 13 13, 一共走的步骤是 1 + 2 = 3 1+2=3 1+2=3, 其他同理. 值得注意的是, 黄色格子和灰色格子要走到 13 13 13 的步骤数是一样的, 他们可以斜着走. 总共走完之后的步骤数是 ( 1 + 2 ) × 8 (1+2) × 8 (1+2)×8

现在还剩下边边的 8 8 8 个人, 拿左上角做例子, 2 2 2 这个人可以往下走一步, 然后往 13 13 13 走一步, 共 2 2 2 步. 其他同理, 总共 2 × 8 2×8 2×8

我们再来看一般一点的情况, 比如 n = 7 n=7 n=7. 先把 8 8 8个方向的人都招过来, 如下图, 共 ( 1 + 2 + 3 ) × 8 (1+2+3)×8 (1+2+3)×8

然后再把里一圈的人招过来, 如下图, 这里一共 8 8 8 个人, 每个人只需走 2 2 2 步, 共 2 × 8 2×8 2×8

最后再把外一圈的人招过来, 如下图, 这里一共 16 16 16 个人, 每个人需要走 3 3 3 步, 共 3 × 16 3×16 3×16

归纳一下:

n=5 时, 步骤数为

( 1 + 2 ) × 8 + 2 × 8 (1+2)×8 + 2×8 (1+2)×8+2×8

n=7 时, 步骤数为

( 1 + 2 + 3 ) × 8 + 2 × 8 + 3 × 16 (1+2+3)×8 + 2×8 + 3×16 (1+2+3)×8+2×8+3×16

用观察法归纳可以写成

( 1 + 2 + 3 + . . . + ⌊ n 2 ⌋ ) × 8 + 1 × ( 8 × 0 ) + 2 × ( 8 × 1 ) + 3 × ( 8 × 2 ) +   . . . + ( ⌊ n 2 ⌋ × ( 8 × ( ⌊ n 2 ⌋ − 1 ) ) ) \begin{aligned}&(1+2+3+ ... + \lfloor\frac{n}{2}\rfloor )×8\\+ &1×(8×0)\\+ &2×(8×1)\\+ &3×(8×2)\\+ &\ ...\\+ &(\lfloor\frac{n}{2}\rfloor×(8×(\lfloor\frac{n}{2}\rfloor-1)))\end{aligned} +++++(1+2+3+...+2n)×81×(8×0)2×(8×1)3×(8×2) ...(2n×(8×(2n1)))

8 ∑ i = 1 ⌊ n 2 ⌋ i + ∑ i = 1 ⌊ n 2 ⌋ i × 8 ( i − 1 ) 8\sum\limits_{i=1}^{\lfloor\frac{n}{2}\rfloor}i + \sum\limits_{i=1}^{\lfloor\frac{n}{2}\rfloor}i×8(i-1) 8i=12ni+i=12ni×8(i1)

用数学归纳法可证. 证明略.

向上取整, 运算称为 Ceiling,用数学符号 ⌈ n ⌉ ⌈n⌉ n (上有起止,开口向下)表示。
.
向下取整, 运算称为 Floor,用数学符号 ⌊ n ⌋ ⌊n⌋ n (下有起止,开口向上)表示。
.
注意,向上取整和向下取整是针对有浮点数而言的; 若整数向上取整和向下取整, 都是整数本身。
.
.
四舍五入:更接近自己的整数; 把小数点后面的数字四舍五入
即:如被舍去部分的头一位数字小于五,则舍去; 如大于等于五,则被保留部分的最后一位数字加1
向上取整:比自己大的最小整数;
向下取整:比自己小的最大整数;
.
取自网络

我们退一步, 就用

( 1 + 2 + 3 + . . . ) × 8 + 2 × 8 + 3 × 16 + . . . (1+2+3+...)×8 + 2×8 + 3×16 + ... (1+2+3+...)×8+2×8+3×16+...

这个公式来计算, 时间复杂度为 O ( m ) O(m) O(m)

有以下代码:

#include <iostream>

using namespace std;

int main() {
    int t; cin >> t;
    for (int _ = 0; _ < t; ++_) {
        int n; cin >> n;
        long long ans = 0; // 确保乘法和求和的计算结果正确, 使用 long long 类型.
        // 1,2,3,...,m 求和公式: m*(m+1)/2
        long long m = n/2; // n/2 向下取整
        ans = (m*(m+1)/2)*8; // (1+2+3+...)*8
        long long ans_tmp = 0;
        for (int i = 2; i <= m; ++i) { // 当 n = 1 时, 不进去循环, 会输出 0
            ans_tmp += 8; // + 2*8 + 3*16 + ...
            ans += i * ans_tmp;
        }
        cout << ans << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值