1 条题解

  • 0
    @ 2025-12-3 9:10:29
    • 一步一步从 O(n5)O(n^5) 的 40 分
    • 优化到 O(n×m)O(n \times m) 的 100 分
    #include <bits/stdc++.h>
    using namespace std;
    
    using i64 = long long;
    
    // 暴力, O(n^4), 60 分
    i64 solve60(const vector<int>& a, int n, int m) {
    	vector<int> s(n + 1, 0);
    	i64 cnt = 0;
    	
        // 前缀异或
        for (int i = 1; i <= n; i++)  s[i] = s[i - 1] ^ a[i];
        
    	// 第一个区间 [l1, r1]
    	for (int l1 = 1; l1 <= n; l1++) for (int r1 = l1; r1 <= n; r1++) {
            
            // 第一个区间 [l2, r2]
    		for (int l2 = r1 + 1; l2 <= n; l2++) for (int r2 = l2; r2 <= n; r2++) {
                
    			// [l1, r1], [l2, r2]
    			int ans = 0;
    			ans = s[r1] ^ s[l1 - 1] ^ s[r2] ^ s[l2 - 1];
    			if (ans == m) cnt++;
    		}
    	}
    	return cnt;
    }
    
    i64 solvePre80(const vector<int>& a, int n, int m) {
        int maxi = 2048;
        
        // L(i, j): 以 a[i] 结尾, 异或值为 j 的子数组个数
        vector<vector<int>> L(n + 1, vector<int>(maxi + 1, 0));
        L[1][a[1]] = 1;
        for (int i = 2; i <= n; i++) {
            L[i][a[i]]++;
            for (int j = 0; j < maxi; j++) {
                L[i][j ^ a[i]] += L[i - 1][j];
            }
        }
        
        // R(i, j): 以 a[i] 开始, 异或值为 j 的子数组个数
        vector<vector<int>> R(n + 1, vector<int>(maxi + 1, 0));
        R[n][a[n]] = 1;
        for (int i = n - 1; i >= 1; i--) {
            R[i][a[i]]++;
            for (int j = 0; j < maxi; j++) {
                R[i][j ^ a[i]] += R[i + 1][j];
            }
        }
        
        i64 cnt = 0;
        for (int i = 1; i < n; i++) for (int j = 0; j < maxi; j++) {
            i64 sum = 0;
            for (int k = i + 1; k <= n; k++) sum += R[k][j ^ m];
            cnt += L[i][j] * sum;
        }
        return cnt;
    }
    
    i64 solve80(const vector<int>& a, int n, int m) {
        int maxi = 2048;
        
        // L(i, j): 以 a[i] 结尾, 异或值为 j 的子数组个数
        vector<vector<int>> L(n + 1, vector<int>(maxi + 1, 0));
        L[1][a[1]] = 1;
        for (int i = 2; i <= n; i++) {
            L[i][a[i]]++;
            for (int j = 0; j < maxi; j++) {
                L[i][j ^ a[i]] += L[i - 1][j];
            }
        }
        
        // R(i, j): 以 a[i] 开始, 异或值为 j 的子数组个数
        vector<vector<int>> R(n + 1, vector<int>(maxi + 1, 0));
        R[n][a[n]] = 1;
        for (int i = n - 1; i >= 1; i--) {
            R[i][a[i]]++;
            for (int j = 0; j < maxi; j++) {
                R[i][j ^ a[i]] += R[i + 1][j];
            }
        }
        
        // 对 R 求下后缀和
        // R(i, j): 以 a[i..n] 开始的, 异或值为 j 的子数组的个数
        for (int i = n - 1; i >= 1; i--) {
            for (int j = 0; j < maxi; j++) {
                R[i][j] += R[i + 1][j];
            }
        }
        
        i64 cnt = 0;
        for (int i = 1; i < n; i++) for (int j = 0; j < maxi; j++) {
            cnt += (i64) L[i][j] * R[i + 1][j ^ m];
        }
        return cnt;
    }
    
    
    i64 solve100(const vector<int>& a, int n, int m) {
        int maxi = 2048;
        
        // L(i, j): 以 a[i] 结尾, 异或值为 j 的子数组个数
        vector<int> L(maxi + 1, 0);
        for (int i = 1; i < n; i++) {  // 注意这里是 i < n, 不是 i <= n
            vector<int> t(maxi + 1, 0);
            t[a[i]] = 1;
            for (int j = 0; j < maxi; j++) t[j ^ a[i]] += L[j];
            L = t;
        }
        // 此时 L 就是 i = n - 1 的结果
        
        i64 ans = 0;
        vector<int> R(maxi + 1, 0);
        vector<int> r(maxi + 1, 0);  // R 的前缀和
        for (int i = n; i > 1; i--) {
            vector<int> t(maxi + 1, 0);
            t[a[i]] = 1;
            for (int j = 0; j < maxi; j++) t[j ^ a[i]] += R[j];
            R = t;
            
            // 计算前缀和
            for (int j = 0; j < maxi; j++) r[j] += R[j];
            
            // 以 i = n 为例, 此时我们需要 i = n - 1 时 L 的结果
            for (int j = 0; j < maxi; j++) ans += L[j] * r[j ^ m];
            
            // 以 i = n 为例, 需要将 L 还原成 i = n - 2 时的结果, 为下一次 for 准备
            L[a[i - 1]]--;
            vector<int> tmp(maxi, 0);
            for (int j = 0; j < maxi; j++) tmp[j] = L[j ^ a[i - 1]];
            L = tmp;
        }
        return ans;
    }
    
    int main() {
    	ios::sync_with_stdio(false);
    	cin.tie(0); cout.tie(0);
    
    	int n, m;
    	cin >> n >> m;
    
    	vector<int> a(n + 1);
    	for (int i = 1; i <= n; i++) cin >> a[i];
    
    //    cout << solve60(a, n, m) << '\n';
    //    cout << solvePre80(a, n, m) << '\n';
    //    cout << solve80(a, n, m) << '\n';
        cout << solve100(a, n, m) << '\n';
    
    	return 0;
    }
    
    
    • 1

    信息

    ID
    204
    时间
    1000ms
    内存
    128MiB
    难度
    8
    标签
    递交数
    57
    已通过
    11
    上传者