• Codeforces 1516B AGAGA XOOORRR


    题目链接: http://codeforces.com/problemset/problem/1516/B

    题意

    一个含有 n 个非负数的数组,定义某种操作可以把相邻的两个数通过 XOR 合并为一个数,即每次操作后数组的元素个数都会减 1。问是否可以经过若干次这样的操作使得数组中的元素都相等?

    思路

    首先需要知道 XOR 操作一些的性质(^ 表示 XOR):

    归零律:a ^ a = 0
    恒等律:a ^ 0 = a
    交换律:a ^ b = b ^ a
    结合律:a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c
    且若有 a ^ b ^ c = d 则有 a = d ^ b ^ c

    解析

    假设经过若干操作后,数组中的元素都相等。那么可以分两种情况考虑,一种是数组中元素的个数为偶数,一种是奇数。其中偶数的时候一定是可以化简为 2 个元素,奇数的时候一定可以化简为 3 个元素。可以假设操作后有 m 个相等的元素,如果 m 是偶数,那么可以通过 XOR 前 m - 2 个元素使得其为 0,遂只剩下最后 2 个元素。如果 m 是奇数,那么前 m - 2 个元素 XOR 后仅剩 1 个元素,遂加上最后 2 个元素共 3 个元素,举例:
    3 ^ 3 ^ 3 ^ 3 = 0 ^ 3 ^ 3 = 3 ^ 3 (偶数)
    3 ^ 3 ^ 3 ^ 3 ^ 3 = 3 ^ 3 ^ 3(奇数)

    2 个元素相等

    如果最后剩 2 个相等的数,因为 a ^ a = 0,所以原始数组中所有元素 XOR 后的值必须为 0。

    3 个元素相等

    如果最后剩 3 个元素相等,即通过 2 个分割点把数组分为 3 部分,这 3 个部分的 XOR 值必须相等。那么可以通过暴力枚举分割点的方式,把原数组分割为三部分,分别计算每部分的 XOR 值。假设分割点分别为 i 和 j,每部分的 XOR 值分别为 a , b, c,XOR[i ... j] 表示 ai ^ a(i+1) ^ ... ^ aj
    a = XOR[0 ... i]
    b = XOR[i + 1 ... j]
    c = XOR[j + 1 ... n - 1]
    为了计算 a, b, c 可以计算一个前缀 XOR 数组 pre[i] 代表 XOR[0 .... i],且因为 a ^ b ^ c = d 可以得到 c = d ^ b ^ a, 所以
    a = XOR[0 .. i] = pre[i]
    b = XOR[i + 1 ... j] = pre[j] ^ pre[i]
    c = XOR[j + 1 ... n - 1] = pre[n - 1] ^ pre[j]

    如果不满足上述的情况,则说明无法将原数组按照此中操作约简为所有元素都相等数组。

    代码

    时间复杂度 O(N^2)

    #include "bits/stdc++.h"
    #define LL long long
    #define LLFmt "%lld"
    #define MIN(x, y) ((x) > (y) ? (y) : (x))
    #define MAX(x, y) ((x) > (y) ? (x) : (y))
    #define SWAP(x, y) ({ int t = x; x = y; y = t; })
    #define fir first
    #define sec second
    #define pb push_back
    const int MAX = 0x3f3f3f3f;
    const int MAXN = 2e3 + 3;
    using namespace std;
     
    int main () {
        int T, n; cin >> T;
        while (T--) {
            int p[MAXN] = { 0 }, a[MAXN] = { 0 }, k = 0, f = 0;
            cin >> n;
            for (int i = 0; i < n; i++) {
                cin >> a[i]; k ^= a[i], p[i] = k;
            }
     
            if (!k) f = 1;
     
            for (int i = 0; i < n - 2; i++) {
                for (int j = i + 1; j < n - 1; j++) {
                    f |= (p[i] == (p[j] ^ p[i]) && p[i] == (p[n - 1] ^ p[j]));
                }
            }
            cout << (f ? "YES" : "NO") << endl;
        }
        return 0;
    }
    

    扩展

    上面判断 3 部分 XOR 相等的时间复杂度为 O(N^2),假设题目加了一个条件,问是否至少可以分为 k 段,那么枚举 k 部分的时间复杂度是巨大的。所有其实这里还有种 O(N) 的方法。

    解析

    假设需要分为 k 部分,每部分的 XOR 值都为 x, 且数组中所有元素的 XOR 值设为 xr, 即 XOR[0 ... n -1 ] = xr,那么有
    x ^ x ^ x ^ ... ^ x ^ x = xr (xr 不为 0, 且 x 的数量 k 为奇数)
    即有:
    0 ^ x = xr
    所以可以从前往后遍历数组,并记录当前的 XOR 值,每当值等于 XOR 时,次数加 1,并重新计算 XOR 值。当遍历完时,判断次数是否大于 k,如果不是则说明无法通过 XOR 将原数组化为 k 部分相等的元素,时间复杂度 O(N)。

    代码

    #include "bits/stdc++.h"
    #define LL long long
    #define LLFmt "%lld"
    #define MIN(x, y) ((x) > (y) ? (y) : (x))
    #define MAX(x, y) ((x) > (y) ? (x) : (y))
    #define SWAP(x, y) ({ int t = x; x = y; y = t; })
    #define fir first
    #define sec second
    #define pb push_back
    #define ios ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
    const int MAX = 0x3f3f3f3f;
    const int MAXN = 2e3 + 3;
    using namespace std;
     
    inline int read () {
        int f = 1,x = 0, ch = getchar();
        while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
        while (isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
        return x * f;
    }
     
    inline LL readll () {
        LL f = 1, x = 0; int ch = getchar();
        while(!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
        while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
        return x * f;
    }
     
    int main () {
        ios; int T = read();
        while (T--) {
            int n = read (), a[MAXN] = { 0 }, xr = 0, cnt = 0, sg = 0;
            for (int i = 0; i < n; i++) a[i] = read(), xr ^= a[i];
            
            for (int i = 0; i < n; i++) {
                sg ^= a[i];
                if (sg == xr) cnt++, sg = 0;
            }
            cout << (xr == 0 || cnt > 2 ? "YES" : "NO") << endl;
        }
        return 0;
    }
    
    It's not numeral,character and punctuation .It's my life.
  • 相关阅读:
    pig安装
    [2013.10.29][Luogu OJ P1873]砍树
    [转帖]OIer之魂、
    [转帖]我们是OIer、
    10007:[2013.10.25]P1.滚土豆(potato.pas/c/cpp)
    [2013.10.18]P2.传作业 (pass.pas/c/cpp)
    [Luogu OJ P1619]解一元二次方程的烦恼
    [Luogu OJ P1433][2013.10.18]DFS基础题-吃奶酪
    高精度加减乘法小程序 Ver 0.9.5 beta
    [2013.10.11]P3.和为零
  • 原文地址:https://www.cnblogs.com/Ash-ly/p/14694664.html
Copyright © 2020-2023  润新知