Codeforces Round #628 (Div. 2)

1325A - EhAb AnD gCd

  • 题意:随意找两个数是他们的最大公约数 GCD 与最小公倍数 LCM 之和为所给定的值。
  • 思路:找一下规律 ,假设所给的 数位n, 那么我们将n分成 1 ,n-1,这两个数,总是附和我们的答案
  • 收获:认真观察所给的条件,自己先构造一下,找找规律

1325B - CopyCopyCopyCopyCopy

  • 题意 :给一个有n个元素的数组,将数组中的元素复制 n 次,将n复制结果拼接起来,形成以新的数组,让求严格递增子序列有多少个
  • 思路:对给的数组排序去重复,剩下的元素个数即是答案。

1325C - Ehab and Path-etic MEXs

  • 题意:给一个n个节点的数,其中数的边权范围[0, n-1], 问我们怎么填 这个数的 n-1的边权,可以任意两个节点之间的 MEX 最小(MEX指的是两个节点 所组成的路径上边权没有出现过的最小数)
  • 思路:对于这个n个节点的数,无论我我们怎么填写 0、1 这两个数,在0和1这件总会以一条路径,这个时候 MEX = 2 或者 MEN > 2 , 我们要想让任意两点之间最小,那么在填写2的时候就不能让 2与 0、1 在同一条路径上,怎么填写 0,1,2,这三个数才不会出现上述的糟糕情况,思路有两条:
    1. 找到一个有3个度数以上的节点,并把这三个填到这个节点的三条边上,这样就一定保证不会出现最 三个数在同一条路径上了。
    1. 找到3个度数为1的节点,分别填上0,1,2,就行了,其他点任意填
  • 注意如果没有 3个度数的节点\ 没有3个度数为的节点,那么这个数其实就是一个 “长链”。
  • 法一:代码:
#include <bits/stdc++.h>
using namespace std;
vector<int> v[100005];
int ans[100005];
int main()
{
    int n;
    scanf("%d",&n);
    for (int i=1;i<n;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        v[a].push_back(i);
        v[b].push_back(i);
        ans[i]=-1;
    }
    pair<int,int> mx(0,0);
    for (int i=1;i<=n;i++)
    mx=max(mx,make_pair((int)v[i].size(),i));
    int cur=0;
    for (int i:v[mx.second])
    ans[i]=cur++;
    for (int i=1;i<n;i++)
    {
        if (ans[i]==-1)
        ans[i]=cur++;
        printf("%d\n",ans[i]);
    }
}

  • 法二:代码:
#include<iostream>
#include<algorithm>
#include<map>
#include<cstdio>
 
#define REP(i,first,last) for(int i=first;i<=last;++i)
#define DOW(i,first,last) for(int i=first;i>=last;--i)
using namespace std;
const int MAXN=114514;
int N,M;
int T;
int out[MAXN];//记录度
int p[MAXN];//比较懒,不想存图,所以就只记录一下每个点最后一条出边,反正最后有影响的之后度为1的点,所以没关系
int answer[MAXN];//记录答案
void work()
{
    scanf("%d",&N);
    int f,t;
    REP(i,1,N-1)
    {
        scanf("%d%d",&f,&t);
        out[f]++;
        out[t]++;
        p[f]=p[t]=i;
    }
    if(N==2)//注意特判2
    {
        printf("%d",0);
        return;
    }
    int cnt=0;
    REP(i,1,N)
    {
        if(out[i]==1)//在前三个度为1的点的出边赋值上0,1,2,为了方便处理这里就用了1,2,3
        {
            answer[p[i]]=++cnt;
            if(cnt==3) 
            { 
                break;
            } 
        }
    }
    REP(i,1,N-1)//输出
    {
        if(answer[i])//如果有答案就输出答案
        {
            printf("%d\n",answer[i]-1);
        }
        else//没有反正可以乱输出
        {
            ++cnt;
            printf("%d\n",cnt-1);
        }
    }
}
int main()
{
    work();
    return 0;
}

1325D - Ehab the Xorcist

  • 题意:给你两个 u,v 把 v任意拆成一个数组
    1.使数组元素相互 异或操作之后的结果值为 u
    2. 这些元素值之和为v
    3. 拆成的这个数组的元素个数尽量少

  • 思路:首先我们可根据题目进行特判,如果 u = 0 && v = 0 的直接输出0,u == v的时候答案为 u,u > v 的时候无如何都没法得出答案输出-1.

    • 接下来就是根据异或操作的性质来分析了:我们可以把 v 拆分成三个数: u ^x ^x = u, 那么要想这样拆分,x = (v-u)/ 2, 那么就要让 (u-v)被2整除,所以如果 u、v不是同奇偶的话是没发这样拆分出来的,直接输入-1,否怎的话是可以拆分的,那么就有了答案 u x x,但是根据样例发现,还有两个数的答案,我们仔细看发现 这两个数的其中一个数为 u+x,另一个为x,为什么能这样呢?,我觉的这里其实要用一点二进制的思想来考虑(还要注意异或操作本来就是对 二进制位进行的操作),我考样例中一组样例 u = 2, v = 4,如果按我们上面的分析的话,我们发现答案为 2,1,1, 但实际上为 3,1,,,这个时候我么考虑 2 的二进制位为:0010,1的二进制位为:0001,3的二进制为:0011,那么3异或1,其实就是异或掉了我们加上的 1 ,而要想满足能异或掉这个相加的值,那么要求这两个相加的数的各个二进制位(如:2 、1),不能同时都是1。
  • 代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<cstdio>
using namespace std;
#define ll long long 
int main()
{
    //freopen("A.txt","r",stdin);
    ll u,v;
    scanf("%lld %lld", &u, &v);
    if(u%2 != v%2 || u > v) printf("-1\n");
    else if(u == v)
    {
        if(!u)  printf("0\n");
        else printf("1\n%lld\n", v);
    }
    else
    {
        ll x = (v - u)/2;
        if(u&x) printf("3\n%lld %lld %lld\n", u, x, x);
        else    printf("2\n%lld %lld\n", u^x, x);
    }

    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值