[编程题]xor
  • 热度指数:1947 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 64M,其他语言128M
  • 算法知识视频讲解
给出n个数字 a_1,...,a_n,问最多有多少不重叠的非空区间,使得每个区间内数字的xor都等于0。

输入描述:
第一行一个整数n; 第二行n个整数 a_1,...,a_n; 对于30%的数据,n<=20; 对于100%的数据,n<=100000, a_i<=100000;


输出描述:
一个整数表示最多的区间个数;
示例1

输入

4
3 0 2 2

输出

2
//感觉可以优化,但是通过了= =
//直观的思路
#include<iostream>
using namespace std;

int main() {
    int n;
    cin>>n;
    int a[n];
    for(int i = 0; i < n; i++) {
        cin>>a[i];
    }
    int dp[n][n][2];
    for(int i = 0; i < n; i++) {
        dp[i][i][0] = a[i];
        dp[i][i][1] = (a[i] == 0) ? 1:0;
    }
    
    for(int j = 1; j < n; j++) {
        for(int i = 0; i+j < n; i++) {
            dp[i][i+j][0] = dp[i][i+j-1][0]^a[i+j];
            dp[i][i+j][1] = (dp[i][i+j][0] == 0) ? 1:0;
            for(int k = 0; k < j; k++) {
                dp[i][i+j][1] = max(dp[i][i+j][1], dp[i][i+k][1]+dp[i+k+1][i+j][1]);
            }
        }
    }
    cout<<dp[0][n-1][1]<<endl;
    
    return 0;
}

发表于 2020-07-04 14:29:17 回复(0)
#include <bits/stdc++.h>
using namespace std;

int main(){
    int n, x, s=0, cnt=0;
    scanf("%d", &n);
    unordered_map<int, bool> mp;
    mp[0] = true;
    while(n--){
        scanf("%d", &x);
        s ^= x;
        if(mp[s]){
            cnt++;
            mp.clear();
        }
        mp[s] = true;
    }
    printf("%d\n", cnt);
    return 0;
}

发表于 2020-11-05 01:04:40 回复(0)
没看懂题目的我?????是太笨了吗
发表于 2019-03-05 15:36:30 回复(0)
/// @brief 给出n个数字 a_1,...,a_n,问最多有多少不重叠的非空区间,使得每个区间内数字的xor都等于0
/// https://www.nowcoder.com/questionTerminal/7cffea0c097c4337821ab3ba25447c1c
///
/// @file maxNonOverlapSeg.cpp
/// @author cuichao
/// @date 2018-09-08

#include <stdio.h>
#include <iostream>

using namespace std;

/// @brief find max num of non-overlap segments in array
///
/// find max segment num in array, such that xor of numbers in each segment
/// is zero
/// 
/// @param a Input array
/// @param maxSeg Recorded intermedia results, maxSeg[i] is max non-onverlap
/// segment num for array[i:end] 
/// @param be Begin idx of subarray to search
/// @param n Lenght of input array
/// @return int Max num of non-overlap segments
int findMaxNonOverlapSeg(const int a[], int maxSeg[], int be, int n){
    if(be >= n) return 0;
    if(maxSeg[be] > 0) return maxSeg[be];

    int maxSegNum = 0, segNum = 0;
    int j, re_xor;
    for(int i=be; i<n; i++){
        j = i;
        re_xor = a[j++];
        while(j<n && re_xor!=0) re_xor ^= a[j++];

        if(re_xor == 0){
            segNum = 1 + findMaxNonOverlapSeg(a, maxSeg, j, n);
            maxSegNum = max(maxSegNum, segNum);
        }
    }
    maxSeg[be] = maxSegNum;
    return maxSeg[be];
}

int main(){
    int N;
    cin >> N;

    int a[N];
    int maxSeg[N];
    for(int i=0; i<N; i++){
        cin >> a[i];
        maxSeg[i] = 0;
    }

    int maxSegNum = findMaxNonOverlapSeg(a, maxSeg, 0, N);
    printf("%d\n", maxSegNum);
    return 0;
}
编辑于 2018-09-08 21:56:07 回复(0)
#用一个set或者map更新一下。每重复出现一次就清空一下所有信息并且答案++,
#然后重新保存set或map。开始的时候要放一个map[0]为了考虑边界条件(也就是一开始就是0的情况)
a=[3,0,2,2]
num = set([0])
last = 0
ans = 0
for i in a:
    last ^= i
    if last in num: 
        print(last)
        ans += 1
        num = set([0])    #
        last = 0
    else:
        num.add(last)
print(ans)

发表于 2019-08-27 01:12:59 回复(0)
题都没读懂
4
3,0,2,2
怎么得到2的?

编辑于 2021-07-16 15:49:32 回复(12)
//B站讲解https://www.bilibili.com/video/BV13g41157hK?t=1897.1&p=30
#include <iostream>
#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;

int main() {
    int n;
    cin>>n;
    vector<int>nums(n);
    // dp[i] -> arr[0..i]在最优划分的情况下,异或和为0最多的部分是多少个
    vector<int>dp(n);
    for(int i=0;i<n;i++){
        cin>>nums[i];
    }

    int xor1 = 0;
    // key : 从0出发的某个前缀异或和
	// value : 这个前缀异或和出现的最晚位置(index)
    unordered_map<int, int>hash;
    hash[0]=-1;
    for(int i=0;i<n;i++){
        xor1^=nums[i];// xor -> 0..i所有数的异或和
        if(hash.count(xor1)){// 上一次,这个异或和出现的位置 
            // pre -> pre + 1 -> i , 最优划分,最后一个部分的开始位置
            // (pre+1, i)最后一个部分
            // a    0..a   (a+1..i)
            int pre=hash[xor1];
            dp[i]=pre==-1? 1:(dp[pre]+1);
        }
        if(i>0){
            dp[i]=max(dp[i-1],dp[i]);
        }
        hash[xor1]=i;//xor1的下标只存最近位置的
    }
    cout<<dp[n-1];
    return 0;


}
// 64 位输出请用 printf("%lld")

发表于 2024-04-08 23:14:56 回复(0)
直接贪心,区间异或操作后出现重复即可说明该段区间异或值为0。
使用无序map记录过程,出现重复后需要清空
#include <bits/stdc++.h>
using namespace std;
 
int main(){
    int n, x, s=0, cnt=0;
    scanf("%d", &n);
    unordered_map<int, bool> mp;
    mp[0] = true;
    while(n--){
        scanf("%d", &x);
        s ^= x;
        if(mp[s]){
            cnt++;
            mp.clear();
            s=0;
        }
        mp[s] = true;
    }
    printf("%d\n", cnt);
    return 0;
}


发表于 2022-07-21 21:43:56 回复(0)
这题有问题吧
输入:10
            9 1 6 10 4 8 5 0 3 10 
            输出是4啊,答案给个2什么意思?
我的代码:
a=int(input())
b=list(map(int,input().split()))
i=0
for n in range(a):
    c=b[n]
    for m in range(n+1,a):
        c=c^b[m]
        if(c==0):
            i+=1
print(i)
发表于 2022-05-22 22:12:38 回复(0)
记得用map存异或值,记录与当前异或值相同的最长前缀的位置,用空间换时间
发表于 2019-11-19 21:38:57 回复(0)
贪心+二分
首先我们知道若[L,R]这段区间异或和为0,则prefix[R] - prefix[L-1]==0,即prefix[R] = prefix[L-1],所以我们将这些相等的位置都存下来,题目说了a_i不会超过100000,那么prefix[]最大也不会超过111111。
当我们到达i位置后,我们需要往前面去找与该段前缀和相等的位置(但是不能够早于前一段划分的点),0需要特判。
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int prefix[N],a[N];
vector<int> v[N];
int main(){
    int n;
    scanf("%d",&n);
    v[0].push_back(0);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        prefix[i]=prefix[i-1]^a[i];
        v[prefix[i]].push_back(i);
    }
    int pos=0,ans=0;
    for(int i=1;i<=n;i++){
        if(a[i]==0){
            pos=i;
            ans++;
        }
        else{
            int num=prefix[i];
            int idx=lower_bound(v[num].begin(),v[num].end(),i)-v[num].begin();
            //printf("%d %d\n",idx,pos);
            if(idx>0&&v[num][idx-1]>=pos){
                pos=i;
                ans++;
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}



编辑于 2019-06-13 09:10:11 回复(0)
// 牛客 XOR
// https://www.nowcoder.com/questionTerminal/7cffea0c097c4337821ab3ba25447c1c
#include <unordered_map>
#include <vector>
#include <algorithm>
#include <iostream>

using namespace std;

int mostXOR(vector<int> &arr)
{
    if (arr.empty())
        return 0;

    unordered_map<int, int> map;
    vector<int> dp(arr.size(), 0);

    int eor = 0;
    map[0] = -1;
    map[arr[0]] = 0;
    dp[0] = arr[0] == 0 ? 1 : 0;
    for (int i = 1; i != arr.size(); ++i)
    {
        eor ^= arr[i];
        if (map.find(eor) != map.end())
        {
            int preEorIndex = map[eor];
            dp[i] = preEorIndex == -1 ? 1 : (dp[preEorIndex] + 1);
        }
        dp[i] = std::max(dp[i - 1], dp[i]);
        map[eor] = i;
    }
    return dp.back();
}

int main()
{
    int N;
    cin >> N;
    vector<int> arr(N, 0);
    for (auto &i : arr)
        cin >> i;
    cout << mostXOR(arr) << endl;
    return 0;
}

编辑于 2019-04-22 13:19:41 回复(1)
9 1 6 10 4 8 5 0 3 10 
这个是怎样得到2的
发表于 2019-02-16 15:16:00 回复(0)
这道题最大的坑点难道不是"空间需要连续的"吗...建议加上这个条件
发表于 2018-10-22 21:08:06 回复(1)
//设置一个start位置用来分隔前面已经找到的异或为0的最多的区间数,后面每个数字向前搜索只能到start位置,若搜索到start位置前区间数只会变少。num对区间数进行计数。
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()){
            int n = sc.nextInt();
            int arr[] = new int[n];
            for(int i=0;i<n;i++){
                arr[i] = sc.nextInt();
            }
            int num=0;
            int start =0;
            for(int i=0;i<n;i++){
                int tmp=0;
                for(int j=i;j>=start;j--){
                    tmp^=arr[j];
                    if(tmp==0){
                        num++;
                        start = i+1;
                        break;
                    }
                }
            }
            System.out.println(num);
        }
    }
}
发表于 2018-09-15 00:02:42 回复(0)
终于搞懂题目意思了。。。
即找出最大的k,使得存在k个区间(l(i),r(i))满足
1<=l(i)<=r(i)<=n (1<=i<=k), r(i)<l(i+1) (1<=i<k),且
a[l(i)] xor a[l(i)+1] xor …. xor a[r(i)] ==0 (1<=i<=k)
例如:
当输入为[3, 0, 2, 2]时,答案为2,存在2个区间[0] 和 [2, 2]满足;
当输入为[2, 2, 0, 2, 2]时,答案为3,[2, 2],[0] 和[2, 2]满足
发表于 2018-09-07 21:42:02 回复(1)
#include <iostream>
#include <vector>
#include <algorithm>

using std::cout;
using std::cin;
using std::endl;
using std::vector;
using Vec = vector<int>;
using Table = vector<vector<int>>;

int main() {
    int n = 0, res = 0;
    cin >> n;
    int rdFlag = n;
    //
    Vec input;
    // 动态规划表 n*n,i行j列 代表 本次区间为[i,j]时 [0,j]区间的总可能数
    Table tb(n, Vec(n, 0));
    // tb 中第n列的最大值
    Vec maxInCol(n, 0);

    input.reserve(n);
    while (rdFlag) {
        int tmp = 0;
        cin >> tmp;
        input.push_back(tmp);
        rdFlag--;
    }

    // O(n^2)
    for (int j = 0; j < input.size(); j++) {
        int xorFlag = input[j];
        for (int i = j; i >= 0; i--) { // 从第j列往前找 xor为零的区间
            // 处理单个0的情况
            if (i == j) {
                if (input[i] == 0) {
                    tb[i][j] = (i > 0) ? (maxInCol[i - 1] + 1) : (1);
                } else {
                    tb[i][j] = (i > 0) ? (maxInCol[i - 1]) : (0);
                }

                if (tb[i][j] > maxInCol[j]) {
                    maxInCol[j] = tb[i][j];
                }
                continue;
            }
            // 处理正常区间
            xorFlag = xorFlag^input[i];
            if (0 == xorFlag) {
                tb[i][j] = (i > 0) ? (maxInCol[i - 1] + 1) : (1);
            } else {
                tb[i][j] = (i > 0) ? (maxInCol[i - 1]) : (0);
            }

            if (tb[i][j] > maxInCol[j]) {
                maxInCol[j] = tb[i][j];
            }
        }// for (int i = j; i >= 0; i--)
    }// for (int j = 0; j < input.size(); j++)
    res = maxInCol[n - 1];
    cout << res;
    return 0;
}

发表于 2018-08-29 02:45:07 回复(4)