给定一个 (n imes m) 矩阵,其中元素为 (1 o nm) 的一个排列,每次操作可以任选一个元素将它变为任意整数,或者选择一列将其循环移位(向上)一格,求使得矩阵变为标准型的最少操作次数
Solution
设 (a[i][j]) 为 (i) 行 (j) 列的数,(c[i][j]) 表示第 (j) 列循环移位 (i) 次后有多少个数已经匹配,则答案为
[sum_{j=1}^m (min_{i=0}^{n-1} (i+n-c[i][j]))
]
考虑如何计算 (c),由于每个元素只会对一个 (c[?][?]) 产生贡献,所以我们判断每个元素是否可能被填在当列,如果可能,计算应该被填在的位置,算出坐标差值,然后对对应的 (c[?][?]) 计算贡献就好了
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,m,**a,**c;
signed main() {
ios::sync_with_stdio(false);
cin>>n>>m;
a=new int* [n+1];
c=new int* [n+1];
for(int i=0;i<=n;i++) {
a[i]=new int[m+1];
c[i]=new int[m+1];
for(int j=0;j<=m;j++) c[i][j]=0;
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
cin>>a[i][j];
if(a[i][j]<j||a[i][j]>n*m||(a[i][j]-j)%m) continue;
c[((i-(a[i][j]-1)/m-1)%n+n)%n][j]++;
}
}
int ans=0;
for(int j=1;j<=m;j++) {
int tmp=1e9;
for(int i=0;i<n;i++) tmp=min(tmp,i+n-c[i][j]);
ans+=tmp;
}
cout<<ans;
}