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<bits/stdc++.h>
#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;
}

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<bits/stdc++.h>
#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<<idx<<" "<<nxt<<endl;
        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;
}

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<bits/stdc++.h>
#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值