Wannafly #1 Xorto(维护异或前缀+暴力)

problem

给定一个长度为n的整数数组,问有多少对互不重叠的非空区间,使得两个区间内的数的异或和为0。

Input

第一行一个数n表示数组长度;
第二行n个整数表示数组;
1<=n<=1000,0<=数组元素<100000。

Output

一行一个整数表示答案。

Sample Input

3
0 0 0

Sample Output

5

Hint

([1,1],[2,2]),([1,1],[3,3]),([1,1],[2,3]),([1,2],[3,3]),([2,2],[3,3])


思路

首先异或运算有一些性质

名称示例
交换律a^b=b^a
结合律(a^b)^c = a^(b^c)
对于任何数xx^x=0,x^0=x
自反性A XOR B XOR B = A xor 0 = A (重要)


对于本题
由于数据量为1000,n^2为1e6,如果能找到方法,时间复杂度是允许的。

关键在于这个不重叠的非空区间怎么考虑

可以考虑n^2枚举区间,算出其xor,然后**找前面(避免区间重复)**xor相同的另一个区间。但如果纯暴力,对每一个枚举的区间,需要在前面再花O(n^2)来找,爆炸。

现在有两个地方可以优化
1.维护一个数组sum [i],记录arr[i]前ixor值,由上面自反性质知:x=sum[j] ^ sum[i-1];

2.对于找前面区间,采用权值数组,这是因为数据为1e5,而无论怎么异或,不会超过2e5的(胡算),所以可行。具体就是,对于每一次枚举区间后,顺便记录下前i个xor值,并权值下,这样后面需要找前面区间xor相同值时,只需访问quan[xor],即可直接获得数量。也就是说,由于本题区间不重叠,加上数比较小,因此可以这样在枚举时,记录前面的信息(也只需要前面的)。这样复杂度为2n^2。


代码示例

#include<bits/stdc++.h>
using namespace std;

int arr[1010];
int sum[1010];

int quan[200010];

int main()
{
    ios::sync_with_stdio(false);
    int n;
    cin>>n;
    for(int i=1;i<=n;++i){
        cin>>arr[i];
    }
    sum[0]=0;
    for(int i=1;i<=n;++i){
        sum[i]=sum[i-1] ^ arr[i];
    }

    long long ans=0;
    for(int i=1;i<=n;++i){
        for(int j=i;j<=n;++j){
            int x=sum[j] ^ sum[i-1];
            ans+=quan[x];
        }
        for(int j=1;j<=i;++j) quan[sum[i] ^ sum[j-1]]++;
    }
    cout<<ans<<endl;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值