Codeforces Round #615 (Div. 3) E. Obtain a Permutation

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 ight)$

求最少的操作次数。

解题思路:

可知,每一列都是独立操作,所以可以计算每一列的最少操作数,首先开一个数组记录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