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(31N\sqrt{N})$的时间内解决。

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

现在预处理已经完成了。

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

所以总的时间复杂度是$O(31N\sqrt{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;
  }

可持久化trie做法:

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

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

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

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

时间: 2024-10-10 07:04:19

bzoj2741【FOTILE模拟赛】L的相关文章

BZOJ2741[FOTILE模拟赛]L

Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r. 为了体现在线操作,对于一个询问(x,y): l=min(((x+lastans)mod N)+1,((y+lastans)mod N)+1). r=max(((x+lastans)mod N)+1,((y+lastans)mod N)+1).

【BZOJ2741】【块状链表+可持久化trie】FOTILE模拟赛L

Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r. 为了体现在线操作,对于一个询问(x,y): l = min ( ((x+lastans) mod N)+1 , ((y+lastans) mod N)+1 ).r = max ( ((x+lastans) mod N)+1 , ((y+last

bzoj2741: 【FOTILE模拟赛】L

2741: [FOTILE模拟赛]L Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 2679  Solved: 766[Submit][Status][Discuss] Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r. 为了体现在线操作,对于一

【BZOJ】【2741】【FOTILE模拟赛】L

可持久化Trie+分块 神题……Orz zyf & lyd 首先我们先将整个序列搞个前缀异或和,那么某一段的异或和,就变成了两个数的异或和,所以我们就将询问[某个区间中最大的区间异或和]改变成[某个区间中 max(两个数的异或和)] 要是我们能将所有[l,r]的答案都预处理出来,那么我们就可以O(1)回答了:然而我们并不能. 一个常见的折中方案:分块! 这里先假设我们实现了一个神奇的函数ask(l,r,x),可以帮我们求出[l,r]这个区间中的数,与x最大的异或值. 我们不预处理所有的左端点,我

bzoj 2741: 【FOTILE模拟赛】L 分塊+可持久化trie

2741: [FOTILE模拟赛]L Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 1116  Solved: 292[Submit][Status] Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r. 为了体现在线操作,对于一个询问(x,y):

【BZOJ2741】【FOTILE模拟赛】L 可持久化字典树+分块

广告: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44496739"); } 题解: 首先我们处理出来sum[0,n]作为异或前缀和,然后答案就不再是[l,r]中间某段区间的异或和,而转化成求了[l?1,r]中任意两点异或和的最大值. 然后我们分块处理出fi,j表示 [第i块的开头,j

【分块】【可持久化Trie】bzoj2741 【FOTILE模拟赛】L

类似p3261,只是我们需要分块预处理anss[i][j]第i块到第j块的答案,然后整块的部分直接获得,零散的部分暴力. #include<cstdio> #include<algorithm> #include<cmath> using namespace std; #define N 12001 #define MAXBIT 31 #define BN 115 int root[N],ch[N*(MAXBIT+1)][2],sz[N*(MAXBIT+1)],tot;

BZOJ 2741【FOTILE模拟赛】L 分块+可持久化Trie树

题目大意 给出一个序列,求[l, r]中的最大连续xor 和. 强制在线 思路 先把整个序列分成n  √  块,预处理每一块的开头到每个数字的最大连续xor 和.这个我们只需处理出前缀xor 和,之后用可持久化Trie树就可以搞定.这样询问的右边就是整块的了.剩下左边的随便暴力一下就能过了.. CODE #define _CRT_SECURE_NO_WARNINGS #include <cmath> #include <cstdio> #include <cstring>

BZOJ 2741: 【FOTILE模拟赛】L [分块 可持久化Trie]

题意: 区间内最大连续异或和 5点调试到现在....人生无望 但总算A掉了 一开始想错可持久化trie的作用了...可持久化trie可以求一个数与一个数集的最大异或和 做法比较明显,前缀和后变成选区间内两个元素异或最大 考虑分块,预处理$f[i][j]$第i块到第j块选两个元素异或最大 询问时两边用可持久化trie暴力,中间整块已经预处理了 可以发现预处理复杂度$O(N\sqrt{N}*30)$,必须要枚举块中元素来算,不如直接保存下来$f[i][j]$为第i块到第j个元素的答案 如果说有什么教