1 条题解
-
0
- 一步一步从 的 40 分
- 优化到 的 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
- 上传者