E. Obtain a Permutation
原题链接:https://codeforces.com/contest/1294/problem/E
题目大意:
给一个无序矩阵,可以进行两个操作:
1.改变任何元素的大小;
2.将任何一列中的元素向上提一位,也就是$a_{1, j}:=a_{2, j}, a_{2, j}:=a_{3, j}, \dots, a_{n, j}:=a_{1, j}$
使得最后的矩阵变为有序的序列,即$\left.a_{1,1}=1, a_{1,2}=2, \ldots, a_{1, m}=m, a_{2,1}=m+1, a_{2,2}=m+2, \ldots, a_{n, m}=(i-1) \cdot m+j\right)$
求最少的操作次数。
解题思路:
可知,每一列都是独立操作,所以可以计算每一列的最少操作数,首先开一个数组记录vis,以该列的第i行为起点所需进行的操作数。首先初始化为n+i(i从0开始)。然后遍历该列每一行算出如果这一行的数字属于该列,那么是以谁为起点才能使这个位置是它。计算得出答案为第a行,则vis[a]-1,然后计算到到最后一行,最后取最小值。在计算出每列最小值相加可得出最后答案。
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=2e5+7; 5 vector<int>arr[N]; 6 int vis[N]; 7 int MAX,MIN; 8 int main(){ 9 int n,m,a,ans,idx; 10 cin>>n>>m; 11 for(int i=1;i<=n;i++){ 12 arr[i].push_back(0); 13 for(int j=1;j<=m;j++){ 14 cin>>a; 15 arr[i].push_back(a); 16 } 17 } 18 ans=0; 19 for(int j=1;j<=m;j++){ 20 for(int i=0;i<n;i++){ 21 vis[i]=n+i; 22 } 23 for(int i=1;i<=n;i++){ 24 if(arr[i][j]<=(j+m*(n-1))&&(arr[i][j]%m==j||(j==m&&arr[i][j]%m==0))){ 25 idx=i-arr[i][j]/m-1; 26 if(j==m){ 27 idx++; 28 } 29 idx=(idx+n)%n; 30 vis[idx]--; 31 } 32 } 33 MIN=1e9+7; 34 for(int i=0;i<n;i++){ 35 MIN=min(MIN,vis[i]); 36 } 37 ans+=MIN; 38 } 39 cout<<ans<<endl; 40 return 0; 41 }
原文地址:https://www.cnblogs.com/meanttobe/p/12255707.html
时间: 2024-11-08 11:22:20