zoukankan      html  css  js  c++  java
  • bzoj2741【FOTILE模拟赛】L

    http://www.lydsy.com/JudgeOnline/problem.php?id=2741

    分块或可持久化trie

    可以先看看这个:高斯消元解XOR方程组

    分块做法:

    我们先求出前i个数的异或和,即b[i]=a[1]^a[2]^...^a[i],不失一般性,记b[0]=0。

    那么a[i]^a[i+1]^...^a[j-1]^a[j]=b[j]^b[i-1]。

    所以原问题变成在b[l-1...r]中任选2个数,使得异或和最大。

    我们将0..N分成$sqrt{N}$块,不妨记第i块的左端为l[i],右端为r[i]。

    每个块建一棵二进制树,将所有的数插入到所在的块的二进制树中。

    然后记$f[i][j]$表示b[i]与第j块中某一个数异或(即b[i]与b[l[j]...r[j]]中的某一个数异或),得到的最大的异或和是多少。这个可以在$O(31Nsqrt{N})$的时间内解决。

    $g[i][j]$表表示第i块中某一个数与第j块中某一个数异或(即b[l[i]...r[i]]中的某一个数异或与b[l[j]...r[j]]中的某一个数异或),得到的最大的异或和是多少。这个可以在$O(Nsqrt{N})$从F数组得到。

    现在预处理已经完成了。

    对于询问区间[l-1...r],分类讨论一下就可以了,时间复杂度是$O(MN)$

    所以总的时间复杂度是$O(31Nsqrt{N}+MN)$

    #include<cstdio>
    #include<cstdlib>
    #include<iostream>
    #include<fstream>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<vector>
    #include<functional>
    #include<deque>
    #include<cctype>
    #include<climits>
    #include<complex>
    //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj
     
    using namespace std;
    
    typedef long long LL;
    typedef double DB;
    typedef pair<int,int> PII;
    typedef complex<DB> CP;
    
    #define mmst(a,v) memset(a,v,sizeof(a))
    #define mmcy(a,b) memcpy(a,b,sizeof(a))
    #define fill(a,l,r,v) fill(a+l,a+r+1,v)
    #define re(i,a,b)  for(i=(a);i<=(b);i++)
    #define red(i,a,b) for(i=(a);i>=(b);i--)
    #define ire(i,x) for(typedef(x.begin()) i=x.begin();i!=x.end();i++)
    #define fi first
    #define se second
    #define m_p(a,b) make_pair(a,b)
    #define p_b(a) push_back(a)
    #define SF scanf
    #define PF printf
    #define two(k) (1<<(k))
    
    template<class T>inline T sqr(T x){return x*x;}
    template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
    template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}
    
    const DB EPS=1e-9;
    inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
    const DB Pi=acos(-1.0);
    
    inline int gint()
      {
            int res=0;bool neg=0;char z;
            for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
            if(z==EOF)return 0;
            if(z=='-'){neg=1;z=getchar();}
            for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
            return (neg)?-res:res; 
        }
    inline LL gll()
      {
          LL res=0;bool neg=0;char z;
            for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
            if(z==EOF)return 0;
            if(z=='-'){neg=1;z=getchar();}
            for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar());
            return (neg)?-res:res; 
        }
    
    const int maxN=12000;
    const int maxcnt=120;
    
    struct Tnode
      {
          Tnode *son[2];
            inline Tnode(){son[0]=son[1]=0;}      
      };
    
    int N,Q;
    int len,cnt,id[maxN+10],l[maxcnt+10],r[maxcnt+10];
    int a[maxN+100];
    Tnode *rt[maxcnt+10];
    int f[maxN+100][maxcnt+10];
    int g[maxcnt+100][maxcnt+10];
    int lastans;
    
    int t[40];
    inline void insert(Tnode *p,int v)
      {
          int i;
          re(i,1,31)t[i]=v&1,v>>=1;
          red(i,31,1)
            {
                if(!p->son[t[i]])p->son[t[i]]=new Tnode;
                p=p->son[t[i]];
            }
      }
    inline int find(Tnode *p,int v)
      {
          int i,res=0;
          re(i,1,31)t[i]=v&1,v>>=1;
          red(i,31,1)
            {
                int to=(p->son[t[i]^1])?t[i]^1:t[i];
                res=(res<<1)+to;
                p=p->son[to];
            }
          return res;
      }
    
    int main()
      {
          freopen("bzoj2741.in","r",stdin);
          freopen("bzoj2741.out","w",stdout);
          int i,j;
          N=gint()+1;Q=gint();
            re(i,2,N)a[i]=gint();
            re(i,1,N)a[i]^=a[i-1];
          len=int(sqrt(DB(N)));
          re(i,1,N)
            {
                if((i-1)%len==0)r[cnt]=i-1,l[++cnt]=i;
                id[i]=cnt;
            }
          r[cnt]=N;
          re(i,1,cnt)rt[i]=new Tnode;
          re(i,1,N)insert(rt[id[i]],a[i]);
          re(i,1,N)re(j,1,cnt)f[i][j]=a[i]^find(rt[j],a[i]);
          re(i,1,N)re(j,1,cnt)upmax(g[id[i]][j],f[i][j]);
          lastans=0;
          while(Q--)
            {
                int x=gint(),y=gint();
                int L=int( min( (LL(x)+LL(lastans))%LL(N-1)+1 , (LL(y)+LL(lastans))%LL(N-1)+1 ) ) +1 ;
                int R=int( max( (LL(x)+LL(lastans))%LL(N-1)+1 , (LL(y)+LL(lastans))%LL(N-1)+1 ) ) +1 ;
                L--;
                lastans=0;
                if(id[L]==id[R] || id[L]+1==id[R])
                  {
                      re(i,L,R)re(j,i,R)upmax(lastans,a[i]^a[j]);
                  }
                else
                  {
                    int p=(L==l[id[L]])?id[L]:id[L]+1,q=(R==r[id[R]])?id[R]:id[R]-1;
                    re(i,p,q)re(j,i,q) upmax(lastans,g[i][j]);
                    re(i,L,l[p]-1)re(j,p,q) upmax(lastans,f[i][j]);
                    re(i,r[q]+1,R)re(j,p,q) upmax(lastans,f[i][j]);
                    re(i,L,l[p]-1)re(j,r[q]+1,R)upmax(lastans,a[i]^a[j]);
                    re(i,L,l[p]-1)re(j,i+1,l[p]-1)upmax(lastans,a[i]^a[j]);
                    re(i,r[q]+1,R)re(j,i+1,R)upmax(lastans,a[i]^a[j]);
                  }
                cout<<lastans<<endl;
            }
          return 0;
      }
    View Code

    可持久化trie做法:

    可持久化trie的想法比较简单。

    第i棵trie中插入了b[0...i],我们可以从第i-1棵trie得到。

    对于询问区间[l-1...r],枚举其中一个数,然后同时在第r棵trie和第l-2棵trie中走即可。

    总的时间复杂度是$O(31MN)$

  • 相关阅读:
    Win7双击任务栏图标导致窗口还原的问题
    一致性哈希算法及其在分布式系统中的应用(转)
    CAP理论(转)
    从Android界面开发谈起(转)
    Android开发入门之Window 环境概念介绍(转)
    数据库缓存技术(转)
    VoltDB开篇 简介(转)
    window下如何让php支持openssl(转)
    mysql分表的3种方法(转)
    linux crontab 每10秒执行一次
  • 原文地址:https://www.cnblogs.com/maijing/p/4768694.html
Copyright © 2011-2022 走看看