首页 > 其他分享 >2019年蓝桥杯省赛-修改数组(并查集)

2019年蓝桥杯省赛-修改数组(并查集)

时间:2024-04-12 20:23:48浏览次数:12  
标签:选择 int 查集 ++ st 蓝桥 Ai 2019 数组

0.题目

时间限制: 1.0s 内存限制: 256.0MB 本题总分:20 分
【问题描述】
给定一个长度为 N 的数组 A = [A1, A2, · · · AN],数组中有可能有重复出现的整数。
现在小明要按以下方法将其修改为没有重复整数的数组。小明会依次修改
A2, A3, · · · , AN。
当修改 Ai 时,小明会检查 Ai 是否在 A1 ~ Ai-1 中出现过。如果出现过,则小明会给 Ai 加上 1 ;如果新的 Ai 仍在之前出现过,小明会持续给 Ai 加 1 ,直到 Ai 没有在 A1 ~ Ai-1 中出现过。
当 AN 也经过上述修改之后,显然 A 数组中就没有重复的整数了。现在给定初始的 A 数组,请你计算出最终的 A 数组。
【输入格式】
第一行包含一个整数 N。
第二行包含 N 个整数 A1, A2, · · · , AN 。
【输出格式】
输出 N 个整数,依次是最终的 A1, A2, · · · , AN。
【样例输入】
5
2 1 1 3 4
【样例输出】
2 1 3 4 5
【评测用例规模与约定】
对于 80% 的评测用例,1 ≤ N ≤ 10000。
对于所有评测用例,1 ≤ N ≤ 100000,1 ≤ Ai ≤ 1000000。

1.题解

1.1 暴力枚举

思路

思路非常好想,使用一个bool数组标记当前位是否被选过
两层循环(一层for,一层while),外层for用于遍历输入的数, while用于从头开始判断标记位,是则停止,标记;否则不断将当前数++;
但是总体耗时 O(n^2), 很明显会超时!

代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1000010;

int n;
int a[N];
bool st[N];

int main()
{
    cin >> n;
    for (int i = 0; i < n; i++) scanf("%d", &a[i]);
        
    st[a[0]] = true;
    for (int i = 1; i < n; i ++)
    {
        if (!st[a[i]]) st[a[i]] = true;
        else
        {
            while (st[a[i]]) a[i] ++;
            st[a[i]] = true;
        }
    }
    
    for (int i = 0; i < n; i++) printf("%d ", a[i]);
    return 0;
}

1.2 并查集

思路

这题的难点主要是能否想到用并查集来解决,我们想要知道我们每次选到某个数,究竟是输出其本身还是其他数?
我们模拟一下思路,如果我们选择1, 那我们首先去找1是否被选择,如果被选择了,然后再寻找2是否被选择....最后找到那个未被选择的数输出.但这样总体时间复杂度高达O(n^2),并不是我们想要的; 我们想要知道我们如果选择1, 如果重复,立即能知道我们应该选择的下一个数.
如果我们修改标记位由bool记录是否重复 -> 记录下一个位置呢?
比如像我们第一次选择了1, 那么flag[1] = 1 + 1 = 2, 再次选择就是 flag[1] = 2 + 1 = 3呢?
这里又有一个问题了,我们维护的难题, 像这里应该同时更新 flag[2] = 2 + 1 = 3; 也就是说我们要同时所有更新值为 flag[1] 的数均 + 1; 这样维护的成本又变成O(n^2)
如何既要更新记录值,又能很好的维护标记呢?

我们想到一种很有用的结构:树以及对应的结构--并查集
我们可以将每个数视为一个节点,节点的值表示该数。我们初始化时,每个数的记录值为它的下一个数,即记录值为当前数加一。
然后,我们通过 find 操作来寻找当前数的记录值。如果当前数的记录值等于它本身,说明它还没有被选择过,直接返回当前数;否则,我们递归地调用 find 操作,找到记录值对应的下一个数,直到找到一个未被选择的数为止(这里如果使用路径压缩,每次find操作会及时维护更新并查集,使树的高度始终维持在较小的范围内,可以默认寻找效率为O(1))。最后,我们将当前数的记录值更新为下一个未被选择的数,以便下一次选择数时能够快速找到。
这样,每次选择数时,我们只需通过 find 操作来找到下一个未被选择的数,时间复杂度为 O(1),非常高效

代码

#include<bits/stdc++.h>
using namespace std;
const int Maxn = 1e6 + 10;
int fa[Maxn + 1];

void init(){
	for(int i = 1; i <= Maxn; i++){
		fa[i] = i;
	}
}

// 压缩路径 
int find(int x){
	if(x == fa[x]){
		return x;
	} else{
		fa[x] = find(fa[x]);
		return fa[x];
	}
}

// 根节点合并 
void merge(int x, int y){
	fa[find(x)] = find(y); 
}

int main(){
	int n;
	cin >> n;
	init();
	for(int i = 0; i < n; i++){
		int a;
		cin >> a;
		int t = find(a); // 下一个未被选择的数
		cout << t << " ";
		merge(t, t+1); // 下一个未被选择的数(根节点)更新为 find(t+1)
	}
	return 0;
} 

标签:选择,int,查集,++,st,蓝桥,Ai,2019,数组
From: https://www.cnblogs.com/trmbh12/p/18132015

相关文章

  • 蓝桥杯-并查集-合根植物
    0.题目1.解析1.1并查集思路主要三大模板功能1.初始化(init)2.寻找父节点(find)3.合并(merge)我们在find中可以使用路径压缩简化运算,缩短运行时间而启发式合并则可以将运行时间压缩,由O(n)到o(logn)代码#include<bits/stdc++.h>usingnamespacestd;constintMaxn......
  • 2023蓝桥杯 java A组 小蓝的旅行计划
    最小堆(优先队列)和区间树(线段树,红黑树)的结合java中有自己实现这两种数据结构的对象(1)最小堆(优先队列)PriorityQueue<int[]>minHeap=newPriorityQueue<>(newComparator<int[]>(){//int[]三个元素第一个cost第二个lim第三个tag @Override publicintcompare(int......
  • [蓝桥杯 2022 省 A] 爬树的甲壳虫
    概率dp,关键是要走出思维定势:一般来讲,都会把dp[i]定义为从0爬到高度i的概率,但是因为任何时刻都有掉下去的可能,这样子不好推(也有大佬这样做出来的)我们把dp[i]定义为从i爬到n的概率,公式就好推了而且,我们可以根据定义很自然地得到:dp[n]=0#include<bits/stdc++.h>usingnamespa......
  • 蓝桥杯-构造(数学公式1/n = 1/(n+1) + 1/(n+1)n )
    0.题目1.题解1.0找规律n=1,1/1=1/2+1/3+1/6n=2,1/2=1/4+1/6+1/12n=3,1/3=1/6+1/9+1/18....实际上,1/6=1/12+1/12,1/12=1/36+2/36=1/36+1/18即1/6=1/(62)+1/(623/2)+1/(623),即2,3,6三种1.1构造我们想要知道1/n......
  • 2022年蓝桥杯C++B组国赛-试题D-最大数字
    0.题目问题描述给定一个正整数N。你可以对N的任意一位数字执行任意次以下2种操作:将该位数字加1。如果该位数字已经是9,加1之后变成0。将该位数字减1。如果该位数字已经是0,减1之后变成9。你现在总共可以执行1号操作不超过A次,2号操作不超过......
  • Maya 2019.2 Mtoa 无法正常加载并报错
    事件起因:在开始安装Maya2019.2时自动安装的Mtoa的版本为5.3.1,但是在插件管理器里无法启用插件,于是乎去网上下了一个低的版本5.1.1,虽然可以使用但是渲染出来的东西不能用;于是乎我又去网上下载了同样的5.3.1的独立安装包,然后安装破解(注意,这里有个坑,后续揭晓为什么),但是并无......
  • 蓝桥杯-长草(BFS)
    0.题目【问题描述】小明有一块空地,他将这块空地划分为n行m列的小块,每行和每列的长度都为1。小明选了其中的一些小块空地,种上了草,其他小块仍然保持是空地。这些草长得很快,每个月,草都会向外长出一些,如果一个小块种了草,则它将向自己的上、下、左、右四小块空地扩展,这四小块......
  • P8725 [蓝桥杯 2020 省 AB3] 画中漂流
    题目:链接:https://www.luogu.com.cn/problem/P8725思路:dp[i][j]表示第i个时刻还有多少体力之前的错误思路:dp[i][j][k]表示第i个时刻,在j位置,有k个体力。但是注意:这三个变量并不是相互独立!!动规的一个取变量原则应该是相互独立确定某个状态。剩下k体力和i时刻可以推出位置!!site......
  • 并查集
    介绍并查集主要用于处理一些不相交集合的合并问题,一些常见的用途有求联通子图,求最小生成树的Kruskal算法和求最近公共祖先等。并查集的基本操作主要有:初始化查询合并操作初始化假设有编号为1,2,3……,n的n个元素,我们用一个数组fa[]来储存每个元素的父节点。一开始,我们先将......
  • 蓝桥杯2016国赛-路径之谜
    0.题目小明冒充X星球的骑士,进入了一个奇怪的城堡。城堡里边什么都没有,只有方形石头铺成的地面。假设城堡地面是nxn个方格。【如图1.png】所示。按习俗,骑士要从西北角走到东南角。可以横向或纵向移动,但不能斜着走,也不能跳跃。每走到一个新方格,就要向正北方和正西方各射一......