CF1283C,CF920C和CF1328C

南昌理工acm暑假集训
本周主要参加多校赛训练和做acwing的每日一题

就写一些我认为还不错的题的题解吧

**

第一道题是

acwing数组补全
题目来源于CF1283C
这道题主要涉及到 构造 和 环图
主要做题思路是模拟
代码思路:
1.就是硬模拟
2.找出缺失的数字
3.找出缺失的位置
4.找出缺失的数字,同时也是缺失位置的情况----“重复的数字”
5.找出缺失的数字,不是缺失位置的情况-------“非重复的数字”
6.分情况讨论
(1)如果重复的数字超过了两个。这些超过的数字中,后一个填前一个的坑就可以。
(2)如果重复的数字只有一个,这个重复的位置需要用非重复的数字去填。
(3)如果重复的数字有0个。非重复的数字,直接挨着往缺失的位置填即可。
题解:(自己没码成功,这是参考过y总的代码写的)

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

using namespace std;

const int N = 200010;

int n;
int p[N], q[N];
bool st[N];

int main()
{
    int T;
    scanf("%d", &T);
    while (T -- )
    {
        scanf("%d", &n);
        memset(q, 0, sizeof q);
        memset(st, 0, sizeof st);
        for (int i = 1; i <= n; i ++ )
        {
            scanf("%d", &p[i]);
            q[p[i]] = i;
        }

        bool flag = false;
        for (int i = 1; i <= n; i ++ )
        {
            if (st[i] || !p[i]) continue;
            st[i] = true;
            int x = i, y = i;
            while (p[x] && !st[p[x]])
            {
                x = p[x];
                st[x] = true;
            }
            while (q[y] && !st[q[y]])
            {
                y = q[y];
                st[y] = true;
            }

            if (p[x] == y) continue;
            if (!flag)
            {
                flag = true;

                for (int j = 1; j <= n; j ++ )
                    if (!p[j] && !q[j])
                    {
                        st[j] = true;
                        p[x] = j;
                        x = j;
                    }
            }
            p[x] = y;
        }

        if (!flag)
        {
            int x = 0, y = 0;
            for (int i = 1; i <= n; i ++ )
                if (!p[i])
                {
                    if (!x && !y) x = y = i;
                    else
                    {
                        p[x] = i;
                        x = i;
                    }
                }
            p[x] = y;
        }

        for (int i = 1; i <= n; i ++ )
            printf("%d ", p[i]);
        puts("");
    }

    return 0;
}

第二道题是

acwing交换相邻元素
题目来源:CF920C
这是一道思维题
主要思路为排序
代码思路:
1.我们假设 [l,r] 区间内字符均为 1,则说明 [l,r+1]区间内的元素可以随意互换,而不能与该区间以外的元素交换。为了最终使其成为升序数组,我们可以将该段内数组元素升序排序。
2.遍历 01 字符串,双指针找到连续的一段可交换的区间,将该区间内元素升序排序。遍历完整个字符串后,如果数组 a 是从 1 到 n 的升序全排列,则输出 YES,否则输出 NO
3.最终可以用 is_sorted(a.begin(), a.end()) 可以直接判断是否升序

题解:

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> a(n);
    string b;
    for(int i = 0; i < n; i++) cin >> a[i];
    cin >> b; 
    // 双指针找连续可交换区间
    int l = 0, r = 0;
    while(r < n) {
        while(b[r] == '1') r++;
        sort(a.begin() + l, a.begin() + r + 1);
        r++;
        l = r;
    }
    // 判断最终数组是否为升序
    bool ok = true;
    for(int i = 0; i < n; i++) {
        if(a[i] != i + 1) {
            ok = false;
            break;
        }
    }

    if(ok) cout << "YES\n";
    else cout << "NO\n";

    return 0;
}

代码思路和题解参考acwing大佬GTAlgorithm

第三题是

acwing三元数异或
题目来源CF1328C
思路
根据结果 x 的每一位上的数字 xixi 进行分类讨论如下(假设 a⩾b):

  1. 当 xi=0 时,a 和 b 对应位置上的数字可以为 (0, 0) 或者 (1, 2),因为要求 a 尽可能小,所以 ai=0,bi=0。
  2. 当 xi=1 时,a 和 b 对应位置上的数字可以为 (0, 1) 或者 (2, 2),因为要求 a 尽可能小且 a⩾b,所以在 a 和 b 还没有确定大小关系时,应该是 ai=1,bi=0;当 a 和 b 已经确定大小时,为了使 a 尽可能小,应该是 ai=0,bi=1。
  3. 当 xi=2 时,a 和 b 对应位置上的数字可以为 (0, 2) 或者 (1, 1),因为要求 a 尽可能小且 a⩾b,所以在 a 和 b 还没有确定大小关系时,应该是 ai=1,bi=1;当 a 和 b 已经确定大小时,为了使 a 尽可能小,应该是 ai=0,bi=2。

使用 flag 记录 a 和 b 是否已经确定大小关系,根据上述讨论可知,在 a 和 b 没有确定大小关系时,遇到 xi=0和 xi=2,ai 和 bi 会填上相同的数字,直到遇到 xi=1 有 ai=1,bi=0,a 和 b 可以确定大小关系。
题解:

#include<bits/stdc++.h>
using namespace std;
char c[51000],a[51000],b[51000];
int t,n;
int main()
{
    cin>>t;
    while(t--)
    {
        int f=0;
        cin>>n;
        cin>>c;
        for(int i=0;i<n;i++)
        {
            if(c[i]=='2'&&f==0) a[i]=b[i]='1';
            else if(c[i]=='1'&&f==0)
            {
                a[i]='1',b[i]='0';
                f=1;
            } 
            else if(c[i]=='0') a[i]=b[i]='0';
            else if(f==1) a[i]='0',b[i]=c[i];
        }

        for(int i=0;i<n;i++)
            cout<<a[i];
        cout<<endl;
        for(int i=0;i<n;i++)
            cout<<b[i];
        cout<<endl;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值