• Solution -「CF 959E」Mahmoud and Ehab and the xor-MST


    Description

    Link.

    一完全图有 (n) 个节点 (0,...,n-1),其中边 ((i,j)) 的权值为 (ioplus j),其中 (oplus) 为位异或操作,试求出最小生成树的边权和。

    Solution

    先从递推的层面考虑.

    我们定义 (F(n)) 表示结点数为 (n) 的答案,也就是最小生成树的边权和.

    首先边界条件为 (F(0)=0,F(1)=1).

    然后我们考虑如何从 (F(n-1)) 推到 (F(n)).

    每当我们新加入一个结点 (n-1)(题目结点编号从 0 开始),它的点权为其本身,也就是 (n-1),那么此时我们就要从之前的 (n-1) 个结点中选出一个点与 (n-1) 相连构成当前的最小生成树.

    因为边 ((u,v)) 的边权 (w(u,v)=u mathrm{xor} v) 且图为完全图,所以我们每加入一个新结点 (n-1) 时,所有我们之前的 (0cdots n-2) 号结点都可以被选择.

    那么问题转化为:对于一个数 (n-1),我们需要选出一个整数 (xin[0,n-1)) 使得 ((n-1) mathrm{xor} x) 最小.

    考虑异或运算的定义:每一位相同为零,不同为一.

    那么我们选出的 (x),需要满足二进制意义下每一位和 (n-1) 尽量相同,并且从右到左(也就是二进位从低到高)的第一个不同的位置尽量低.

    那么结论就摆在眼前了,我们选择的这个 (x)((n-1)-mathrm{lowbit}(n-1)).

    为什么?想想 (mathrm{lowbit(x)}) 操作的定义:二进制下 (x) 最低的 1 和后面的 0 组成的二进制数.

    这样结论的正确性就显然了.

    我们 (F(n)) 的递推公式为 (F(n)=F(n-1)+(n mathrm{xor} (n mathrm{xor} mathrm{lowbit}(n)))).

    那么暴力递推的代码如下:

    (code?)

    #include<bits/stdc++.h>
    using namespace std;
    long long f[100005];
    signed main()
    {
        long long n;
        scanf("%lld",&n);
        f[0]=0;
        f[1]=1;
        for(long long i=2;i<n;++i)   f[i]=f[i-1]+(i^(i^(i&-i)));
        printf("%lld
    ",f[n-1]);
        return 0;
    }
    

    仔细观察一下递推式,(n mathrm{xor} (n mathrm{xor} mathrm{lowbit}(n))) 不就是 (mathrm{lowbit}(n)) 嘛!

    那么为题转化为求 (mathrm{lowbit}) 前缀和.

    通过打一个 (mathrm{lowbit}) 表的方法,我们发现 (mathrm{lowbit}) 的值十分有规律,就像这种形式:

    [ exttt{1 2 1 4 1 2 1 8 1 2 1 4 1 2 1 16 1 2 1 4 1 2 1 8 1 2 1 4 1 2 1 32}cdots ]

    其实这种规律要证明也很方便,只要根据二进制数末尾的情况即可得知.

    虽然这个规律没啥用,但是启发了我们按位统计贡献的方法在 (Theta(1)) 空间 (Theta(log_{2}n)) 的时间内计算出了 (mathrm{lowbit}) 前缀和.

    具体方法请参考代码.

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    signed main()
    {
        LL n;
        scanf("%lld",&n);
        LL ans=0,app=1,low=n;
        while(low>1)  ans+=app*(low>>1),low-=(low>>1),app<<=1;
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    python3.6关键字总结
    python文件操作
    基础之你容易忽略的细节
    模块一
    内置函数
    java成员变量和局部变量的区别
    java面向对象
    java数组
    java函数(方法)语法规则
    java流程控制switch
  • 原文地址:https://www.cnblogs.com/orchid-any/p/13708102.html
Copyright © 2020-2023  润新知