标准输出
埃戈尔有一张大小的桌子n×mn×m,行号从11到nn以及编号为11到mm。每个单元格都有一个颜色,该颜色可以表示为11到105105.
让我们表示位于rr-第四行和cc-第四栏(r,c)(r,c)。我们定义曼哈顿距离两个细胞之间(r1,c1)(r1,c1)和(r2,c2)(r2,c2)作为它们之间最短路径的长度,路径中的每个连续单元必须有一个共同的边。路径可以通过任何颜色的单元格。例如,在表中3×43×4曼哈顿之间的距离(1,2)(1,2)和(3,3)(3,3)是33,最短的路径之一是:(1,2)→(2,2)→(2,3)→(3,3)(1,2)→(2,2)→(2,3)→(3,3).
埃戈尔决定计算相同颜色的每一对细胞之间曼哈顿距离的总和。帮他算这笔钱。
输入
第一行包含两个整数。nn和mm (1≤n≤m1≤n≤m, n⋅m≤100000n⋅m≤100000)-表中的行数和列数。
下一个nn行描述表的一行。这个ii-第四行包含mm整数ci1,ci2,…,cimci1,ci2,…,cim (1≤cij≤1000001≤cij≤100000)中单元格的颜色。ii-第四排
输出量
打印一个整数--相同颜色的每个单元格之间曼哈顿距离之和。
input
Copy
2 3 1 2 3 3 2 1
output
Copy
7
input
Copy
3 4 1 1 2 2 2 1 1 2 2 2 1 1
output
Copy
76
input
Copy
4 4 1 1 2 3 2 1 1 2 3 1 2 1 1 1 2 1
output
Copy
129
题解
我们注意到细胞间的曼哈顿距离(r1,c1)(r1,c1)和(r2,c2)(r2,c2)等于|r1−r2|+|c1−c2||r1−r2|+|c1−c2|。对于每一种颜色,我们将组成一个所有单元格的列表。(r0,c0),…,(rk−1,ck−1)(r0,c0),…,(rk−1,ck−1)对于此颜色,计算此颜色的目标和,并总结所有颜色的答案。之和相等:
∑i=0k−1∑j=i+1k−1|ri−rj|+|ci−cj|=(∑i=0k−1∑j=i+1k−1|ri−rj|)+(∑i=0k−1∑j=i+1k−1|ci−cj|)∑i=0k−1∑j=i+1k−1|ri−rj|+|ci−cj|=(∑i=0k−1∑j=i+1k−1|ri−rj|)+(∑i=0k−1∑j=i+1k−1|ci−cj|)
我们将计算第一个和,第二个和是相似的。让一个数组ss等于rr,但按顺序排列。然后:
∑i=0k−1∑j=i+1k−1|ri−rj|=∑i=0k−1∑j=i+1k−1sj−si=(∑i=0k−1∑j=i+1k−1sj)+(∑i=0k−1∑j=i+1k−1−si)∑i=0k−1∑j=i+1k−1|ri−rj|=∑i=0k−1∑j=i+1k−1sj−si=(∑i=0k−1∑j=i+1k−1sj)+(∑i=0k−1∑j=i+1k−1−si)
价值sjsj发生在第一个双和中。jj时间,价值−si−si发生在第二个和中。k−1−ik−1−i时代。然后,该值等于:
∑j=0k−1jsj+∑i=0k−1−(k−1−i)si=∑i=0k−1(2i+1−k)si∑j=0k−1jsj+∑i=0k−1−(k−1−i)si=∑i=0k−1(2i+1−k)si
最后一次和可以在O(k)O(k),排序数组的时间复杂性是O(k原木k)O(k原木k)。总体的复杂性是O(nm原木(nm))O(nm原木(nm))。我们还可以通过将单元格按正确的顺序添加到列表中来对坐标数组进行排序。这会产生一个O(nm)O(nm)解决办法
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
long long int ans,len;
int n , m;
vector<int> mp[maxn];
vector<int> rr[maxn], cc[maxn];
int main ()
{
//找两个细胞间最短路径
cin >> n >> m ;
for ( int i = 1 ; i <= n ; i++ )
{
mp[i].push_back(0);//压入
for ( int j = 1 ; j <= m ; j++ )
{
int x ;
cin >> x;
rr[x].push_back(i);
mp[i].push_back(x);
}
}
for ( int j = 1 ; j <= m ; j++ )
{
for ( int i = 1 ; i <= n ; i++ )
{
int x = mp[i][j];
cc[x].push_back(j);
}
}
ans = 0;
for ( int i = 1 ; i <= 100000 ; i++ )
{
if ( rr[i].size() > 1 )
{
for ( int j = 1 ; j < rr[i].size() ; j++ )
{
len = rr[i][j] - rr[i][j-1];
ans += 1ll * (rr[i].size() - j ) * len * j;
}
}
if ( cc[i].size() > 1 )
{
for ( int j = 1 ; j < cc[i].size() ; j++ )
{
len = cc[i][j] - cc[i][j-1];
ans += 1 * (cc[i].size() - j) * len * j;
}
}
}
cout << ans << endl;
return 0;
}
}
}