CodeForces 1422 B Nice Matrix 題解
阿新 • • 發佈:2020-10-05
題意
給你一個 \(n*m\) 的矩陣,你可以每次將其中一個數 \(+1\) 或 \(-1\) ,求多少次可以使矩陣每一行每一列為迴文的.
若一個數列 \((a_1,a_2,a_3,\dots,a_n)\) 為迴文, \(\forall a_i ,a_i = a_{n-i+1}\)
\(\texttt{Data Range:}\)
\(1 \leq n,m \leq 100,a_i \leq 10^9\)
思路
我們注意到,要使每行每列都是迴文的,就要使
\(a_{i,j} = a_{i,m-j+1} = a_{n-i+1,j} = a_{n-i+1,m-j+1}\)
如圖:
即圖中的 \(4\)
那我們只要每次處理這 \(4\) 個綠色方塊,使其相同的操作次數最小。
設這 \(4\) 個方塊的數從小到大為 \(x_1,x_2,x_3,x_4\) ,最後我們要是這些數都變為 \(mid\) 。
代價為 \(s = |x_1-mid| + |x_2 - mid| + |x_3 - mid| + |x_4 - mid|\)
結論
當 \(x_2 \leq mid \leq x_3\) , \(s\) 有最小值。
證明
如圖:
綠色的線段和 代表 \(s\) 。
不管 \(x_1,x_2,x_3,x_4\) 的大小,我們都可以發現:
\(x_2 <= mid <= x_3\)
因此,我們只要列舉 \(mid = x_2\) 或\(mid = x_3\) 就可以算答案了。
程式碼
#define re(x) read(x) #define ll long long using namespace std; const int MAXN = 110; const ll INF = 1e15; int n,m,a[MAXN][MAXN]; int main (){ int T; re(T); while(T--){ re(n);re(m); for(int i = 1;i <= n;i++) for(int j = 1;j <= m;j++) re(a[i][j]); ll ans = 0; for(int i = 1;i <= n/2;i++){ for(int j = 1;j <= m/2;j++){ //每一行正中間的一個數無需考慮 ll tt = INF,sum; sum = a[i][j]; tt = min(tt,abs(a[i][j]-sum) + abs(a[n-i+1][j]-sum)+abs(a[i][m-j+1]-sum) + abs(a[n-i+1][m-j+1]-sum)); sum = a[n-i+1][j]; tt = min(tt,abs(a[i][j]-sum) + abs(a[n-i+1][j]-sum)+abs(a[i][m-j+1]-sum) + abs(a[n-i+1][m-j+1]-sum)); sum = a[i][m-j+1]; tt = min(tt,abs(a[i][j]-sum) + abs(a[n-i+1][j]-sum)+abs(a[i][m-j+1]-sum) + abs(a[n-i+1][m-j+1]-sum)); sum = a[n-i+1][m-j+1]; tt = min(tt,abs(a[i][j]-sum) + abs(a[n-i+1][j]-sum)+abs(a[i][m-j+1]-sum) + abs(a[n-i+1][m-j+1]-sum)); ans += tt; //注意,當時我寫的時候沒有排序,而是每個數進行列舉,因為資料量很小,所以可以過 } if(m&1) ans += abs(a[i][m/2+1]-a[n-i+1][m/2+1]); //如果有居中的行,只要滿足這一行為迴文的. } if(n&1){ for(int i = 1;i <= m/2;i++){ ans += abs(a[n/2+1][i] - a[n/2+1][m-i+1]); } } write(ans); } return 0; }