@[TOC]Codeforces Round 775(Div.1)A. Weird Sum
题目及来源
- 题目来源: 11月13日灵茶试炼
- 题目描述:
Egor 有一张大小为 n × m n \times m n×m 的表格,其中行的编号为 1 1 1 至 n n n ,列的编号为 1 1 1 至 m m m 。每个单元格都有一种颜色,可以用 1 1 1 到 1 0 5 10^5 105 的整数表示。
我们把位于第 r r r 行和第 c c c 列交叉处的单元格称为 ( r , c ) (r, c) (r,c) 。我们将两个单元格 ( r 1 , c 1 ) (r_1, c_1) (r1,c1) 和 ( r 2 , c 2 ) (r_2, c_2) (r2,c2) 之间的曼哈顿距离定义为它们之间最短路径的长度,路径中的每个连续单元格必须有一个公共边。路径可以穿过任何颜色的单元格。例如,在表格 3 × 4 3 \times 4 3×4 中, ( 1 , 2 ) (1, 2) (1,2) 和 ( 3 , 3 ) (3, 3) (3,3) 之间的曼哈顿距离为 3 3 3 ,其中一条最短路径如下: ( 1 , 2 ) → ( 2 , 2 ) → ( 2 , 3 ) → ( 3 , 3 ) (1, 2) \to (2, 2) \to (2, 3) \to (3, 3) (1,2)→(2,2)→(2,3)→(3,3) .
埃戈尔决定计算每对相同颜色的单元格之间的曼哈顿距离之和。请帮助他计算这个总和。 - Input
第一行包含两个整数 n n n 和 m m m ( 1 ≤ n ≤ m 1 \leq n \le m 1≤n≤m , n ⋅ m ≤ 100 000 n \cdot m \leq 100\,000 n⋅m≤100000 ) - 表格的行数和列数。
接下来的 n n n 行分别描述表格的一行。第 i i i 行包含 m m m 个整数 c i 1 , c i 2 , … , c i m c_{i1}, c_{i2}, \ldots, c_{im} ci1,ci2,…,cim 。( 1 ≤ c i j ≤ 100 000 1 \le c_{ij} \le 100\,000 1≤cij≤100000 ) - 第 i i i 行中单元格的颜色。 - Output
打印一个整数 - 每对相同颜色的单元格之间的曼哈顿距离之和。
题目思路
两点(x1, y1), (x2, y2)的曼哈顿距离就是
∣
x
1
−
x
2
∣
+
∣
y
1
−
y
2
∣
|x1 - x2| + |y1 - y2|
∣x1−x2∣+∣y1−y2∣
因为曼哈顿距离x, y 是相互不影响的所以可以将同一个数字的x,y先进行排序,然后
将其按照贡献法的思路算新加进来一个坐标对于答案的贡献为,例如前m个数的坐标分别为x1, x2, …, xm, 新加入的坐标为xj, 对于答案的贡献为
(
x
j
−
x
1
)
+
(
x
j
−
x
2
)
+
.
.
.
+
(
x
j
−
x
m
)
(xj - x1) + (xj - x2) + ... + (xj - xm)
(xj−x1)+(xj−x2)+...+(xj−xm), 将该公式整理可得
m
∗
x
j
−
(
x
1
+
x
2
+
.
.
.
+
x
m
)
m * xj - (x1 + x2 + ... + xm)
m∗xj−(x1+x2+...+xm)
所以可以排序后用前缀和来维护答案。
代码
- go语言版本代码如下
package main
import (
"bufio"
. "fmt"
"os"
"sort"
)
// func init() { debug.SetGCPercent(-1) } // 关闭垃圾收集
func run() {
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush() // 加速读取
var n, m, v, ans int
Fscan(in, &n, &m)
f := func(p []int) {
pre := 0
for i, v := range p {
ans += i*v - pre
pre += v
}
}
var matrix [100010][2][]int
for i := 0; i < n; i++ {
for j := 0; j < m; j++ {
Fscan(in, &v)
matrix[v][0] = append(matrix[v][0], i)
matrix[v][1] = append(matrix[v][1], j)
}
}
for _, nums := range matrix {
f(nums[0])
sort.Ints(nums[1]) // slices.Sort(), 1.21版本
f(nums[1])
}
Fprintln(out, ans)
}
func main() {
run()
}
- C++语言版本代码如下
C++必须得开long long数组,不然会爆
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
class Solution {
public:
void solve() {
int n, m;
cin >> n >> m;
LL v;
vector<vector<vector<LL>>> matrix(100010, vector<vector<LL>>(2));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> v;
matrix[v][0].emplace_back(i);
matrix[v][1].emplace_back(j);
}
}
LL ans = 0;
function<LL(vector<LL>)> f = [](vector<LL> p) -> LL {
LL res = 0;
LL pre = 0;
for (LL i = 0; i < p.size(); i++) {
res += i * p[i] - pre;
pre += p[i];
}
return res;
};
for (int i = 1; i <= 100000; i++) {
ans += f(matrix[i][0]);
sort(matrix[i][1].begin(), matrix[i][1].end());
ans += f(matrix[i][1]);
}
cout << ans << '\n';
}
};
static int fast_io = [](){
std::ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
return 0;
}();
int main()
{
auto *it = new Solution;
it->solve();
return 0;
}