APC001F Xor Tree

Posted libra9z

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了APC001F Xor Tree相关的知识,希望对你有一定的参考价值。

原题链接

这题是神仙思维题啊

(a_u=igoplus_{ein ext{u.edges}} ext{weight}_e),即所有与(u)相邻的边的权值异或和。

那么,那个不寻常的操作即珂转化为:找两个下标(i,j)和一个数(x),要(a_i,a_j)同时异或上(x)。最后还是要求使得所有的(a_i=0)的最少操作数。

发现搞到这儿还是不会/kel

然后接着我们思考另一个东西:

设集合(S)满足(S)中的所有数的异或和为(0),且任意一个(S)的非空子集里的数的异或和都不为(0)

那么窝们需要至少(|S|-1)次上面的那个操作才能使得(S)中的所有数变为(0)

证明? 咕咕咕

算了,还是简单证明一下吧:

先看一个广义的推论:集合(|S|)至少需要经过(|S|-1)次操作才能使得(|S|)变成由(|S|-1)(0)和一个(igoplus_S)组合出来的大小为(|S|)集合。

证明如下:

假设当(|S|=n-1)时推论成立。当(|S|=n)时,不妨设最后一次这样的操作中的一个数为(S_n)。那么前面窝们需要通过(n-2)次操作搞出来(n-2)(0)和一个(igoplus_{1leq ileq n-1}S_i)。这即为符合假设。

所以若(|S|=n-1)时推论成立,则当(|S|=n)时推论成立。

又因为当(|S|=2),推论显然成立,所以上述推论成立。

(igoplus_S=0)时,上述结论成立。

所以窝们要让操作数尽量少,就要划分出尽量多的(S)

假设窝们划分出了(m)(S),那么答案就是(n-m)

然后窝们发现虽然会有(100000)个数,但是每个数都在范围([0,15])之间,也就是相同的数珂能会出现很多次。

窝们珂以这样划分:

  1. 对于每个数(0),单独划分为一个(S)
  2. 对于每两个相同的数,单独划分为一个(S)

这样下来就只剩下了每个数最多一次。

然后考虑(dp_{mask})表示出现数的集合是(mask)最多珂以划分为多少个(S)

那么(dp_{mask} = max_{submaskin mask}{dp_{submask}+dp_{maskigoplus submask}})

总时间复杂度:(O(n+3^{15}))

贴一下代码:

// Code by H~$~C
#include <bits/stdc++.h>
using namespace std;

static const int Maxn = 100005;

int n;
int a[Maxn];
int dp[Maxn];

int main() {
  scanf("%d", &n);
  for (int i = 1; i < n; ++i) {
    int u, v, w;
    scanf("%d%d%d", &u, &v, &w);
    ++u, ++v;
    a[u] ^= w, a[v] ^= w;
  }
  
  int ans = 0;
  int allmask = 0;
  for (int i = 1; i <= n; ++i) {
    if (a[i] == 0) {
      ++ans;
    }
    else if (allmask & (1 << a[i] - 1)) {
      allmask ^= (1 << a[i] - 1);
      ++ans;
    }
    else {
      allmask ^= (1 << a[i] - 1);
    }
  }
  
  dp[0] = 0;
  for (int mask = 1; mask < (1 << 15); ++mask) {
    dp[mask] = -1;
    int xorsum = 0;
    for (int i = 0; i < 15; ++i) {
      if (mask >> i & 1) {
        xorsum ^= (i + 1);
      }
    }
    if (xorsum != 0) {
      continue;
    }
    
    for (int smask = mask; smask; smask = (smask - 1) & mask) {
      if (dp[smask] == -1) continue;
      dp[mask] = max(dp[mask], dp[smask] + dp[mask ^ smask]);
    }
    dp[mask] = max(dp[mask], 1);
  }
  
  printf("%d
", n - (ans + dp[allmask]));
  return 0;
}

以上是关于APC001F Xor Tree的主要内容,如果未能解决你的问题,请参考以下文章

AtCoder - 3913 XOR Tree

Xor Tree CodeForces

Codeforces Round #245 (Div. 1)A. Xor-tree(深搜)

C. Xor Tree(分治)

Tree Xor(线段树)

Tree Xor(未完全搞定)