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\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-08-30 14:42:37

Codeforces Round #615 (Div. 3) E. Obtain a Permutation的相关文章

Codeforces Round #615 (Div. 3) A-F简要题解

contest链接:https://codeforces.com/contest/1294 A. 给出a.b.c三个数,从n中分配给a.b.c,问能否使得a = b = c.计算a,b,c三个数的差值之和,n对其取余,判断是否为0即可. AC代码: 1 #include<iostream> 2 #include<vector> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring>

Codeforces Round #615 (Div. 3)

暂时没有F题的题解.太菜了. A - Collecting Coins 题意:有三个人,分别有a,b,c枚硬币,你有n枚硬币,要求把n枚硬币全部给这三个人并且使得他们的硬币数变为相等.问是否可行. 题解:先验证硬币总数a+b+c+n是否能被3整除,然后验证要补的硬币的数量少于n. void test_case() { int a[5], n; scanf("%d%d%d%d", &a[1], &a[2], &a[3], &n); sort(a + 1,

Codeforces Round #615 (Div. 3). D - MEX maximizing

题面:https://codeforces.com/contest/1294/problem/D 题目大意: 每次都会往你的数列里加一个值,你可以任意加减这个值若干次(但是只能加x或者减x) 然后问最小的不属于这个数列的非负整数是什么 你需要进行的操作是,让这个最小的不属于这个数列的非负整数最大 每次加一个值并且询问一遍 解题思路: 易得到,每一次输出的答案在进行完题目的贪心后会呈现上升趋势,且值最大只可能为序列内元素的个数 所以我们可以让每次加入的值在进行完若干次操作后尽量成为靠前的序列中还没

Codeforces Round #615 (Div. 3). B - Collecting Packages

题面:https://codeforces.com/contest/1294/problem/B 题目大意: 机器人从(0,0)开始,他只能往上'U'或者往右'R'走 坐标系中有着很多包裹,分别在一些点上 机器人需要走过去把这些包裹全部收集起来 问能不能做到 如果能,再输出移动方式,相同移动方式输出字典序最小的方案 解题思路: pair或者结构体排序,x与y的优先级任意,因为下一个包裹必定在当前机器人位置右方/上方/右上方 否则直接输出NO,表示不可能存在这种移动方式 在输出移动方式时,注意能先

Codeforces Round #615 (Div. 3) F. Three Paths on a Tree

F. Three Paths on a Tree 原题链接:https://codeforces.com/contest/1294/problem/F 题目大意: 给定一棵树,选出三点,使三点连成的j简单路径最大.简而言之,三个点连成的边的集合大小. 解题思路: 假设任取一点为三点连线的公共点,最长路径就是这个点到其他三个点的三条最长边之和,可知这个点一定在直径上(画图分析假设不在时的最长路径可反证).所以先求出树的直径,在使用$ans =(a b+a c+b c) / 2$遍历可以得到第三个点

题解 Codeforces Round #615 (Div. 3) (CF1294)

A:判断一下和是不是3的倍数,由于只加不减,所以还要判断有没有大于和的1/3. 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #define it register int 5 #define ct const int 6 #define il inline 7 using namespace std; 8 int T,a,b,c,n,x; 9 namespace io{ 10 il c

Codeforces Round #615 (Div. 3) 题解

A - Collecting Coins 题意: 给你四个数a,b,c,d,n.问你是否能将n拆成三个数A,B,C,使得A+a=B+b=C+c. 思路: 先计算三个数的差值的绝对值abs,如果abs大于n则肯定不行,如果小于n,还需判断(n-abs)%3是否为0,不为0则不行. #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<vector

Codeforces Round #615(div.3) A 题解

题意: 分别有a,b,c个硬币在对应的三个人手中,我有n个硬币,问如何将这n个硬币分给这三个人使得最后三个人的硬币数相同. 思路: 先求出每个人与最多的人的硬币个数的差距,然后拿n个硬币去填补这个空缺,分过剩下来没有分的如果可以%3==0,则说明可以相同.如果不为0则说明无法分配. 水题一道: #include<iostream> #include<algorithm> using namespace std; int main() { int t; cin>>t; w

【贪心】Codeforces Round #436 (Div. 2) D. Make a Permutation!

题意:给你一个长度为n的数组,每个元素都在1~n之间,要你改变最少的元素,使得它变成一个1~n的排列.在保证改动最少的基础上,要求字典序最小. 预处理cnt数组,cnt[i]代表i在原序列中出现的次数.b数组,代表没有出现过的数是哪些.b数组的长度就是答案. b数组是从小到大排好的,然后for循环b数组,同时用一个指针p指着a数组的当前位置,最开始指向开头,如果cnt[a[p]]==1,就向后跳,否则再看 是否b[i]<a[p]或者a[p]这个数是否已经出现过了(用个hav数组表示a[p]是否已