AtCoder Beginner Contest 126 DEF

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值