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
,这三个数才不会出现上述的糟糕情况,思路有两条: -
- 找到一个有3个度数以上的节点,并把这三个填到这个节点的三条边上,这样就一定保证不会出现最 三个数在同一条路径上了。
-
- 找到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。
- 接下来就是根据异或操作的性质来分析了:我们可以把 v 拆分成三个数:
-
代码:
#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;
}