#include <bits/stdc++.h>
using namespace std;
const long long inf = 2e9;
const long long base = 998244353;
long long mod = 1e9 + 7;
long long bin_pow(long long a, long long n) {
  if (!n) return 1;
  if (n & 1) {
    return (a * bin_pow(a, n - 1)) % mod;
  } else {
    return bin_pow((a * a) % mod, n / 2) % mod;
  }
}
long long reverse(long long a) { return bin_pow(a, mod - 1); }
void xor_fft(vector<long long>& a, bool revert) {
  for (long long len = 2; len <= a.size(); len <<= 1) {
    for (long long i = 0; i < a.size(); i += len) {
      for (long long j = 0; j < len / 2; ++j) {
        long long u = a[i + j];
        long long v = a[i + len / 2 + j];
        a[i + j] = u + v;
        a[i + len / 2 + j] = u - v;
      }
    }
  }
  if (revert) {
    for (auto& c : a) c /= a.size();
  }
}
void multiply(vector<long long>& a, vector<long long>& b) {
  long long len = 1;
  while (len < max(a.size(), b.size())) len <<= 1;
  a.resize(len);
  b.resize(len);
  xor_fft(a, false);
  xor_fft(b, false);
  for (long long i = 0; i < len; ++i) {
    a[i] *= b[i];
  }
  xor_fft(a, true);
  xor_fft(b, true);
  for (long long i = 0; i < len; ++i) {
    a[i] %= mod;
  }
}
map<pair<long long, long long>, long long> cost;
long long maxn = 131072;
long long n;
vector<set<long long>> g;
vector<char> used;
vector<long long> p;
long long cycle_st, cycle_end;
bool dfs(long long v, long long from) {
  used[v] = 1;
  for (auto to : g[v]) {
    if (to == from) continue;
    if (used[to] == 0) {
      p[to] = v;
      if (dfs(to, v)) return true;
    } else if (used[to] == 1) {
      cycle_end = v;
      cycle_st = to;
      return true;
    }
  }
  used[v] = 2;
  return false;
}
int main() {
  std::ios_base::sync_with_stdio(false);
  std::cin.tie(nullptr);
  auto start = clock();
  long long m;
  cin >> n >> m;
  g.assign(n, set<long long>());
  long long st = -1;
  for (long long i = 0; i < m; ++i) {
    long long a, b, c;
    cin >> a >> b >> c;
    --a;
    --b;
    g[a].insert(b);
    g[b].insert(a);
    cost[{a, b}] = c;
    cost[{b, a}] = c;
    if (st == -1)
      st = c;
    else
      st ^= c;
  }
  vector<vector<long long>> results;
  do {
    p.assign(n, -1);
    used.assign(n, 0);
    cycle_st = -1;
    dfs(0, -1);
    if (cycle_st == -1) break;
    vector<long long> cycle;
    cycle.push_back(cycle_st);
    for (long long v = cycle_end; v != cycle_st; v = p[v]) cycle.push_back(v);
    cycle.push_back(cycle_st);
    vector<long long> result;
    for (long long i = 1; i < cycle.size(); ++i) {
      result.push_back(cost[{cycle[i], cycle[i - 1]}]);
    }
    results.push_back(move(result));
    result.clear();
    g[cycle[0]].erase(cycle[1]);
    g[cycle[1]].erase(cycle[0]);
  } while (cycle_st != -1);
  assert(results.size() == m - n + 1);
  vector<vector<long long>> new_results;
  new_results.push_back({0});
  for (auto& c : results) {
    sort(c.begin(), c.end());
    new_results.push_back(vector<long long>(c.back() + 1));
    for (auto d : c) {
      new_results.back()[d] += 1;
    }
  }
  new_results[0].resize(maxn);
  new_results[0][st] = 1;
  auto first = new_results[0];
  for (long long i = 1; i < new_results.size(); ++i) {
    multiply(new_results[0], new_results[i]);
  }
  mod = 1e9 + 12321;
  for (long long i = 1; i < new_results.size(); ++i) {
    multiply(first, new_results[i]);
  }
  for (long long i = 0; i < new_results[0].size(); ++i) {
    if (new_results[0][i] > 0 || first[i] > 0) {
      cout << i << ' ' << new_results[0][i];
      break;
    }
  }
  std::cerr << double(clock() - start) / CLOCKS_PER_SEC << std::endl;
  return 0;
}
