AtCoder Beginner Contest 126 DEF
https://atcoder.jp/contests/abc126
D题
题意:
对1棵有n个结点的树01染色,
要求任何有相同距离的顶点之间的距离为偶数
输入:n个点,n-1条边
思路:
链式前向星建树,从1个点出发找每个点到它的距离,距离为偶数的都涂0,距离为奇数的都涂1 (没开longlong wa了几发)
void dfs(int u,int c){
res[u] = c;
vis[u] = true;
for(int i=h[u];~i;i=ne[i]){
int v = e[u],w = va[u];
if(vis[v]) continue;
if(w & 1) dfs(v,c ^ 1);
else dfs(v,c);
}
}
int main(){
read(n);
for(int i=0;i<n-1;i++){
read(a),read(b),read(c);
add(a,b,c);
add(b,a,c);
}
dfs(1,0);
for(int i=1;i<=n;i++) printf("%d\n", res[i]);
}
================================================
E题:
题意:
A数组有n个数,每个数可能是1或2,
给定m组关系 每次给出Xi Yi Zi 满足
问最少询问几个数,可以知道所有的数
思路:
求联通块的个数。
其实和zi没有关系,因为
可能是奇数或者偶数,其中一个知道了,另一个也就知道了
如果有3个数通过两组关系连成1个联通块的话,只要知道1个数,其他的数就也都知道了,扩展到更多个数也一样,一个联通块中只要有1个数知道了,其他数就都知道了。
即求连通块的个数
void dfs(int u){
vis[u] = 1;
for(int i=h[u];~i;i=ne[i]){
int v = e[i];
if(!vis[v]) dfs(v);
}
}
int main(){
memset(h,-1,sizeof h);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b);
add(b,a);
}
ll res = 0;
for(int i=1;i<=n;i++){
if(!vis[i]){
res++;
dfs(i);
}
}
printf("%lld\n", res);
return 0;
}
================================================
F题
题意:
给定 n 和 k
要求构造出一个长度为 2 ^ ( n + 1) 的序列满足
0 到 (2 ^ n - 1) 每个数出现两次,且
每对相同的数字之间区间异或和相同
如ai = aj , ai ^ a(i+1) ^ … a(j-1) ^ aj = k
构造:
0 1 2 … (2 ^ n - 1) k (2 ^ n - 1) …2 1 0 k
说明:
0 1 2 … (2 ^ n - 1) 里面 少个k ,把k提到了后面
(2 ^ n - 1) …2 1 0 里面也少个k ,把k提到了后面
这样保证了,非k的数中,每个数都是成对出现,异或为0,中间还有个k
所以异或为k
两个k之间,k (2 ^ n - 1) …2 1 0 k
我们知道: 从 0 异或到 (2 ^ n - 1) 异或值为 0
所以 k (2 ^ n - 1) …2 1 0 异或起来为0 ,最后还有个k ,所以异或为k
还要特殊处理
① 如果 k >= (1 << n) 不满足 输出 -1
② 如果 k == 1&& n == 1 不满足 输出 - 1
③ 如果 k == 0 则 每个数连续输出两次即可
void solve(){
if(k >= (1 << m) || m==1&&k==1){
puts("-1");
return;
}
n = 1 << m+1;
if(!k){
for(int i=1;i<=n;i++) printf("%d ",(i-1)/2);
return;
}
for(int i=0;i<(1<<m);i++)
if(i!=k) printf("%d ",i);
printf("%d ",k);
for(int i=(1<<m)-1;i>=0;i--)
if(i!=k) printf("%d ",i);
printf("%d",k);
}
int main(){
cin>>m>>k;
solve();
return 0;
}