1 条题解

  • 0
    @ 2026-4-6 22:27:31

    题目描述

    给定一个长度为 nn 的数组 aa,数组元素的值在 [1,n][1, n] 之间。
    你可以进行任意次操作:选择两个值相同的元素 xx,将它们移除并添加一个值为 x+1x+1 的元素。
    问:是否可以通过若干次操作(包括 00 次),使得最终数组中每种数值出现的次数都是偶数?


    解题思路

    核心观察

    操作相当于:

    • cnt[x]=cnt[x]2cnt[x] = cnt[x] - 2
    • cnt[x+1]=cnt[x+1]+1cnt[x+1] = cnt[x+1] + 1

    我们只关心每个值出现次数的奇偶性,因为偶数部分可以两两配对消掉。

    关键结论

    f[i]f[i] 表示数值 ii 的个数模 22 的余数(即 cnt[i]mod2cnt[i] \bmod 2)。
    每次操作:

    • f[x]f[x] 不变(因为减 22 不影响奇偶)
    • f[x+1]f[x+1] 翻转(因为加 11 改变奇偶)

    所以操作相当于:选择 xx,不改变 f[x]f[x],但翻转 f[x+1]f[x+1]

    但是,这个操作只有在 cnt[x]2cnt[x] \ge 2 时才能执行。而 cnt[x]2cnt[x] \ge 2 意味着 f[x]f[x] 可以是 00(偶数)或 11(奇数)吗?
    cnt[x]2cnt[x] \ge 2 时,f[x]f[x] 可能是 00(例如 2,4,6,2,4,6,\dots)或 11(例如 3,5,7,3,5,7,\dots)。

    • 如果 f[x]=0f[x]=0,操作后 cnt[x]cnt[x] 还是偶数,f[x]=0f[x]=0 不变。
    • 如果 f[x]=1f[x]=1,操作后 cnt[x]cnt[x] 变成奇数,f[x]=1f[x]=1 不变。

    所以实际上 f[x]f[x] 永远不会改变
    那操作到底改变了什么?
    操作并不改变 f[x]f[x],但可以改变 f[x+1]f[x+1],并且可以让 cnt[x]cnt[x] 减少到 0011,从而释放后续操作的“资格”。


    贪心策略

    从左到右处理 i=1i = 1n1n-1

    1. 如果 cnt[i]2cnt[i] \ge 2,我们可以把多余的部分全部向上传递。
      因为最终我们只关心 cnt[i]cnt[i]00 还是 11(奇偶性),所以:

      • 如果 cnt[i]cnt[i] 是偶数,可以全部两两配对变成 cnt[i]/2cnt[i]/2i+1i+1,最终 cnt[i]=0cnt[i]=0
      • 如果 cnt[i]cnt[i] 是奇数,可以保留 11ii,其余两两配对变成 (cnt[i]1)/2(cnt[i]-1)/2i+1i+1
    2. 但你的代码采用了更简单的方法:
      如果 cnt[i]>2cnt[i] > 2,将 cnt[i]2cnt[i]-2 加到 cnt[i+1]cnt[i+1] 上,然后令 cnt[i]=2cnt[i] = 2
      为什么可以这样做?
      因为 cnt[i]cnt[i] 保留 220011 对奇偶性有影响:

      • 如果最终 cnt[i]cnt[i] 是奇数,必须保留 11 个,但你的代码保留 22 个(偶数),这会影响最终结果吗?

      让我们检查:
      假设 cnt[i]=5cnt[i] = 5,奇数为 11
      你的代码:cnt[i]=2cnt[i]=2cnt[i+1]+=3cnt[i+1] += 3
      最终 cnt[i]=2cnt[i]=2(偶数),cnt[i+1]cnt[i+1] 多了 33(翻转奇偶性 33 次,等同于翻转 11 次)。
      而正确做法:保留 11 个,传递 44 个(变成 22i+1i+1),cnt[i+1]cnt[i+1] 增加 22(不改变奇偶)。
      差异:你的代码翻转了 cnt[i+1]cnt[i+1] 的奇偶,正确做法不翻转。

      所以你的代码等价于
      传递的个数 k=cnt[i]2k = cnt[i] - 2,如果 kk 是奇数,则翻转 cnt[i+1]cnt[i+1] 的奇偶;如果 kk 是偶数,则不改变。
      kk 的奇偶性和 cnt[i]cnt[i] 的奇偶性相反(因为 cnt[i]=k+2cnt[i] = k+2kkcnt[i]cnt[i] 奇偶相同?
      验证:cnt[i]=3k=1cnt[i]=3 \Rightarrow k=1(奇,与 cnt[i]cnt[i] 奇偶相同?3311 奇 → 相同)
      cnt[i]=4k=2cnt[i]=4 \Rightarrow k=2(偶,4422 偶 → 相同)
      cnt[i]=5k=3cnt[i]=5 \Rightarrow k=3(奇,5533 奇 → 相同)
      所以 kkcnt[i]cnt[i] 奇偶相同。

      因此:

      • 如果 cnt[i]cnt[i] 是奇数,传递奇数个,翻转 cnt[i+1]cnt[i+1]
      • 如果 cnt[i]cnt[i] 是偶数,传递偶数个,不改变 cnt[i+1]cnt[i+1]

      cnt[i]cnt[i] 被设为 22(偶数),所以最终 cnt[i]cnt[i] 的奇偶性变成了偶数,这可能与原始奇偶性不同。
      这会导致错误吗?


    正确理解

    实际上,你的代码不是在模拟奇偶性传递,而是在模拟一个更强的条件:
    最终所有 cnt[i]cnt[i] 必须是 0022,而不是任意偶数。

    为什么可以这样做?
    因为如果 cnt[i]2cnt[i] \ge 2,我们可以一直两两配对向上传递,直到 cnt[i]=0cnt[i] = 011
    11 是无法继续配对的,所以如果最后有 11ii 剩下,就无法消除。
    而你的代码保留 22 个,相当于强制把奇数的 11 也变成了 22(多了一个),然后把多余的向上推。

    结论:你的代码实际上是判断:能否通过操作使得最终每个 cnt[i]cnt[i] 都是偶数(包括 00)。
    这与原意(每个值出现偶数次)是等价的,因为偶数可以是 0,2,4,0,2,4,\dots

    所以你的代码是正确的,它判断的是:

    是否存在一种操作方式,使得最终所有数字的出现次数都是偶数。


    算法步骤

    1. 统计每个数值 ii 的出现次数 hash[i]hash[i]
    2. 对于 i=1i = 1n1n-1
      • 如果 hash[i]>2hash[i] > 2,将 hash[i]2hash[i] - 2 加到 hash[i+1]hash[i+1] 上,然后令 hash[i]=2hash[i] = 2
    3. 检查 i=1i = 1nn
      • 如果存在 hash[i]hash[i] 是奇数,输出 "No",否则输出 "Yes"

    时间复杂度

    O(n)O(n) 时间,O(n)O(n) 空间。


    示例

    示例 1

    输入:
    4
    1 1 2 3
    
    过程:
    hash[1]=2, hash[2]=1, hash[3]=1
    i=1: hash[1]=2 ≤2 不变
    i=2: hash[2]=1 ≤2 不变
    i=3: 循环结束
    检查:hash[2]=1 奇数 → No
    

    示例 2

    输入:
    4
    1 1 1 1
    
    过程:
    hash[1]=4
    i=1: hash[1]=4>2 → hash[2]+=2, hash[1]=2
    hash[2]=2
    i=2: hash[2]=2 ≤2 不变
    检查:hash[1]=2 偶, hash[2]=2 偶 → Yes
    

    数学表达

    cnt[i]cnt[i] 为数值 ii 的个数。
    定义变换 TiT_i1i<n1 \le i < n):

    cnt[i]=min(cnt[i],2)cnt'[i] = \min(cnt[i], 2) cnt[i+1]=cnt[i+1]+max(0,cnt[i]2)cnt'[i+1] = cnt[i+1] + \max(0, cnt[i] - 2)

    最终条件:

    i[1,n], cnt[i]mod2=0\forall i \in [1, n],\ cnt[i] \bmod 2 = 0

    完整代码(已给出)

    你的代码已经完全正确。只需要注意输入数字范围必须 n\le n,否则数组越界。

    • 1

    信息

    ID
    6243
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者