zoukankan      html  css  js  c++  java
  • 【HDU

    BUPT2017 wintertraining(15) #7E

    题意

    把数组A划分为k个区间,每个区间不超过L长度,每一个区间异或和之和为S。现在求:S不超过X,区间个数的最大值。
    且A是这样给你的:A[1], P, Q。A[i]=(A[i-1]*P+Q)%M。M为(2^{28})

    题解

    容易想到dp, dp[i] :前 i 个数最多划分多少个区间。s[i]为前缀异或和。
    dp[i]=max(dp[j]+1),i-L<j<i,且s[j]^s[i](le) x。
    dp[n]就是答案。
    但是这样是(O(n^2))
    异或字典树 优化为(O(nlogA))

    字典树来维护s[i],总共N个数,最多28位,所以28*N个节点。
    要找 j 满足s[j]异或s[i]不超过x的最大的dp[j]+1。我们沿着字典树一位位找,如果x这一位是0,那么s[j]这一位肯定是和s[i]相同,异或起来才不超过x。如果x这一位是1,那么s[j]这一位可以和s[i]相同,直接取这个节点的最大值;也可以是与s[i]不同,然后继续走。

    因为长度不超过L,所以每次处理到第i个,要删去第i-L-1个。

    因为一个异或值可能出现多次,所以记录出现次数,删去时减少一次出现次数,次数为0时将对应的值设为-1。

    代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define M 268435456
    #define N 100005
    
    using namespace std;
    int dp[N], a[N];
    
    struct Trie{
        int ch[N*28][2];
        int val[N*28];//异或到当前位置不超过x的最多区间数
        int cnt[N*28];//出现次数
        int size;
        void init(){
            size=0;
            memset(ch,0,sizeof ch);
        }
        void Insert(int node, int pos, int id, int num){
            cnt[node]++;
            if(pos<0){
                val[node]=dp[id];
                return;
            }
            int bit=(num>>pos)&1;
            if(ch[node][bit]==0){
                ch[node][bit]=++size;
                val[size]=-1;
                cnt[size]=0;
            }
            Insert(ch[node][bit], pos-1, id, num);
            val[node]=max(val[node], val[ch[node][bit]]);
        }
    
        int Query(int node, int pos, int x, int num){
            if(pos<0)
                return val[node];
            int xbit=(x>>pos)&1, nbit=(num>>pos)&1;
            int ans=-1;
            if(xbit){
                if(ch[node][nbit])
                    ans = val[ch[node][nbit]];
                if(ch[node][!nbit])
                    ans = max(ans, Query(ch[node][!nbit], pos-1, x, num));
            }
            else if(ch[node][nbit])
                ans = Query(ch[node][nbit], pos-1, x, num);
            return ans;
        }
    
        void Delete(int node, int pos, int num){
            if(!--cnt[node])
                val[node]=-1;
            if(pos<0)
                return;
    
            int bit=(num>>pos)&1;
            Delete(ch[node][bit], pos-1, num);
            val[node]=val[ch[node][bit]];
            if(ch[node][!bit])
                val[node]=max(val[node],val[ch[node][!bit]]);
        }
    }trie;
    
    int main(){
        int t;
        scanf("%d", &t);
        while(t--){
            int n,x,l;
            scanf("%d%d%d", &n,&x,&l);
            int p,q;
            scanf("%d%d%d", &a[1],&p,&q);
            for(int i=2;i<=n;++i)
                a[i]=(a[i-1]*p+q)%M;
            for(int i=2;i<=n;++i)a[i]^=a[i-1];
    
            trie.init();trie.Insert(0,27,0,0);
    
            for(int i=1;i<=n;++i){
                if(i>l+1&&dp[i-l-1]!=-1)trie.Delete(0, 27, a[i-l-1]);
                dp[i]=trie.Query(0, 27, x, a[i]);
                if(dp[i]!=-1){
                    dp[i]++;
                    trie.Insert(0, 27, i, a[i]);
                }
            }
            printf("%d
    ", dp[n]==-1?0:dp[n]);
        }
        return 0;
    }
    
    
  • 相关阅读:
    2018.4.5课堂笔记
    黑白染色——封锁阳光大学
    末日游戏——杨辉三角+搜索
    dilworth定理+属性排序(木棍加工)
    伯努利错装信封问题
    zhx'code1
    字符串-----KMP竟然是18禁
    Presto Event Listener开发
    Presto安装完成之后需要做的
    Apache Calcite 论文学习笔记
  • 原文地址:https://www.cnblogs.com/flipped/p/7111682.html
Copyright © 2011-2022 走看看