C.Weird Sum(點貢獻)
阿新 • • 發佈:2022-03-07
C.Weird Sum
Tag
點貢獻
題目來源
Codeforces Round #775 (Div. 2, based on Moscow Open Olympiad in Informatics)
題目大意
給定一個\(n \times m\)的表格,表格的元素代表著顏色的種類,求問所有相同種類的顏色的距離和,定義兩個表格之間的距離為它們的橫座標和縱座標的差之和,例如(1,2)到(3,3)的距離為3
解題思路
- 我們先考慮某種顏色,比如1。1對答案的貢獻就是任意的兩個1之間的橫座標的差值的和對答案的貢獻 加上 任意的兩個1之間的縱座標的差值的和對於答案的貢獻。更加詳細一點,假設第\(i\)
- 現在我們單獨考慮\(x\)座標下的答案,由於上述式子的複雜度是\(O(n^2)\)的,因此我們需要考慮每個點對於答案的貢獻值
- 考慮1的\(x\)軸座標中的相鄰兩個點的距離對於答案的貢獻,即這段距離會有哪幾對點的連線經過,那麼很顯然便是這段距離的左邊的點的個數乘上右邊的點的個數,即
n表示1的個數
AC程式碼
#include <bits/stdc++.h> using namespace std; #define IOS ios::sync_with_stdio(0) #define LL long long #define maxn (int)(1e6 + 10) #define FFF freopen("out", "w", stdout); int n , m; vector<int> mp[maxn]; vector<int> rr[maxn], cc[maxn]; int main () { IOS; 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); } } LL ans = 0; for ( int i = 1 ; i <= 100000 ; i++ ) { if ( rr[i].size() > 1 ) { for ( int j = 1 ; j < rr[i].size() ; j++ ) { LL 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++ ) { LL len = cc[i][j] - cc[i][j-1]; ans += 1ll * (cc[i].size() - j) * len * j; } } } cout << ans << endl; }