第十五届蓝桥杯省赛第二场C/C++B组C题【传送阵】题解(AC)



解题思路

由于 a a a 数组是一个 1 1 1 到 n n n 的一个排列,那么形成的一定是如下形式:

一定会构成几个点的循环,或者是几个单独的点。

从任意点开始,如果能进入一个循环,一定可以将整个循环的宝藏都拿走,因为不限进入传送门的次数。

那么,我们可以用并查集来维护点与点之间的关系,以及一个小团体里头点的数量。

由于我们可以使用一次从 j j j 跳到 j − 1 j - 1 j−1 或 j + 1 j + 1 j+1 的位置,那么我们可以枚举所有的 c n t [ f i n d ( j ) ] + c n t [ f i n d ( j + 1 ) ] cnt[find(j)] + cnt[find(j + 1)] cnt[find(j)]+cnt[find(j+1)],其中 f i n d ( j ) ≠ f i n d ( j + 1 ) find(j) \neq find(j+1) find(j)=find(j+1)。

时间复杂度约为 O ( n ) O(n) O(n)。

cpp 复制代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;

const int N = 1e6 + 10;

int n;
int p[N], cnt[N];

int find(int x)
{
    if (x != p[x])
        p[x] = find(p[x]);
    return p[x];
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; ++ i )
        p[i] = i, cnt[i] = 1;
    
    for (int i = 1; i <= n; ++ i )
    {
        int x;
        cin >> x;
        int a = find(i), b = find(x);
        if (a == b)
            continue;
        cnt[a] += cnt[b];
        p[b] = a;
    }
    
    int res = 0;
    for (int i = 1; i < n; ++ i )
    {
        int a = find(i), b = find(i + 1);
        if (a == b)
            res = max(res, cnt[a]);
        else
            res = max(res, cnt[a] + cnt[b]);
    }
    
    cout << res << endl;
    
    return 0;
}

【在线测评】

相关推荐
Bigan(安)5 小时前
【奶茶Beta专项】【LVGL9.4源码分析】03-显示框架-图层管理
linux·c语言·mcu·arm·unix
云雾J视界5 小时前
51单片机信号处理实战:C语言A/D与D/A转换应用,从传感器采集到PWM控制全解析
c语言·51单片机·信号处理·pwm·模拟信号·数字信号·a/d
一匹电信狗5 小时前
【LeetCode】栈和队列进阶题目
c++·算法·leetcode·职场和发展·stl·栈和队列
WongKyunban5 小时前
使用Valgrind检测内存问题(C语言)
c语言·开发语言
Bin二叉5 小时前
南京大学cpp复习——第二部分(继承)
开发语言·c++·笔记·学习
代码游侠5 小时前
数据结构——线性表
linux·c语言·数据结构·学习·算法
橘子编程5 小时前
仓颉语言:华为新一代编程利器
java·c语言·开发语言·数据库·python·青少年编程
lingggggaaaa5 小时前
免杀对抗——C2远控篇&PowerShell&C#&对抗AV-EDR&停用AMSI接口&阻断ETW跟踪&调用
c语言·开发语言·c++·学习·安全·c#·免杀对抗
zzzsde5 小时前
【C++】异常:概念及使用
开发语言·c++·算法
繁星星繁5 小时前
CMake快速上手
c语言·c++·编辑器·学习方法·visual studio code