zoukankan      html  css  js  c++  java
  • [HEOI2013]ALO

    https://zybuluo.com/ysner/note/1238170

    题面

    现在你拥有(n)颗宝石,每颗宝石有一个能量密度,记为(a_i)。现在你可以选取连续的一些宝石(必须多于一个)进行融合,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值与其他任意一颗宝石的能量密度按位异或的值
    现在你需要知道你怎么选取需要融合的宝石,才能使生成的宝石能量密度最大。

    • (nleq5*10^4)

    题面

    显然要可持久化(Trie)树。
    唯一有点费脑子的地方是次大值

    在一个区间找次大值会把复杂度弄得很鬼。
    换个角度想,如果枚举次大值,则有两种情况:

    • 最大值在左边,右边数都比次大值小(右端点右一个比次大值大)
    • 最大值在右边,左边数都比次大值小(左端点左一个比次大值小)

    实际上我们可以用链表维护大小关系。
    (a_i)从小到大枚举,用完这个数就把它删掉,这样左右端就是两个比它大的数,可以(O(1))确定区间左右端点。
    于是分情况统计答案即可。
    不加rt调1h系列

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #define re register
    #define il inline
    #define ll long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    #define fp(i,a,b) for(re int i=a;i<=b;i++)
    #define fq(i,a,b) for(re int i=a;i>=b;i--)
    using namespace std;
    const int mod=1e9+7,N=1e5+100;
    struct dat{int w,id;bool operator < (const dat &o) const {return w<o.w;}}a[N];
    int ysn,sum[N*50],t[N*50][2],l[N],r[N],ans,n,rt[N*50];
    il ll gi()
    {
       re ll x=0,t=1;
       re char ch=getchar();
       while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
       if(ch=='-') t=-1,ch=getchar();
       while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
       return x*t;
    }
    il void Build(re int x,re int &y,re int w,re int dep)
    {
      sum[y=++ysn]=sum[x]+1;
      if(dep<0) return;
      re int p=(w>>dep)&1;
      t[y][p^1]=t[x][p^1];
      Build(t[x][p],t[y][p],w,dep-1);
    }
    il int Query(re int x,re int y,re int w,re int dep)
    {
      if(dep<0) return 0;
      re int p=(w>>dep)&1,tmp=sum[t[y][p^1]]-sum[t[x][p^1]];
      if(tmp) return (1<<dep)+Query(t[x][p^1],t[y][p^1],w,dep-1);
      else return Query(t[x][p],t[y][p],w,dep-1);
    }
    int main()
    {
      n=gi();
      fp(i,1,n) a[i].w=gi(),a[i].id=i,l[i]=i-1,r[i]=i+1,Build(rt[i-1],rt[i],a[i].w,30);
      sort(a+1,a+1+n);
      fp(i,1,n)
        {
          re int x=a[i].id,z=l[x],y=r[x];
          r[z]=y;l[y]=z;
          if(z) ans=max(ans,Query(rt[l[z]],rt[y-1],a[i].w,30));
          if(y<=n) ans=max(ans,Query(rt[z],rt[r[y]-1],a[i].w,30));
        }
      printf("%d
    ",ans);
      return 0;
    }
    
  • 相关阅读:
    java如何编写多线程
    Java调用dll动态库
    HashMap源码解析
    LinkedList源码解析
    ArrayList源码解析
    springboot配置cxf
    java生成二维码
    原生js--跨域消息传递
    原生js--应用程序存储和离线web应用
    原生js--userData
  • 原文地址:https://www.cnblogs.com/yanshannan/p/9417089.html
Copyright © 2011-2022 走看看