速通ACM省铜第六天 赋源码(MEX Count)
目录
引言:
MEX Count
题意分析
逻辑梳理
代码实现
结语:
引言:
今天依旧是更新一篇,理了下昨天那题的思路,感觉应该是没有问题的了,本来今天想着打俩题,但今天温度太燥热了,脑子想不进去,就决定还是就打一题了(其实是下一题是1500的题,因为还没打出过这个难度的题,所以没把握能在今天打完,所以就放明天打了),今天我们要讲的是CF难度分定为1400的一道题,但这题我感觉比昨天1300的简单很多,思路特别简单清晰,那么,接下来,我们就进入今天的算法讲解——————>
MEX Count
那么,一如既往,我们分三步来讲解这道1400的题,接下来,我们就来分析一下题目
题意分析
这是题目的链接Problem - 2123E - Codeforces
不想跳转的可看下图
这个题目还是很简单的,就是给你一个长度为 n 的数组,然后你可以从其中删掉 0 - n 个元素,然后这个数组的值就是数组里的最小非负整数,问你在删除X个元素的情况下,数组的值有几种可能,然后从删除0个开始到删除n个为止,每次都输出数组值的情况的个数。
这就是题目要我们做的事情了,逻辑其实也很简单,接下来我们就进入逻辑梳理环节
逻辑梳理
首先,我们来想一下如果想要让数组的值为x时,需要保证的条件
最小的条件:要保证数组内有0 - x-1的数,即要有x个数
最大的条件:就是不管别的数,首先要把 x 这个位置上的数的个数给清空
那么接下来,我们通过删除元素个数来满足这个条件
如果要保证数组内大小为 x 的元素个数为0,那么我们删掉大小为 x 的元素的个数就可以了
如果要保证数组内只有0- x-1的数,那么最坏的情况就是0- x-1的数都只有一个,那么就是把数组内的其他的数全部删光,即删掉 n-x 个元素
那也就是说,如果要让数组的值为x,那么删除元素的个数的范围就是要在 x到n-x这个范围内
那么,范围确定好了,接下来还有细节问题,那便是如果一个数组中间有间隔,那么就可以直接中断不访问后面的了,如图
该图中2的个数为0,已经中断了,不管比2大的数有多少,都只会输出2,所以遇到第一个个数为0的元素后,就可以直接结束不访问后面的元素了
那么每个数的范围都知道了,细节也注意到了,那删除不同个数能出现的可能情况也就一目了然了,那么,怎么用代码来实现呢,接下来,我们来进入代码实现环节
代码实现
那么,我们只需要先用一个数组来进行存储每个数的次数即可,然后再用循环找到第一个出现次数为0的一个数字,接下来,在缩小后的范围内进行操作即可,这便完成了逻辑梳理中中断访问的操作,但这个其实不说应该也都会
主要还是如何算个数的问题,如果用每个数的范围来进行排序再递进大概率会超时,若用遍历这毫无疑问会超时,那么关乎到范围,其实我们可以用差分来解决,若用了差分,那么该题的难点也就解决了,那么接下来,就展示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;
int a[200010];
int cha[200010];void solve()
{memset(a, 0, sizeof(a));memset(cha, 0, sizeof(cha));int n, k;cin >> n;for (int i = 1; i <= n; i++){cin >> k;a[k]++;}int wei = 0;for (int i = 0; i <= n; i++){if (a[i] == 0){wei = i;break;}}for (int i = 0; i <= wei; i++){cha[a[i]]++;cha[n - i + 1]--;}int ans = 0;for (int i = 0; i < n; i++){ans += cha[i];cout << ans << " ";}cout << "1" << endl;
}int main()
{cin >> t;while (t--){solve();}return 0;
}
那么,这题就讲完啦
结语:
今日算法讲解到此结束啦,希望对你们有所帮助,谢谢观看,如果觉得不错可以分享给朋友哟。
明天的题目应该难度会上一层次,毕竟是1500的题,我可能还没把握能做出来(悲)