Codeforces Round #628 (Div. 2) C,D

C. Ehab and Path-etic MEXs


题意

给定一颗包含 n n n个节点的树,添加权值使得任意两点的简单路径的长度最大值最小,权值范围 [ 0 , n − 2 ] [0,n-2] [0,n2]

输入描述

第一行一个 n n n表示树节点的个数
接下来 n − 1 n-1 n1行,每行两个数 u , v u,v u,v,表示u和v存在一条边.
输入保证是一颗树, 2 ≤ n ≤ 1 0 5 2 \leq n\leq 10^5 2n105.

输出描述

输出 n − 1 n-1 n1行,每一行代表的是第 i i i行输入边所对应的权值,答案可能存在多种,输出任意一种即可。

分析

考虑贪心,尽可能把权值小的数放在叶子节点所对应的边,故对所对应简单路径的长度最大的才会最小。换句话说就是尽可能的将权值大的数放在任意两点简单路径,经过的边较多的地方。

#include 
#define fir first
#define sec second
#define pb 	push_back
#define ll  long long
using namespace std;
const ll mod=1e9+7;
const int maxn=1e6+7;
ll a[maxn],b[maxn],ans[maxn];
ll n,m;
int solve(int T) {
	memset(a,0,sizeof(a));
	int n;cin>>n;
	vector<pair<int,int> >vec;
	for(int i=1;i<=n-1;i++){
        int x,y;cin>>x>>y;
        a[x]++;a[y]++;
        vec.pb({x,y});
	}
	memset(ans,-1,sizeof(ans));
	memset(b,0,sizeof(b));
	int now=0;
	for(int i=0;i<n-1;i++){
		if(a[vec[i].fir]==1&&b[vec[i].fir]==0) {
			ans[i]=now++;
			b[vec[i].fir]==1;

		}
		else if(a[vec[i].sec]==1&&b[vec[i].sec]==0) {
			ans[i]=now++;
			b[vec[i].sec]==1;
		}
	}
	for(int i=0;i<n-1;i++) if(ans[i]==-1) ans[i]=now++;
	for(int i=0;i<n-1;i++) cout<<ans[i]<<endl;
	return 0;
}
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T=1;
//    cin>>T;
    for(int cas=1; cas<=T; cas++) {
        solve(T);
    }
    return 0;
}

D. Ehab the Xorcist


题意

给定两个数 0 ≤ u , v ≤ 1 0 18 0 \leq u,v\leq10^{18} 0u,v1018,寻找最短的数组使得其满足数组的每个元素的异或值等于 u u u,和为 v v v

输入描述

输入两个数 0 ≤ u , v ≤ 1 0 18 0 \leq u,v\leq10^{18} 0u,v1018.

输出描述

答案不存在,则输出 − 1 -1 1.
答案存在,则第一行输出数组元素的个数,第二行输出n个整数。

分析

若答案存在的话,构造得 [ u , x , x ] , x = v − u 2 [u,x,x],x=\frac{v-u}{2} [u,x,x]x=2vu满足题意,故数组最大长度为3

  1. 考虑答案不存在的情况,由于异或是某种不进位的加法,存在 u > v u>v u>v或者 u u u v v v奇偶性不同,则输出 − 1 -1 1
  2. 考虑长度 0 , 1 0,1 0,1的情况,当 u = v u=v u=v时,输出 1 1 1 u = v = 0 u=v=0 u=v=0时,输出 0 0 0.
  3. 考虑长度为 2 , 3 2,3 2,3的情况。如果存在 < a , b > <a,b>满足条件,则有
    a ⊕ b = u , a + b = v a \oplus b =u,a+b=v ab=u,a+b=v注意到 a + b = a ⊕ b + 2 ∗ ( a & b ) a+b=a\oplus b+2*(a&b) a+b=ab+2(ab).
    a & b = v − u 2 = x a&b=\frac{v-u}{2}=x ab=2vu=x
    如果 x x x某一位存在1 的话,那么说明 a , b a,b a,b中对应位也一定是1,那么我们可以得到 a ⊕ b = u a \oplus b=u ab=u对应位必定是0,换句话说就是,当长度为2时,必须得满足 x & u = 0 x&u=0 xu=0
    也就意味着 x ⊕ u = x + u x\oplus u=x+u xu=x+u
    故长度为2的数组对应为 [ u + x , x ] [u+x,x] [u+x,x],长度为3的数组对应为 [ u , x , x ] [u,x,x] [u,x,x]

代码

#include 
#define fir first
#define sec second
#define pb 	push_back
#define ll  long long
using namespace std;
const ll mod=1e9+7;
const int maxn=1e6+7;
ll a[maxn],b[maxn],ans[maxn];
ll n,m;
int solve(int T) {
	ll u,v;cin>>u>>v;
	if(u==0&&v==0) cout<<0<<endl;
	else if(u==v) cout<<1<<endl<<u<<endl;
	else if(u>v||(v-u)%2) cout<<-1<<endl;
	else {
		ll x=(v-u)/2;
		if((x&u)==0) cout<<2<<endl<<x<<" "<<(x^u)<<endl;
		else cout<<3<<endl<<u<<" "<<x<<" "<<x<<endl;
	}
	return 0;
}
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T=1;
//    cin>>T;
    for(int cas=1; cas<=T; cas++) {
        solve(T);
    }
    return 0;
}

你可能感兴趣的:(CodeForces)