zoukankan      html  css  js  c++  java
  • fjwc2019 D6T2 密文(trie+贪心)

    #194. 「2019冬令营提高组」密文

    设$s[i]$表示前$i$个密文的异或和

    容易发现,只要知道$s[0]~s[n](s[0]=0)$就可以知道每一位的值。

    转化一下,就变成了在完全图上求最小生成树,边权是$[l,r]$段的异或和

    然鹅数据范围太大了......

    但是边权是特殊的异或和!

    于是我们用一棵trie维护边权,每次用贪心的思想

    对于树上的某点,用最小的代价合并代表左右两个子树的连通块

    合并时代价的计算直接暴力就好辣

    可以证明每次的连通块数都减少一半

    即复杂度为$O(nlognloga_{i})$

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    inline int min(int a,int b){return a<b?a:b;}
    #define N 100005
    #define M 3000005
    int n,t,rt,u,a[N],ch[M][2],le[M],ri[M],h[N];
    long long ans;
    void ins(int &x,int d,int i){
        if(!x) x=++u;
        if(i>=0) ins(ch[x][(d>>i)&1],d,i-1);
    }
    int find(int x,int d,int i){
        if(i<0) return 0;
        int p=(d>>i)&1;
        return ch[x][p]?find(ch[x][p],d,i-1):find(ch[x][p^1],d,i-1)+(1<<i);
    }
    void dfs(int x,int d,int i){
        if(i<0){
            h[++t]=d; le[x]=ri[x]=t;
            return;
        }le[x]=t+1;
        int lc=ch[x][0],rc=ch[x][1],L,R,mn=1<<i;
        if(lc) dfs(lc,d,i-1);
        if(rc) dfs(rc,d|(1<<i),i-1);
        if(lc&&rc){
            if(ri[lc]-le[lc]<ri[rc]-le[rc]) L=lc,R=rc;
            else L=rc,R=lc;
            for(int j=le[L];j<=ri[L];++j)
                mn=min(mn,find(R,h[j],i-1));
            ans+=mn+(1<<i);
        }ri[x]=t;
    }
    
    int main(){
        freopen("secret.in","r",stdin);
        freopen("secret.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
            scanf("%d",&a[i]),a[i]^=a[i-1];
        for(int i=0;i<=n;++i) ins(rt,a[i],30);
        dfs(rt,0,30); printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    Linux文件及目录查找
    英语单词independent
    英语单词omitting
    英语单词deploy
    英语单词debug
    线程
    进程
    操作系统历史
    分布式爬虫
    爬虫基础
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/10547633.html
Copyright © 2011-2022 走看看