Typesetting math: 100%

切比雪夫距离

曼哈顿距离

若点 A(x1,y1),B(x2,y2) 则两点间的曼哈顿距离为 |x1x2|+|y1y2|

已知 n 个点求两两之间的曼哈顿距离之和,易得 x 的贡献与 y 的贡献是分开的

可以用两次排序去绝对值 + 前缀和解决

复杂度 O(nlogn)

切比雪夫距离

曼哈顿距离是 4 向移动的最少步数,切比雪夫距离则是 8 向移动最少步数

即对于 A(x1,y1),B(x2,y2) 两点的切比雪夫距离为 max(|x1x2|,|y1y2|)

问题:给定 n 个点,求两两之间的切比雪夫距离之和

此时 x,y 的贡献不能单独算了,怎么办?

转换

将原坐标系逆时针旋转 45 ,再放大 2

会发现:此(坐标系中的曼哈顿距离)是(原坐标系中切比雪夫距离)的 2 倍

考虑 (x1,y1) 旋转后的坐标 (x2,y2)

x2=x1cos45y1sin45=12(x1y1)

y2=y1cos45+x1sin45=12(x1+y1)

放大了 2 倍,所以 x2=x1y1,y2=x1+y1

转换成曼哈顿距离,同样 O(nlogn) 求,最后除以 2

给一个 n×m 的棋盘,两个玩家有 'S''M' 两种国王,国王八向移动

传播值定义为玩家国王两两之间距离和,要分别求两个玩家的传播值

板子(确信)

code

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long uLL;
typedef long double LD;
typedef long long LL;
typedef double db;
const int N = 1005;
int n, m, tot;
struct poi { int x, y; } a[N * N];
LL tt, sm;
char mp[N][N];
inline bool cmp1(poi A, poi B) { return A.x < B.x; }
inline bool cmp2(poi A, poi B) { return A.y < B.y; }
inline void sol(char Ch) {
    tot = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            if (mp[i][j] == Ch) a[++tot] = (poi){ i - j, i + j };
    sort(a + 1, a + tot + 1, cmp1);
    sm = tt = 0;
    for (int i = 1; i <= tot; i++) sm += a[i].x * (i - 1) - tt, tt += a[i].x;
    sort(a + 1, a + tot + 1, cmp2), tt = 0;
    for (int i = 1; i <= tot; i++) sm += a[i].y * (i - 1) - tt, tt += a[i].y;
    printf("%lld ", sm / 2);
}
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%s", mp[i] + 1);
    sol('M'), sol('S');
}

upd 补充

将一个点 (x,y) 的坐标变为 (x+y,xy) 后,原坐标系中的曼哈顿距离=新坐标系中的切比雪夫距离

将一个点 (x,y) 的坐标变为(x+y2,xy2) 后,原坐标系中的切比雪夫距离 = 新坐标系中的曼哈顿距离

本文作者:小蒟蒻laf

本文链接:https://www.cnblogs.com/KonjakLAF/p/16114224.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   小蒟蒻laf  阅读(282)  评论(0编辑  收藏  举报
历史上的今天:
2021-04-07 2021.04.03【NOIP提高B组】模拟 总结
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起