【每日一题】15.Xorto (前缀和枚举)

补题链接:Here

题意:选取任意不重叠的两个区间,使异或结果为 \(0\)

样例:\(1,2,3,4,5,5\)

在样例中我们可以选取 \(1,2,3\)\(5,5\) 就是满足题意

思路:相同元素的异或为 \(0\) ,所以我们找到两个点 \(i - j\) ,与 \(i -j\) 相同答案的个数(这句话是废话....)

先求出异或前缀和,然后枚举每个位置,统计该位置之前的所有前缀和、即吧该位置作为右端点枚举计算右端点之前的所有位,为左端点计数。

同时当把该位当作右端点计算完之后,并用map存储,把该店当作左端点,逐个枚举右端点,用map查询相同的值,进行计数.

\(1,2,3,4,5,6,7,8,8\)

比如,当 \(i\) 运算到第一个 \(8\) 的时候,前面有 \(1,2,3\) 的异或值为 \(0\) ,且已经记录,然后当第一个 \(8\) 为右端点运算结束之后,变为左端点是,第一个 \(8\) 和第二个 \(8\) 异或结果为 \(0\) ,并且此时还有前面 \(1,2,3\) 异或为 \(0\) , \(累计数 +1\)

using ll    = long long;
const int N = 1e6 + 10;
ll n, x, ans, a[N], b[N];
void solve() {
    cin >> n;
    for (ll i = 1; i <= n; ++i) {
        cin >> x;
        a[i] = a[i - 1] ^ x;
    }
    for (ll i = 1; i <= n; ++i) {
        for (ll j = 0; j < i; ++j) b[a[i] ^ a[j]]++;
        for (ll j = i + 1; j <= n; ++j)
            ans += b[a[i] ^ a[j]];
    }
    cout << ans << "\n";
}
posted @ 2021-04-27 14:12  Koshkaaa  阅读(61)  评论(0编辑  收藏  举报