• 【题解】HDU5845 Best Division (trie树)


    【题解】HDU5845 Best Division (trie树)

    题意:给定你一个序列(三个参数来根),然后请你划分子段。在每段子段长度小于等于(L)且子段的异或和(le x)的情况下最大化分出子段的个数

    区间/子段/序列这种东西一大性质就是右端点之后与前面无关。

    (dp(i))表示上一个右端点是(i)且前面分出来的子段都满足条件的最多子段个数。

    直接转移(O(n^2))考虑优化这个东西,子段转前缀和是应该记起来的套路,现在问题就是变成查询两个前缀和的异或值是否满足条件。

    先不考虑(L)的限制

    处理两者异或的数据结构=trie树,于是可以建立一颗01trie,trie的叶子节点可以表示一个值,建立trie输入的字符串就是他对应位置的前缀和。

    考虑假如已经有了一个trie树了,在trie树上查询的实质是生成一个新的数。我们可以在生成这个数的时候根据该当前生成位上的新生成的那个数能否为(1),以及(x)是否为(1)讨论一下一个节点子树最大值。

    查询子树最大值可以直接线段树+dfs序,但这是数据结构学傻的表现。可以发现trie树树高是(log n)的,直接在插入的时候暴力跳父亲更新父亲的值即可。

    考虑(L)的限制,这个限制就相当于要让这个trie树支持删除操作,可以每个节点套一个multiset,但这是stl用傻了的表现。可以发现dp数组的值是不降的(这里其实存疑),所以可以直接删。

    复杂度(O(nlog n))

    //@winlere
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<set>
    
    using namespace std;  typedef long long ll;
    inline int qr(){
          register int ret=0,f=0;
          register char c=getchar();
          while(!isdigit(c))f|=c==45,c=getchar();
          while(isdigit(c)) ret=ret*10+c-48,c=getchar();
          return f?-ret:ret;
    }
    
    const int maxn=1e5+5;
    const int inf=0x3f3f3f3f;
    const int mod=(1<<28)-1;
    
    struct E{
          int son[2],Max,cnt;
          inline void clear(){memset(son,0,sizeof son);Max=0;cnt=0;}
          inline int&operator[](int x){return son[x];}
          inline void upd(const int&val,const int&tag){
    	    if(tag==1){
    		  if(Max<val) Max=val,cnt=1;
    		  else if(Max==val) ++cnt;
    	    }
    	    else {
    		  if(Max==val) --cnt;
    		  if(cnt==0) Max=0;
    	    }
          }
    }e[maxn*28];
    int sum[maxn],dp[maxn],cnt,n,x,L,p,q;
    
    inline void insert(const int&x,const int&val){
          int now=0;
          for(int t=27;~t;--t){
    	    int g=x>>t&1;
    	    if(!e[now][g]) e[now][g]=++cnt,e[cnt].clear();
    	    now=e[now][g];
    	    e[now].upd(val,1);
          }
    }
    
    inline void Delete(const int&x,const int&val){
          int now=0;
          for(int t=27;~t;--t){
    	    int g=x>>t&1;
    	    now=e[now][g];
    	    e[now].upd(val,-1);
          }
    }
    
    inline int que(const int&s,const int&x){
          int ret=-1,now=0;
          for(int t=27;~t;--t){
    	    int g=s>>t&1;
    	    if(x>>t&1){
    		  if(e[now][g])	ret=max(ret,e[e[now][g]].Max);
    		  if(e[now][g^1]) now=e[now][g^1];
    		  else return ret;
    	    }
    	    else{
    		  if(e[now][g]) now=e[now][g];
    		  else return ret;
    	    }
          }
          ret=max(ret,e[now].Max);
          return ret;
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
          freopen("in.in","r",stdin);
          //freopen("out.out","w",stdout);
    #endif
          int T=qr();
          while(T--){
    	    n=qr(); x=qr(); L=qr();
    	    sum[1]=qr(); p=qr(); q=qr();
    	    memset(e,0,sizeof e);
    	    e[cnt=0].clear();
    	    for(int t=2;t<=n;++t) sum[t]=(1ll*sum[t-1]*p+q)&mod;
    	    for(int t=2;t<=n;++t) sum[t]^=sum[t-1];
    	    memset(dp,-1,sizeof dp);
    	    insert(0,0); dp[0]=0;
    	    for(int t=1,l=t-L-1,k;t<=n;++t,++l){
    		  if(l>=0) if(dp[l]>=0) Delete(sum[l],dp[l]);
    		  k=que(sum[t],x);
    		  if(k>=0) dp[t]=k+1,insert(sum[t],dp[t]);
    	    }
    	    printf("%d
    ",dp[n]==-1?0:dp[n]);
          }
          return 0;
    }
    
    
    
  • 相关阅读:
    面试官问你如何解决web高并发这样回答就好了
    react-native页面间传递数据的几种方式
    图片上传知识点梳理
    使用Vue CLI 3将基于element-ui二次封装的组件发布到npm
    OpenCV学习笔记09--通过cvPtr2D或指针算法绘制图形
    [code segments] OpenCV3.0 SVM with C++ interface
    LINUX设备驱动程序笔记(一)设备驱动程序简单介绍
    redis 简单安装使用
    Linux常见压缩命令
    计算机网络13--网络应用的体系结构
  • 原文地址:https://www.cnblogs.com/winlere/p/11725419.html
Copyright © 2020-2023  润新知