• bzoj5301[CQOI2018]异或序列


    题意

    已知一个长度为 n 的整数数列 a[1],a[2],…,a[n] ,给定查询参数 l、r ,问在 [l,r] 区间内,有多少连续子
    序列满足异或和等于 k 。
    也就是说,对于所有的 x,y (l≤x≤y≤r),能够满足a[x]^a[x+1]^…^a[y]=k的x,y有多少组。

    分析

    这样的题目首先按照异或运算前缀和,就变成多次查询区间内有多少对数满足异或和为k.
    考虑简单的情况.异或和为0的时候,就变成查询区间内有多少对数相同.这是很显然的莫队题目.
    那么异或和为k的时候我们也可以考虑莫队.比较简明的思路是用trie树维护区间内所有的数字,加入/删除数字的时候更新答案.
    另一种方式是,把所有的前缀和异或上k,组成另外一个数列,那么对于询问的区间在原先的前缀和数列和异或k的前缀和数列上都有一个数集,然后找两个数集的相同的数对(就是找这样的数对:数值相同,但是一个数在这个数集,另一个数在那个数集).

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn=100005;
    int a[maxn],s1[maxn],s2[maxn];
    int cnt1[500000],cnt2[500000],ans;
    int SZ=250;
    struct query{
        int l,r,num,ans;
        void read(){
            scanf("%d%d",&l,&r);l--;
        }
    }Q[maxn];
    bool cmp1(const query &A,const query &B){
        if(A.l/SZ!=B.l/SZ)return A.l<B.l;
        return A.r<B.r;
    }
    void init(int l,int r){
        //printf("%d %d
    ",l,r);
        
        for(int i=l;i<=r;++i){
            //printf("%d ",s1[i]);
            cnt1[s1[i]]++;
        }//printf("
    ");
        for(int i=l;i<=r;++i){
            cnt2[s2[i]]++;//printf("%d ",s2[i]);
            ans+=cnt1[s2[i]];
        }//printf("
    ");
        //printf("%d
    ",ans);
    }
    void move(int l1,int r1,int l2,int r2){
        for(int i=l1;i<l2;++i){
            ans-=cnt2[s1[i]];ans-=cnt1[s2[i]];
            cnt1[s1[i]]--;cnt2[s2[i]]--;
            if(s1[i]==s2[i])ans+=1;
        }
        for(int i=l1-1;i>=l2;--i){
            ans+=cnt2[s1[i]];ans+=cnt1[s2[i]];
            cnt1[s1[i]]++;cnt2[s2[i]]++;
            if(s1[i]==s2[i])ans-=1;
        }
        for(int i=r1+1;i<=r2;++i){
            ans+=cnt2[s1[i]];ans+=cnt1[s2[i]];
            cnt1[s1[i]]++;cnt2[s2[i]]++;
            if(s1[i]==s2[i])ans-=1;    
        }
        for(int i=r1;i>r2;--i){
            ans-=cnt2[s1[i]];ans-=cnt1[s2[i]];
            cnt1[s1[i]]--;cnt2[s2[i]]--;
            if(s1[i]==s2[i])ans+=1;
        }
    }
    int res[maxn];
    int main(){
        int n,m,k;scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;++i){
            scanf("%d",a+i);
        }
        for(int i=1;i<=n;++i)s1[i]=s1[i-1]^a[i];
        for(int i=0;i<=n;++i)s2[i]=s1[i]^k;
        for(int i=1;i<=m;++i)Q[i].read();
        for(int i=1;i<=m;++i)Q[i].num=i;
        sort(Q+1,Q+m+1,cmp1);
        init(Q[1].l,Q[1].r);Q[1].ans=ans;
        for(int i=2;i<=m;++i){
            move(Q[i-1].l,Q[i-1].r,Q[i].l,Q[i].r);
            Q[i].ans=ans;
        }
        if(k==0){
            for(int i=1;i<=m;++i)Q[i].ans-=(Q[i].r-Q[i].l+1);
        }
        for(int i=1;i<=m;++i)Q[i].ans/=2;
        for(int i=1;i<=m;++i)res[Q[i].num]=Q[i].ans;
        for(int i=1;i<=m;++i)printf("%d
    ",res[i]);
        return 0;
    }
    
  • 相关阅读:
    关于使用css3属性:transform固定菜单位置,在滑动页面时菜单闪现抖动的问题
    使用iscroll.js插件时,遇到在Android端无法点击a超链的解决办法
    window.external的使用
    SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系
    chain.doFilter(request,response)含义
    巧用Ajax的beforeSend 提高用户体验
    getRequestDispatcher(path).forward(),,执行完,后面的代码居然还会执行!!!记得加return 啊亲
    @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
    ajax修改表单的值后dom没更新的解决办法
    .net core json序列化首字符小写和日期格式处理
  • 原文地址:https://www.cnblogs.com/liu-runda/p/10292730.html
Copyright © 2020-2023  润新知