zoukankan      html  css  js  c++  java
  • 「2019冬令营提高组」密文

    传送门

    考虑前缀异或和 $b[i]$

    如果知道每个 $b[i]$ 就相当于知道所有数

    初始知道 $b[0]$,每次操作 $l,r$ 就是求出 $b[l-1] xor b[r]$

    考虑转化成图论模型,把 $b[i]$ 看成点(包括 $b[0]$),每次操作相当于把两个点 $b[l-1],b[r]$ 连边,边权为 $b[l-1] xor b[r]$

    当整个图变成一个联通块时就相当于求出了所有的 $b[i]$

    要求图联通时代价最小,显然考虑 prim 求最小生成树

    对于一个点 $u$,找一个点 $v$ 使得边权最小,显然可以用 $trie$ 来找

    但是每次都暴力搞还是太慢了,考虑贪心

    对于 $trie$ 上的一个节点,如果只考虑左儿子的联通块和右儿子的联通块合并,那么最小代价必然是左儿子子树中的一个叶子节点和右儿子子树中的一个叶子节点连起来

    那么对 $trie$ 上的每个节点 $u$,递归左右儿子,先让左右儿子的子树变成联通块,然后,枚举它左子树的每个叶子节点,然后暴力往右子树中查询最小值,最后把最小代价加到答案里

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<vector>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=1e5+7;
    const ll INF=1e18+7;
    int n,b[N];
    int ch[N*31][2],rt,tot;//trie
    vector <int> G[N*31];//G存每个节点的子树所有叶子代表的b
    void insert(int &u,int x,int d)//插入
    {
        if(!u) u=++tot;
        G[u].push_back(x);
        if(d>=0) insert(ch[u][ (x>>d)&1 ],x,d-1);
    }
    int query(int u,int x,int d)//查询
    {
        if(d<0) return 0;
        if(ch[u][ (x>>d)&1 ]) return query(ch[u][ (x>>d)&1 ],x,d-1);
        else return query(ch[u][ ((x>>d)&1)^1 ],x,d-1) + (1<<d);
    }
    ll ans;
    void solve(int u,int d)//递归处理
    {
        if(d<0) return;
        if(ch[u][0]) solve(ch[u][0],d-1);
        if(ch[u][1]) solve(ch[u][1],d-1);
        if(ch[u][0]&&ch[u][1])
        {
            ll res=INF; int lc=ch[u][0],rc=ch[u][1];
            for(int i=G[lc].size()-1;i>=0;i--)
                res=min(res,1ll*query(rc,G[lc][i],d-1));
            ans+=res+(1<<d);
        }
    }
    int main()
    {
        freopen("secret.in","r",stdin);
        freopen("secret.out","w",stdout);
        n=read();
        for(int i=1;i<=n;i++) b[i]=b[i-1]^read();
        for(int i=0;i<=n;i++) insert(rt,b[i],29);//注意b[0]也要插入
        solve(rt,29);
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    智慧养老民政监管平台建设方案
    CF600E Lomsat gelral dsu on tree
    dsu on tree详解
    【Spring 从0开始】Spring5 新功能,整合日志框架 Log4j2
    【Spring 从0开始】JdbcTemplate 数据库事务管理
    【Spring 从0开始】JdbcTemplate 数据库事务参数
    【Spring 从0开始】JdbcTemplate 数据库事务管理
    【Spring 从0开始】JdbcTemplate 操作数据库
    【Spring 从0开始】AOP 操作
    【Spring 从0开始】AOP 操作中的相关术语、环境准备
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/10548565.html
Copyright © 2011-2022 走看看