6759A异或序列

题目描述
已知一个长度为n的整数数列a1,a2,…,an,给定查询参数l、r,问在al,al+1,…,ar区间内,有多少子序列满足异或和等于k。也就是说,对于所有的x,y(l≤x≤y≤r),满足ax⊕ax+1⊕⋯⊕ay=k的x,y有多少组。

 

输入
输入第一行为3个整数n,m,k。第二行为空格分开的n个整数,即a1,a2,…,an。接下来m行,每行两个整数lj,rj,代表一次查询。

 

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

 

样例输入
4 5 1
1 2 3 1
1 4
1 3
2 3
2 4
4 4

 

样例输出
4
2
1
2
1

 

提示

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

使用莫队算法。

这里只讲一下细节和实现问题。

初始化cnt[0] = 1:如果只给你一个数据ai = 1,和k = 1,怎么计算?就是1^0 = 1,就是说使用了数字0来参与异或,所以初始化cnt[0] = 1.

同时,因为多使用了数字0,导致使用莫队模板时左端点 L-1

还有就是col [i] 中存储的是前i项异或的值

#include<bits/stdc++.h>
using namespace std;
const int M = 1e5 + 5;
struct Node
{
    int l,r,id;    
}q[M];
int col[M],cnt[M],ans[M],pos[M],block,tot;   
int n,m,k;
bool cmp(Node a, Node b)
{
    return pos[a.l]==pos[b.l] ? a.r<b.r : a.l<b.l;
}
void add(int x)
{
    tot += cnt[col[x]^k];
    cnt[col[x]]++;
}
void sub(int x)
{
    
    tot -= cnt[col[x]^k];
    cnt[col[x]]--; 
}
int main()
{
    ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);  //加快cin,cout速度,同时endl换成'\n'
    cin>>n>>m>>k;
    block = sqrt(n);
    for(int i = 1; i <= n; i++)
    {
        cin>>col[i];    
        col[i] ^= col[i-1];
        pos[i] = i/block + 1;
    }
    for(int i = 1; i <= m; i++)
    {
        cin>>q[i].l>>q[i].r;
        q[i].id = i;
    }
    sort(q+1,q+1+m,cmp);
    int l = 1, r = 0;
    cnt[0] = 1;
    for(int i = 1; i <= m; i++)
    {
        while(l>q[i].l)    l--,add(l-1);
        while(l<q[i].l)    sub(l-1),l++;
        while(r>q[i].r)    sub(r--);
        while(r<q[i].r)    add(++r);
        ans[q[i].id] = tot;
    }
    for(int i = 1; i <= m; i++)
        cout<<ans[i]<<'\n';
    return 0;
}

 

转载于:https://www.cnblogs.com/lwsh123k/p/9439713.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值