• P4462 [CQOI2018]异或序列


    题目描述

    已知一个长度为n的整数数列 a1,a2,...,ana_1,a_2,...,a_na1,a2,...,an ,给定查询参数l、r,问在 al,al+1,...,ara_l,a_{l+1},...,a_ral,al+1,...,ar 区间内,有多少子序列满足异或和等于k。也就是说,对于所有的x,y (I ≤ x ≤ y ≤ r),能够满足 ax⨁ax+1⨁...⨁ay=ka_x igoplus a_{x+1} igoplus ... igoplus a_y = kaxax+1...ay=k 的x,y有多少组。

    输入输出格式

    输入格式:

    输入文件第一行,为3个整数n,m,k。

    第二行为空格分开的n个整数,即 a1,a2,..ana_1,a_2,..a_na1,a2,..an

    接下来m行,每行两个整数 lj,rjl_j,r_jlj,rj ,表示一次查询。

    输出格式:

    输出文件共m行,对应每个查询的计算结果。

    输入输出样例

    输入样例#1: 
    4 5 1
    1 2 3 1
    1 4
    1 3
    2 3
    2 4
    4 4
    输出样例#1: 
    4
    2
    1
    2
    1

    说明

    对于30%的数据, 1≤n,m≤10001 ≤ n, m ≤ 10001n,m1000

    对于100%的数据, 1≤n,m≤105,0≤k,ai≤105,1≤lj≤rj≤n

    Solution:

      这题面有毒,我不改了,题意就是$10^5$个数,$10^5$次查询,每次询问区间$[l,r]$中的子序列异或和为$k$的值的个数。

      首先,很容易想到异或的性质$a;xor;b;xor;b=a$,所以用前缀异或和$a[i]$表示前$i$个数的异或和,那么子序列$p_x;xor;p_{x+1}…;xor;p_{y-1};xor;p_{y}=a_y;xor;a_{x-1}$。

      若$a_{x-1};xor;a_y=k$,则$a_{x-1}=a_y;xor;k$,于是本题预处理出前缀异或和,将每个区间的下界$l-1$(因为$[l,r]$的异或和为$a[r];xor;a[l-1]$),加减一个数等同于修改并统计当前区间$a_p;xor;k$出现的个数,于是本题就成了一道莫队模板题——查询区间中某个数的个数。

    代码:

    #include<bits/stdc++.h>
    #define il inline
    #define ll long long
    using namespace std;
    const int N=100005;
    int n,m,k,a[N],pos[N],ans[N],num[N*2],tot;
    struct data{
        int l,r,id;
    }t[N];
    il int gi(){
        int a=0;char x=getchar();bool f=0;
        while((x<'0'||x>'9')&&x!='-')x=getchar();
        if(x=='-')x=getchar(),f=1;
        while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
        return f?-a:a;
    }
    il bool cmp(data a,data b){return pos[a.l]==pos[b.l]?a.r<b.r:a.l<b.l;}
    il void add(int p){tot+=num[k^a[p]],++num[a[p]];}
    il void del(int p){--num[a[p]],tot-=num[k^a[p]];}
    int main()
    {
        n=gi(),m=gi(),k=gi();
        int s=int(sqrt(n));
        for(int i=1;i<=n;i++)pos[i]=(i-1)/s+1,a[i]=a[i-1]^gi();
        for(int i=1;i<=m;i++)t[i].l=gi()-1,t[i].r=gi(),t[i].id=i;
        sort(t+1,t+m+1,cmp);
        for(int i=1,l=1,r=0;i<=m;i++){
            while(t[i].l>l)del(l++);
            while(t[i].l<l)add(--l);
            while(t[i].r<r)del(r--);
            while(t[i].r>r)add(++r);
            ans[t[i].id]=tot;
        }
        for(int i=1;i<=m;i++)printf("%d
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    HDOJ 5294 Tricks Device 最短路(记录路径)+最小割
    国家人工智能(AI)的美好前景
    预防埃博拉病毒感染的试验疫苗投入人体试验
    MySQL同步复制搭建方法指南详细步骤
    正则表达式,用相反的方式过滤掉特殊字符
    Linux入门教程
    Linux:-bash: ***: command not found
    linux命令大全
    linux下打开、关闭tomcat,实时查看tomcat运行日志
    chmod u+x ./j2sdk-1_4_2_04-linux-i586.bin的含义
  • 原文地址:https://www.cnblogs.com/five20/p/8910067.html
Copyright © 2020-2023  润新知