速通ACM省铜第八天 赋源码(1709)
目录
引言:
1709
题意分析
逻辑梳理
代码实现
结语:
引言:
今天我们来讲一道跟之前相比比较简单的题来放松放松,这是一道CF难度评定为1300的题,好巧不巧还是我们昨天打的那道题的同场比赛的前一题,如图,但我感觉其实这俩题难度其实差不多,甚至我感觉这题比2121E来的还难点
那么接下来,我们就进入今日的算法讲解————————>
1709
按照惯例,我们先看一下题目
题意分析
这是题目链接Problem - 2121D - Codeforces
不想跳转的可看下图
题目看着很长,相比昨天那题就长了很多,在题目梳理方面就比较麻烦了,但其实该题目想表达的核心意思其实很简单,那便是给出俩个长度为n的数组a和数组b,其中的元素范围从1到2n不重复出现,但都会出现一次
然后我们需要将俩个数组进行操作,最终得到2个数组满足三个条件
1.ai<ai+1
2.bi<bi+1
3.ai<bi
就这三个条件
然后我们可以对数组进行的操作分为三种
1.交换ai和ai+1的元素
2.交换bi和bi+1的元素
3.交换ai 和bi 的元素
可以任选一种进行操作
然后问你操作多少次可以将数组变到满足条件,先输出交换的次数,然后再输出交换的顺序,输出交换顺序时候先写操作的种类的标号,再写操作的下标,一种操作输出完用空格隔开就可以了
注:操作的次数不用最少的次数,只要满足条件内的次数就可以了
题意分析已经分析的差不多啦,那么接下来我们进入逻辑梳理部分
逻辑梳理
这个题目的逻辑其实很简单,就是先将俩个数组先进行从小到大排序,然后在排序过程中顺便得出排序时候的操作数和排序时候的操作步骤
接下来就是重点,那就是将俩个排完序的从前往后或者从后往前遍历一遍,若ai<bi,那么操作次数就+1,然后存入一次i位置的3类别操作即可,为什么呢,那我们就通过图文来进行讲解(我讲解从前往后遍历的情况,若想要从后往前也是同样的,就不多说了),如图
若ai比bi大,就交换ai与bi,这时已知ai<ai+1,bi<bi+1
因为ai比bi大,所以交换完,bi肯定既<ai+1,也<bi+1
此时,我们不确定ai是否小于bi+1,但是我们会接着往下遍历,若ai+1>bi+1,也会进行交换,若ai+1<bi+1,则不交换,那我们来分析下这两种情况
若交换的话,就相当于是把ai和a+1与bi和bi+1进行对换了,那么此时已经能确保上下大小关系满足了,因为是整个上下对调,所以左右关系也满足了
若不交换的话,就说明ai+1<bi+1,再加上ai<ai+1,自然ai<bi+1,因为bi<ai,ai<ai+1,那自然bi<ai+1,所以只要一路遍历下去就可以了
那么这题的核心思路就证明完毕了,我们再最后梳理一下,整体思路就是先对俩个数组进行排序,然后再排序过程中存入相关节点操作,然后顺便更新次数。排完序后进行一次从前往后或从后往前的遍历找出ai>bi的个数存入相关数组即可,最后输出次数并按存的顺序依次输出方案种类和节点数即可。
那么该题的逻辑梳理就结束啦,接着就进入代码实现的环节啦
代码实现
那么,我们现在首先要解决的是排序的问题,怎么排序呢,肯定不能用sort,毕竟如果用sort了,那在排序期间怎么储存数据已经记录次数呢,所以我们就要手搓一个排序来新增我们需要实现的功能,那么,我们回顾十大排序,最简单的且跟相邻俩个数进行操作最有效的是不是插入排序,所以我们只需要自己自定义一个插入排序的函数,然后在里面进行新增功能的操作啦
那么存下标用什么存呢,我推荐用vector来进行存储,这样输出时候也方便点
那么接下来,我们就来看一下AC源码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <queue>
#include <vector>
using namespace std;int t, ans;
queue <int> l;
queue <int> L;
queue<int> T;
int a[50];
int b[50];void Sort(int c[50],int n)
{int temp = c[1];for (int i = 2; i <= n; i++){if (c[i] > temp){temp = c[i];continue;}if (c[i] < temp){int ll = c[i];ans++;l.push(i - 1);swap(c[i], c[i - 1]);for (int j = i - 2; j > 0; j--){if (ll < c[j]){ans++;l.push(j);swap(c[j], c[j + 1]);continue;}break;}}}
}void solve()
{ans = 0;int n;cin >> n;for (int i = 1; i <= n; i++){cin >> a[i];}Sort(a, n);while (!l.empty()){L.push(l.front());l.pop();}for (int i = 1; i <= n; i++){cin >> b[i];}Sort(b, n);for (int i = 1; i <= n; i++){if (a[i] > b[i]){ans++;T.push(i);}}cout << ans << endl;while (!L.empty()){cout << "1 " << L.front() << endl;L.pop();}while (!l.empty()){cout << "2 " << l.front() << endl;l.pop();}while (!T.empty()){cout << "3 " << T.front() << endl;T.pop();}
}int main()
{cin >> t;while (t--){solve();}return 0;
}
代码虽较长,但其实逻辑还是挺清晰的,那么这题就讲解完啦
结语:
今日算法讲解到此结束啦,希望对你们有所帮助,谢谢观看,如果觉得不错可以分享给朋友哟。