• 2022牛客暑期多校训练营7(总结+补题)


    总结

    今天因为多校和 robocom 决赛冲突了,所以我们队大概只打了一个半小时(但是还是把三道签到题做完了),队友1一开始就发现 C 是签到题,简单交流了一下思路后就交给队友1写了,我和队友2一起看另外一道签到题 F ,队友2得出贪心的结论之后就由我开写,我们分别在45分钟过了 F ,52分钟过了 C,四点多打完 robocom 之后回来又看到 G 题过了一车人,我们将三种长度的 6 种情况讨论出来后一发过掉了 G,比赛结束。由于这把多校只打了一个多小时,所以剩下的题还是得找时间补一补的。

    题解

    C - Constructive Problems Never Die

    题意:给你一个数组 a a a ,让你构造一个从 1 − n 1-n 1n 的排列 b b b ,数组 a [ i ] a[i] a[i] 的意思是在第 i i i 个位置中数组 b b b 的值不能为 a [ i ] a[i] a[i] ,即 b [ i ] ! = a [ i ] b[i]!=a[i] b[i]!=a[i] 如果能构造,则输出 Y E S YES YES 并将构造的数组 b b b 输出,不能则输出 N O NO NO

    做法:

    由观察我们容易得出,只要数组 a a a 不是只存在一种数字,则有解(全为一个数时无论如何 b 数组中也会有一个数使得 b [ i ] = a [ i ] b[i]=a[i] b[i]=a[i] ),我们可以考虑将数组 a a a 中出现的每种数及这种数的一个下标存起来,例如 1 1 2 3 4,我们则将(1,2)(2,3)(3,4)(4,5)存下,然后让数组 b b b b [ 3 ] = 1 , b [ 4 ] = 2 , b [ 5 ] = 3 , b [ 2 ] = 4. b[3]=1,b[4]=2,b[5]=3,b[2]=4. b[3]=1,b[4]=2,b[5]=3,b[2]=4. 即将数字错位,然后再将剩余的数全部填到剩余的空位中(因为剩余的数没有出现在 a a a 中,因此我们可以以任意的方式填,也不会出现 a [ i ] = b [ i ] a[i]=b[i] a[i]=b[i] 的情况)

    代码:

    /*
     author:wuzx
     */
    
    #include
    #define ll long long
    #define int long long
    #define endl "\n"
    #define P pair<int,int>
    #define f first
    #define s second
    using namespace std;
    const int inf = 0x3f3f3f3f;
    int t;
    int n,m,k;
    signed main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        cin>>t;
        while(t--)
        {
            map<int,int> mp;
            cin>>n;
            for(int i=0;i<n;i++)
            {
                cin>>m;
                mp[m]=i;//将每种数字的一个下标存进map里
            }
            if(mp.size()==1)//只有一种数时输出NO
                cout<<"NO"<<endl;
            else
            {
                cout<<"YES"<<endl;
                vector<int> ans(n,0),vis(n+1,0);
                vector<P> b;
                for(auto [x,y]:mp)
                    b.emplace_back(x,y);
                m=b.size();
                for(int i=0;i<m;i++)//将第i种数的下表设为第i+1个数的下标,并记录这个数已经填了
                {
                    auto [x,y]=b[(i+1)%m];
                    auto [x1,y1]=b[i];
                    ans[y]=x1;
                    vis[x1]=1;
                }
                int idx=1;
                for(int i=0;i<n;i++)//将剩余的数填进空位里
                {
                    if(!ans[i])
                    {
                        while(vis[idx])
                            idx++;
                        ans[i]=idx;
                        idx++;
                    }
                }
                for(auto x:ans)
                    cout<<x<<" ";
                cout<<endl;
            }
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    F - Candies

    题意:

    给你一个环形数组,当数组中相邻两个元素满足 a [ i ] = a [ i + 1 ] a[i]=a[i+1] a[i]=a[i+1] a [ i ] + a [ i + 1 ] = x a[i]+a[i+1]=x a[i]+a[i+1]=x ,可将这两个数从数组中消去,问最多能进行多少次消除操作。

    做法:

    这题队友2简单推了几种情况,觉得这是贪心,然后我就用并查集模拟循环链表,遇到能删除的直接删除即可。

    代码:

    /*
     author:wuzx
     */
    
    #include
    #define ll long long
    #define int long long
    #define endl "\n"
    #define P pair<int,int>
    #define f first
    #define s second
    using namespace std;
    const int inf = 0x3f3f3f3f;
    int t;
    int n,m,k;
    signed main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        cin>>n>>k;
        vector<int> a(n),fa(n),pre(n);
        for(int i=0;i<n;i++)   
        {
            cin>>a[i];
            fa[i]=i;
            pre[i]=i;
        }
        function<int(int)> find = [&](int x)
        {
            return fa[x]==x?x:fa[x]=find(fa[x]);
        };
        function<int(int)> find1 = [&](int x)
        {
            return pre[x]==x?x:pre[x]=find1(pre[x]);
        };
        int idx=0;
        int ans=0;
        int len=n;
        int cnt=0;
        while(1)
        {
            int nxt=find((idx+1)%n);
            if(idx==nxt)
                break;
            // cout<
            if(a[idx]+a[nxt]==k||a[idx]==a[nxt])
            {
                ans++;
                len-=2;
                int n1xt=find((nxt+1)%n);
                fa[idx]=n1xt;
                fa[nxt]=n1xt;
                int pre1=find1((idx-1+n)%n);
                pre[nxt]=pre1;
                pre[idx]=pre1;
                if(idx==pre1)
                    break;
                idx=pre1;
                cnt=0;
                if(len<=1)
                    break;
            }
            else
            {
                idx=find((idx+1)%n);
                cnt++;
            }
            if(cnt>len+10)
                break;
        }
        cout<<ans<<endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    G - Regular Expression

    题意:

    涉及正则表达式的知识,给你一个字符串问你用正则表达式最短能用几个字符表示出来,输出最短的正则表达式长度及个数。

    做法:

    考虑字符长度为 1 1 1 ,以 a a a 为例,此时只有两种情况 a a a .    .\space\space .   答案为 1 2

    再考虑字符长度为 2 2 2 的情况,若两个字符相同,则有 a a   a .   . a   a +   . +   . .   . ∗   a ∗ aa\space a.\space .a\space a+\space .+\space ..\space .*\space a* aa a. .a a+ .+ .. . a 这长度为二的八种情况

    若两个字符不相同,则有 a b   a .   . b   . .   . ∗   . + ab\space a.\space .b\space ..\space .*\space .+ ab a. .b .. . .+ 这长度为二的六种情况

    若字符长度大于2,若字符串中只有一种字符,则有 a +   a ∗   . +   . ∗ a+\space a* \space .+\space .* a+ a .+ . 这长度为二的四种情况

    若字符串不止一种字符,则有 . ∗   . + .*\space .+ . .+ 这长度为二的两种情况。

    代码:

    /*
     author:wuzx
     */
    
    #include
    #define ll long long
    #define int long long
    #define endl "\n"
    #define P pair<int,int>
    #define f first
    #define s second
    using namespace std;
    const int inf = 0x3f3f3f3f;
    int t;
    int n,m,k;
    signed main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        cin>>t;
        while(t--)
        {
            string ss;
            cin>>ss;
            if(ss.size()==1)
                cout<<1<<" "<<2<<endl;
            else if(ss.size()==2)
            {
                if(ss[0]==ss[1])
                    cout<<2<<" "<<8<<endl;
                else
                    cout<<2<<" "<<6<<endl;
            }
            else if(count(ss.begin(),ss.end(),ss[0])==ss.size())
                cout<<2<<" "<<4<<endl;
            else
                cout<<2<<" "<<2<<endl;
        }   
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
  • 相关阅读:
    SpringBoot事件监听器源码分析
    R语言批量处理nc数据/R语言MK趋势检验/NCL绘图(nc可视化)
    Linux学习第23天:Linux中断驱动开发(二): 突如其来
    工具 | Windows 功能猎手 (WFH)
    小巧有劲的按摩好手,能装兜里的护理工具,小鸟斗士筋膜枪体验
    企业电子招标采购系统源码Spring Boot + Mybatis + Redis + Layui + 前后端分离 构建企业电子招采平台之立项流程图
    一个完整的项目测试方案流程应该是什么样的?
    Web安全总结
    数据链路层-封装成帧
    21天算法打卡系列(4)
  • 原文地址:https://blog.csdn.net/m0_51028279/article/details/126236545