题意:给你一个n*m的矩阵,你可以进行两种操作。
- 将矩阵中任意一个数变为任意数。
- 选择矩阵的一列所有数向上移一个位置。
下图第一列就是进行了一次操作2
最后通过最少的操作次数将矩阵变为下面这种形式:
思路:只需要一列一列的考虑即可,每一列最小最终答案就是最小。选取一列遍历每个数,先判断这个数是否是这一行应该出现的数,如果是再判断距离它正确的位置需要移动几次,然后map记录这个次数加1,将一列变为正确需要的次数就是需要移动的次数加上需要改变的数的个数。没遍历一个数就按这个计算一下这一列需要的次数,最终记录最小的次数即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx=1e6+7;
vector<int> v[maxx];
int main()
{
ios::sync_with_stdio(0);
int n,m;
cin>>n>>m;
for(int i=1,a;i<=n;i++)
{
v[i].push_back(0);
for(int j=1;j<=m;j++)
{
cin>>a;
v[i].push_back(a);
}
}
int ans=0;
for(int i=1;i<=m;i++)
{
int temp,minn=n;
map<int,int> ma;
for(int j=1;j<=n;j++)
{
if(v[j][i]%m!=i%m||v[j][i]>n*m) continue;
temp=v[j][i]/m+(v[j][i]%m!=0);
if(j>=temp)
temp=j-temp;
else temp=n-temp+j;
ma[temp]++;
minn=min(minn,temp+n-ma[temp]);
}
ans+=minn;
}
cout<<ans<<endl;
}