Codeforces Round #628 (Div. 2)

Codeforces Round #628 (Div. 2)

比赛传送门

A. EhAb AnD gCd

题目传送门

Problem Restatement

给出一个整数\(x\),请你构造两个整数\(a,b\),使得\(\gcd(a,b)+\text{lcm}(a,b)=x\)

\((2≤𝑥≤10^9,1\leq a,b,\leq 10^9)\)

Solution

\(a=1,b=x-1\)即可。

B. CopyCopyCopyCopyCopy

题目传送门

Problem Restatement

给出一个长度为\(n\)的序列\(a\),并构造一个新的序列按顺序包含\(n\)个序列\(a\)

求出新序列中最长的严格上升子序列。

$(1≤𝑛≤10^5 , 1≤𝑎𝑖≤10^9) $

Solution

\(a\)序列中有\(m\)不同的数字的话,它的最长严格上升子序列,最长一定只能是\(m\)

所以新的序列中,最长的严格上升子序列也就只能是\(m\)

由于\(m\leq n\),所以新序列中每一个\(a\)按顺序挑出来一个数,那么一定能构造出来一个长度为\(m\)的严格上升子序列。

那么答案就很明显了:排序+去重后的序列,即是答案。

C. Ehab and Path-etic MEXs

题目传送门

Problem Restatement

给你一颗节点数为\(n\)的树,请你将\([0,n-2]\)里的整数作为权值,分配给\(n-2\)条边,使得((对于任意两个节点\(u,v\)的唯一路径,在路径之外的所有边的最小值)中的最大值最小

\((2≤𝑛≤10^5)\)

Test Case 1

如图,选取任意两个点构成的路径,之外的最小值中最大至少也只能为\(2\)。而这也是最小情况了。

Solution

题目有点绕,但是理解之后不难发现,树上的叶子结点其实是解题的重中之重(由于这是一个无根树,所以叶子结点不妨定义成所有度数为\(1\)的节点)。

因为对于任意一条路径,最多只能占有两个叶子结点,所以对于叶子数大于\(2\)的树来说,无论路径怎么选择,都至少有一个叶子结点暴露在路径外面。那很明显,我们把叶子结点上按顺序放满最小的那些权值,剩下权值随意分配即可。(对于叶子数小于等于\(2\)的树,权值的分配并不影响答案,特判我都懒得写)

当然聪明的你肯定已经发现,其实填\(0,1,2\)就可以了,剩下的其实都没关系,但是这么写方便啊(反正更严格不扣分

Code

按照我的思路写,代码真的简洁。

#include <bits/stdc++.h>
#define LL long long
#define MAXN 100005
using namespace std;

int f[MAXN],g[MAXN],dgr[MAXN];

void solve(){
	int n;
	scanf("%d", &n);
	memset(dgr+1,0,(n-1)*sizeof(dgr[0]));
	for(int i=1;i<n;i++){
		scanf("%d %d", &f[i], &g[i]);
		dgr[f[i]]++,dgr[g[i]]++;
	}
	int cnt=0,cntd=n-2;
	for(int i=1;i<n;i++){
		if(dgr[f[i]]==1 || dgr[g[i]]==1)
			printf("%d\n", cnt++);
		else
			printf("%d\n", cntd--);
	}
}

int main(){
    int T=1;
    // scanf("%d", &T);
    while(T--){
        solve();
    }
    return 0;
}

D. Ehab the Xorcist

题目传送门

Problem Restatement

给你两个自然数\(u,v\),请你构造一个最短的正整数序列,使得序列所有元素按位异或为\(u\),所有元素之和为\(v\)。(如果无解输出\(-1\))

\((0≤𝑢,𝑣≤10^{18})\)

Solution

这题很明显是考察按位异或\(\oplus\)的性质。

先判断特殊的情况:

​ 如果\(u>v\),很明显无解,因为按位异或可以理解成进位的加法,不可能比加法结果大。

​ 如果\(u=v=0\),按照样例可以有空序列,所以这个答案为空序列。

​ 如果\(u=v\not=0\),那么答案为长度为\(1\)的序列\(u\)

​ 如果\(u\)\(v\)二进制个位不相等(即\(u\)\(v\)奇偶性不同),也是无解的,因为个位上相加异或值必须一样(因为前面没有进位)。

考虑完特殊情况,考虑\(\oplus\)的其他特殊性质,比如\(a\oplus a=0,a\oplus 0=a\)。这两个性质可是好性质啊,如果我们能构造一个序列,\(\oplus\)到最后变成\(u\oplus 0\)岂不是美滋滋。按照这个思路,正好我们论证了,\(u,v\)奇偶性相同且\(v> u\)(其余情况已经被特判),不妨让\(x=\frac{v-u}{2}\)。我们有\(u\oplus x\oplus x=u\)\(u+x+x=v\)。所以我们构造出来了一个通用的三元解\((u,\frac{v-u}{2},\frac{v-u}{2})\)

那我们只需要考虑二元解是否存在即可。

在比赛现场的时候,由于本人还是对异或不熟悉,导致我直接开写了一个按位构造,代码能力差的我把写的一塌糊涂,导致我花了30多分钟在这题上面,代码还很难看。比赛代码(千万不要点开,写的太丑AAAA)

然而,的确是有更简单的构造方法的。前提是得知道另性质\(a+b=a\oplus b+2*(a\& b)\)。为什么呢,之前我们说了:按位异或可以理解成进位的加法。那么什么时候会进位,那就是所有按位与\(1\)的时候啦!那么为什么有\(2*\)呢,因为进位之和的值要全体左移一位。就这样,我们推导出了这个公式。

根据这个公式我们发现,\(v=u+2*(a\& b)\),那么\(a\&b=\frac{v-u}{2}=x\)。Wow,这个操作让限制条件从\((u,v)\)转换成了\((u,x)\)。我们不需要判断+中的进位,只需要整整意义上按位来考虑问题。

那么考虑\(\oplus\)\(\&\)中的每一位来构造二元解,我们会发现只有当\(u\)中某一位为\(1\)的同时\(x\)中某一位也为\(1\)时,是无法构造的。换句话说,如果\(u\&x\)不为\(0\),则无二元解。

而对于有二元解构造结果来说,不妨让一个数为\(u+x\),另一个数为\(x\)即可,即\((u+\frac{v-u}{2},\frac{v-u}{2})\)

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

void solve(){
	LL u,v;
	scanf("%lld %lld", &u, &v);
	if(u>v || (v-u)%2==1){
		printf("-1\n");
		return;
	}
	if(u==v){
		if(u==0) printf("0\n");
		else printf("1\n%lld\n", u);
		return;
	}
	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);
}

int main(){
    int T=1;
    // scanf("%lld", &T);
    while(T--){
        solve();
    }
    return 0;
}
posted @ 2020-03-16 16:39  Leachim  阅读(130)  评论(0编辑  收藏  举报