1. 程式人生 > 實用技巧 >CodeForces 1422 B Nice Matrix 題解

CodeForces 1422 B Nice Matrix 題解

題意

給你一個 \(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;
}