zoukankan      html  css  js  c++  java
  • CF1553H XOR and Distance

    题目链接

    Codeforces 1553H XOR and Distance

    题目大意

    给定一个长度为 (n) 的数列 (a_i)​ 和一个数字 (k),满足 (a_i< 2^k),设

    [f(x)=min_{i=1}^nmin_{j=i+1}^n|(a_ioplus x)-(a_joplus x)| ]

    请对所有 (0leq xleq 2^k-1),求出 (f(x))

    (1leq kleq 19)(2leq nleq2^k)(a_i eq a_j)

    思路

    建出字典树,可以发现答案即为字典树的所有相邻叶子的距离最小值,考虑 (x) 变化时 (Trie) 形态的变化,注意到如果 (x) 只翻转第 (p) 位,那么 (Trie) 的所有深度为 (p-1) 的节点的左右儿子就会发生互换,变化量是 (O(2^{k-p})) 的,所以如果我们可以保证第 (i) 位被翻转了 (O(2^{k-i})) 次,那么这边的时间复杂度就可以做到 (1 imes2^k+2 imes2^{k-1}+...+2^k imes1=O(kcdot2^k)) 的了。

    好像只要每个 (x)(xoplus highbit(x)) 转移过来就可以满足这个条件了!但是这样好像不能一次做完,因为这个转移关系是一张 (DAG),还需要把 (Trie) 可持久化,看起来不好做。我们需要的是一个 (0)(2^k-1) 的排列,满足相邻两个数字只有一位被翻转了,且第 (i) 总共被翻转的次数是 (O(2^{k-i})) 的,第一个性质好像有点熟悉,这不就是格雷码嘛,手玩一下 (CSP2019) 给出的那个 (Gray;Code) 构造,可以发现它是第 (i) 位被翻转 (O(2^i)) 次,这里把二进制位做一下镜像对称即可,即 (FFT) 里的那个 (rev) 数组。

    时间复杂度对了,考虑具体维护信息,由于有左右儿子翻转这个操作,在 (Trie) 的每个节点上维护 (ans,mx,mn,len) 四个属性,分别表示当前子树内的答案,最大和最小值离左边界的距离(翻转后的),当前节点对应区间的长度,在 (Trie) 的形态变化时将信息上传即可。

    维护是线性的,所以时间复杂度 (O(kcdot2^k))

    Code

    #include<iostream>
    #include<stack>
    #include<fstream>
    #include<ctime>
    #define rep(i,a,b) for(int i = (a); i <= (b); i++)
    #define per(i,b,a) for(int i = (b); i >= (a); i--)
    #define N 600000
    #define K 20
    #define Inf 0x3f3f3f3f
    using namespace std;
    
    int Gray[N], rev[N], ans[N], Log[N];
    int n, k;
    
    struct Trie{
        struct node{
            int ans, c[2];
            int mn, mx, len;
        } t[N*K];
        int cnt;
    
        int New(int k){
            t[++cnt].ans = Inf;
            t[cnt].len = 1<<k, t[cnt].mn = Inf, t[cnt].mx = -1;
            return cnt;
        }
        void init(){ New(k), t[0].ans = Inf; }
    
        void update(int x){
            t[x].ans = min(t[t[x].c[0]].ans, t[t[x].c[1]].ans);
            t[x].mn = Inf, t[x].mx = -1;
            rep(i,0,1){
                int y = t[x].c[i];
                if(!y) continue;
                t[x].mn = min(t[x].mn, t[y].mn + i*t[y].len);
                t[x].mx = max(t[x].mx, t[y].mx + i*t[y].len);
            }
            int l = t[x].c[0], r = t[x].c[1];
            if(l && r) t[x].ans = min(t[x].ans, t[r].mn+t[l].len-t[l].mx);
        }
    
        void insert(int n){
            int x = 1;
            stack<int> s;
            per(i,k-1,0){
                s.push(x);
                int id = n>>i&1;
                if(!t[x].c[id]) t[x].c[id] = New(i);
                x = t[x].c[id];
            }
            t[x].mn = t[x].mx = 0;
            while(!s.empty()) update(s.top()), s.pop();
        }
    
        void change(int x, int lev, int p){
            if(x == 0) return;
            if(lev == p){
                swap(t[x].c[0], t[x].c[1]), update(x);
                return;
            }
            change(t[x].c[0], lev-1, p), change(t[x].c[1], lev-1, p);
            update(x);
        }
    
        void print(){
            rep(i,1,cnt) cout<<i<<":"<<t[i].c[0]<<","<<t[i].c[1]
                <<" "<<t[i].ans<<" "<<t[i].len<<' '<<t[i].mn<<","<<t[i].mx<<endl;
            cout<<endl;
        }
    } Trie;
    
    void init(){
        Gray[0] = 0, Gray[1] = 1;
        rep(i,1,k-1) rep(j,0,(1<<i)-1) 
            Gray[(2<<i)-j-1] = Gray[j]|(1<<i);
        rep(i,0,(1<<k)-1) rev[i] = rev[i>>1]>>1 | ((i&1)<<(k-1));
        rep(i,0,(1<<k)-1) Gray[i] = rev[Gray[i]];
        rep(i,0,k-1) Log[1<<i] = i;
    }
    
    int main(){
        ios::sync_with_stdio(false);
        cin>>n>>k;
        int a;
        Trie.init();
        rep(i,1,n) cin>>a, Trie.insert(a);
        init();
    
        ans[0] = Trie.t[1].ans;
        rep(i,1,(1<<k)-1){
            Trie.change(1, k-1, Log[Gray[i]^Gray[i-1]]);
            ans[Gray[i]] = Trie.t[1].ans;
        }
    
        rep(i,0,(1<<k)-1) cout<<ans[i]<<" ";
        cout<<endl;
        return 0;
    }
    
  • 相关阅读:
    288.软件开发过程与软件测试
    287.软件测试概述
    离散数学课程重点
    博客园美化
    渗透测试-Getshell总结
    C++迭代器
    每日一题2
    计算机网络面试总结(传输层)
    每日一题-1
    网络安全必备技能
  • 原文地址:https://www.cnblogs.com/Neal-lee/p/15125407.html
Copyright © 2011-2022 走看看