Problem:
Problem E: Rooted Tree Game
Problem
初期状態として複数の根付き木が与えられる。これに対しAliceとBobはゲームを行う。ゲームは2人交互に行い、先手がAliceで後手がBobである。ターンが回ってきたプレイヤーは以下の行動を取る。
根(親を持たない頂点)を1つ選択する。この頂点を
S
とする。
S
を根とする根付き木に含まれる頂点を選択する(ここでは
S
も選択可能)。この頂点を
T
とする。
S
から
T
への経路上にある頂点を、
S
と
T
も含めすべて削除する。また、削除された頂点が端点であるような辺もすべて削除する。
ターンが回ってきた時点で頂点がすべて削除されていた場合、そのプレイヤーの負けとなる。
AliceとBobが常に最適な行動を取る時、与えられた初期状態に対し、勝利するプレイヤーを判定せよ。
以下の図は、プレイヤーの行動の例を示す。
Input
入力は以下の形式で与えられる。
N
M
p
1
p
2
:
p
M
1行目に、初期状態の頂点数
N
と辺の数
M
が空白区切りで与えられる。この時、各頂点を表す番号は1~
N
である。次の
M
行では、辺の情報が与えられる。このうち
i
行目では1つの整数
p
i
が与えられる。これは、頂点
p
i
から頂点
i
への辺があることを表す。言い換えると、頂点
i
の親が頂点
p
i
であることを表す。
Constraints
入力は以下の制約を満たす。
1 ≤
N
≤ 1000
0 ≤
M
< N
i
<
p
i
≤ N ( 1 ≤
i
≤
M
)
Output
勝利するプレイヤーの名前(AliceまたはBob)を1行に出力せよ。
Sample Input1
6 3
4
4
5
Sample Output1
Alice
Sample Input2
6 4
2
5
4
5
Sample Output2
Bob

Submitted solutions:

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int N, P[1 << 18];
int M;
int Answer[1 << 18];
vector<int> Cand;
vector<int> G[1 << 18];

int FindMex(vector<int> vec) {
	vec.push_back(-1);
	vec.push_back(10000000);
	sort(vec.begin(), vec.end());
	for (int i = 0; i < vec.size() - 1; i++) {
		if (vec[i + 1] - vec[i] >= 2) return vec[i] + 1;
	}
	return -1;
}

void dfs(int pos, int cur) {
	int base_xor = 0;
	for (int to : G[pos]) base_xor ^= Answer[to];
	Cand.push_back(cur ^ base_xor);

	// Recursion
	for (int to : G[pos]) {
		int nex_xor = ((cur ^ base_xor) ^ Answer[to]);
		dfs(to, nex_xor);
	}
}

int main() {
	// Step 1. Input
	cin >> N >> M;
	for (int i = 1; i <= M; i++) cin >> P[i];
	for (int i = 1; i <= M; i++) G[P[i]].push_back(i);

	// Step 2. Dynamic Programming
	for (int i = 1; i <= N; i++) {
		Cand.clear();
		dfs(i, 0);
		Answer[i] = FindMex(Cand);
	}

	// Step 3. Output
	int ret = 0;
	for (int i = M + 1; i <= N; i++) ret ^= Answer[i];
	if (ret != 0) cout << "Alice" << endl;
	else cout << "Bob" << endl;
	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 11640
final_rank: 3

code_snippet: #include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <climits>
#include <cfloat>
#include <ctime>
#include <cassert>
#include <map>
#include <utility>
#include <set>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <sstream>
#include <complex>
#include <stack>
#include <queue>
#include <numeric>
#include <list>
#include <iomanip>
#include <fstream>
#include <bitset>

using namespace std;

#define foreach(it, c) for (__typeof__((c).begin()) it=(c).begin(); it != (c).end(); ++it)
template <typename T> void print_container(ostream& os, const T& c) { const char* _s = " "; if (!c.empty()) { __typeof__(c.begin()) last = --c.end(); foreach (it, c) { os << *it; if (it != last) os << _s; } } }
template <typename T> ostream& operator<<(ostream& os, const vector<T>& c) { print_container(os, c); return os; }
template <typename T> ostream& operator<<(ostream& os, const set<T>& c) { print_container(os, c); return os; }
template <typename T> ostream& operator<<(ostream& os, const multiset<T>& c) { print_container(os, c); return os; }
template <typename T> ostream& operator<<(ostream& os, const deque<T>& c) { print_container(os, c); return os; }
template <typename T, typename U> ostream& operator<<(ostream& os, const map<T, U>& c) { print_container(os, c); return os; }
template <typename T, typename U> ostream& operator<<(ostream& os, const pair<T, U>& p) { os << "(" << p.first << ", " << p.second << ")"; return os; }

template <typename T> void print(T a, int n, const string& split = " ") { for (int i = 0; i < n; i++) { cout << a[i]; if (i + 1 != n) cout << split; } cout << endl; }
template <typename T> void print2d(T a, int w, int h, int width = -1, int br = 0) { for (int i = 0; i < h; ++i) { for (int j = 0; j < w; ++j) { if (width != -1) cout.width(width); cout << a[i][j] << ' '; } cout << endl; } while (br--) cout << endl; }
template <typename T> void input(T& a, int n) { for (int i = 0; i < n; ++i) cin >> a[i]; }
#define dump(v) (cerr << #v << ": " << v << endl)

#define rep(i, n) for (int i = 0; i < (int)(n); ++i)
#define erep(i, n) for (int i = 0; i <= (int)(n); ++i)
#define all(a) (a).begin(), (a).end()
#define rall(a) (a).rbegin(), (a).rend()
#define clr(a, x) memset(a, x, sizeof(a))
#define sz(a) ((int)(a).size())
#define mp(a, b) make_pair(a, b)
#define ten(n) ((long long)(1e##n))

template <typename T, typename U> void upmin(T& a, const U& b) { a = min<T>(a, b); }
template <typename T, typename U> void upmax(T& a, const U& b) { a = max<T>(a, b); }
template <typename T> void uniq(T& a) { sort(a.begin(), a.end()); a.erase(unique(a.begin(), a.end()), a.end()); }
template <class T> string to_s(const T& a) { ostringstream os; os << a; return os.str(); }
template <class T> T to_T(const string& s) { istringstream is(s); T res; is >> res; return res; }
void fast_io() { cin.tie(0); ios::sync_with_stdio(false); }
bool in_rect(int x, int y, int w, int h) { return 0 <= x && x < w && 0 <= y && y < h; }

typedef long long ll;
typedef pair<int, int> pint;

const int dx[] = { 0, 1, 0, -1 };
const int dy[] = { 1, 0, -1, 0 };


int dp[1024];
vector<int> g[1024];
int grundy(int);
void dfs(int i, set<int>& path, set<int>& ns, int x)
{
    path.insert(i);

    for (int to : g[i])
        x ^= grundy(to);
    ns.insert(x);

    for (int to : g[i])
        dfs(to, path, ns, x ^ grundy(to));

    path.erase(i);
}
int grundy(int i)
{
    if (dp[i] != -1)
        return dp[i];

    set<int> ns, path;
    dfs(i, path, ns, 0);

    int x = 0;
    while (ns.count(x))
        ++x;
    return dp[i] = x;
}
int main()
{
    int n, m;
    cin >> n >> m;
    clr(dp, -1);
    bool root[1024];
    fill_n(root, n, true);
    rep(i, m)
    {
        int p;
        cin >> p;
        --p;

        root[i] = false;
        g[p].push_back(i);
    }

    int x = 0;
    rep(i, n)
        if (root[i])
            x ^= grundy(i);
    cout << (x ? "Alice" : "Bob") << endl;
}
accuracy: 1
time_ms: 100
memory_kb: 1580
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;

constexpr int MAX_N = 1000;

int n, m;
vector<int> children[MAX_N];
int parent[MAX_N];

int memo[MAX_N];
pair<bool, int> memo2[MAX_N][MAX_N];
vector<int> nodes[MAX_N];

vector<int> calc(int v) {
  auto &res = nodes[v];
  if(!res.empty()) return res;

  res.emplace_back(v);
  for(const auto &c : children[v]) {
    const auto vec = calc(c);
    res.insert(res.end(), vec.begin(), vec.end());
  }
  return res;
}

int grundy(int v);
pair<bool, int> dfs(int v, int u) {
  auto &res = memo2[v][u];
  if(res.second != -1) return res;

  bool reach = false;
  int value = 0;
  if(v == u) {
    reach = true;
    for(const auto &c : children[v]) {
      value ^= grundy(c);
    }
  }
  else {
    vector<pair<bool, int>> buf;
    buf.reserve(children[v].size());
    for(const auto &c : children[v]) {
      buf.emplace_back(dfs(c, u));
      reach |= buf.back().first;
    }

    if(reach) {
      for(const auto &e : buf) {
	value ^= e.second;
      }
    }
    else {
      value = grundy(v);
    }
  }

  return res = make_pair(reach, value);
}

int grundy(int v) {
  int &res = memo[v];
  if(res != -1) return res;

  set<int> S;
  for(const auto &u : nodes[v]) {
    S.insert(dfs(v, u).second);
  }

  res = 0;
  while(S.count(res)) ++res;
  return res;
}

int main() {
  cin.tie(NULL);
  ios::sync_with_stdio(false);

  cin >> n >> m;

  memset(parent, -1, sizeof(parent));

  for(int i = 0; i < m; ++i) {
    int p;
    cin >> p;
    --p;

    parent[i] = p;
    children[p].emplace_back(i);
  }

  memset(memo, -1, sizeof(memo));
  for(int i = 0; i < n; ++i) {
    for(int j = 0; j < n; ++j) {
      memo2[i][j] = make_pair(false, -1);
    }
  }

  int x = 0;
  for(int v = 0; v < n; ++v) {
    if(parent[v] == -1) {
      calc(v);
      x ^= grundy(v);
    }
  }

  cout << (x != 0 ? "Alice" : "Bob") << endl;

  return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 11404
final_rank: 5

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <sstream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <numeric>
#include <cctype>
#include <tuple>
#include <array>
#include <climits>
#include <bitset>

// BEGIN CUT HERE
#ifdef _MSC_VER
#include <agents.h>
#endif
// END CUT HERE 

#define FOR(i, a, b) for(int i = (a); i < (int)(b); ++i)
#define rep(i, n) FOR(i, 0, n)
#define ALL(v) v.begin(), v.end()
#define REV(v) v.rbegin(), v.rend()
#define MEMSET(v, s) memset(v, s, sizeof(v))
#define MP make_pair
#define MT make_tuple

using namespace std;

typedef long long ll;
typedef pair<ll, ll> P;

const int N = 1010;
int dp[N];
vector<int> G[N];

int calc_grundy(int v);

void dfs(int v, int x, set<int> &st){
	for (auto nxt : G[v]){
		x ^= calc_grundy(nxt);
	}
	st.insert(x);
	for (auto nxt : G[v]){
		dfs(nxt, x^calc_grundy(nxt), st);
	}
}

int calc_grundy(int v){
	int &res = dp[v];
	if (res >= 0) return res;

	set<int> st;
	dfs(v, 0, st);
	for (int i = 0; i <= 1000; ++i){
		if (st.count(i) == 0) return res = i;
	}
	return -1;
}

int main(){
	cin.tie(0);
	ios::sync_with_stdio(false);

	MEMSET(dp, -1);

	int n, m;
	cin >> n >> m;

	vector<int> p(n, -1);
	rep(i, m){
		cin >> p[i];
		--p[i];
		G[p[i]].push_back(i);
	}

	int g = 0;
	rep(i, n) if (p[i] < 0) g ^= calc_grundy(i);

	cout << (g ? "Alice" : "Bob") << endl;

	return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 1468
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define REP(i,n) for(int i=0;i<(int)(n);++i)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
#define ALL(c) (c).begin(), (c).end()
#define valid(y,x,h,w) (0<=y&&y<h&&0<=x&&x<w)
#define tpl(...) make_tuple(__VA_ARGS__)
const int INF = 0x3f3f3f3f;
const double EPS = 1e-8;
const double PI = acos(-1);
typedef long long ll;
typedef pair<int,int> pii;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T>bool chmin(T &a, const T &b) { if (a>b) { a=b; return 1; } return 0; }
template<class T>ostream&operator<<(ostream &o,const vector<T>&t){o<<'[';FOR(i,t){if(i!=t.begin())o<<',';o<<*i;}return o<<']';}
template<class S,class T>ostream&operator<<(ostream &o,const pair<S,T>&t){return o<<'('<<t.first<<','<<t.second<<')';}
template<int N,class Tp>void output(ostream&,const Tp&){}
template<int N,class Tp,class,class ...Ts>void output(ostream &o,const Tp&t){if(N)o<<',';o<<get<N>(t);output<N+1,Tp,Ts...>(o,t);}
template<class ...Ts>ostream&operator<<(ostream&o,const tuple<Ts...>&t){o<<'(';output<0,tuple<Ts...>,Ts...>(o,t);return o<<')';}
template<class T>void output(T t,char z=10){if(t<0)t=-t,putchar(45);int c[20];
int k=0;while(t)c[k++]=t%10,t/=10;for(k||(c[k++]=0);k;)putchar(c[--k]^48);putchar(z);}
template<class T>void outputs(T t){output(t);}
template<class S,class ...T>void outputs(S a,T...t){output(a,32);outputs(t...);}
template<class T>void output(T *a,int n){REP(i,n)output(a[i],i!=n-1?',':10);}
template<class T>void output(T *a,int n,int m){REP(i,n)output(a[i],m);}
template<class T>bool input(T &t){int n=1,c;for(t=0;!isdigit(c=getchar())&&~c&&c-45;);
if(!~c)return 0;for(c-45&&(n=0,t=c^48);isdigit(c=getchar());)t=10*t+c-48;t=n?-t:t;return 1;}
template<class S,class ...T>bool input(S&a,T&...t){input(a);return input(t...);}

vector<int> g[1000];
int grundy(int v, int p);

int vvv;
void dfs(int v, int p, int gr, int vvv, vector<int> &gv) {
  FOR(it, g[v]) {
    if (*it == p) continue;
    gr ^= grundy(*it, v);
  }
  // if (gr == 0) {
  //   cout << p+1 << " " << vvv+1 << " " << v+1 << endl;
  // }
  gv.push_back(gr);
  FOR(it, g[v]) {
    if (*it == p) continue;
    dfs(*it, v, gr ^ grundy(*it, v), vvv, gv);
  }
}

int dp[1000];
int grundy(int v, int p) {
  if (dp[v] >= 0) return dp[v];
  vvv= v;
  vector<int> gv;
  dfs(v,p,0,v,gv);
  sort(ALL(gv));
  int res = 0;
  gv.erase(unique(ALL(gv)), gv.end());
  REP(i,gv.size()) {
    if (gv[i] != res) break;
    res++;
  }
  // cout << v+1 << " " << gv << " " << res << endl;
  return dp[v] = res;
}

int main() {
  int n,m;
  while(cin >> n >> m) {
    REP(i,n) g[i].clear();
    vector<int> num(n);
    REP(i,m) {
      int p; cin >> p;
      g[p-1].push_back(i);
      num[i]++;
    }
    memset(dp,-1,sizeof(dp));
    int gr = 0;
    REP(i,n) {
      if (num[i] == 0) {
        gr ^= grundy(i,-1);
      }
    }
    // output(dp,n);
    cout << (gr?"Alice":"Bob") << endl;
  }
}
accuracy: 1
time_ms: 20
memory_kb: 1448
final_rank: 1