#include <bits/stdc++.h>
using namespace std;
int gcd(int x, int y) { return (!y ? x : gcd(y, x % y)); }
const int maxn = 2e5;
vector<int> g[maxn], tree[maxn];
map<pair<int, int>, int> we;
int par[maxn];
int gpar(int v) { return (par[v] == v ? v : par[v] = gpar(par[v])); }
bool mrg(int u, int v) {
  u = gpar(u);
  v = gpar(v);
  if (u == v) return false;
  par[v] = u;
  return true;
}
int h[maxn];
void dfs(int v, int p) {
  for (auto u : tree[v]) {
    if (u == p) continue;
    par[u] = v;
    h[u] = h[v] + 1;
    dfs(u, v);
  }
}
vector<int> get_path(int u, int v) {
  if (h[u] < h[v]) swap(u, v);
  vector<int> p, rig;
  while (h[u] > h[v]) {
    p.push_back(u);
    u = par[u];
  }
  while (u != v) {
    p.push_back(u);
    rig.push_back(v);
    u = par[u], v = par[v];
  }
  p.push_back(u);
  reverse(rig.begin(), rig.end());
  for (auto i : rig) p.push_back(i);
  return p;
}
const int maxb = 18;
int mods[2] = {int(1e9 + 7), int(1e9 + 9)};
int mod;
const int N = (1 << maxb);
int bpw(int a, int b) {
  int ans = 1;
  while (b) {
    if (b & 1) ans = 1LL * ans * a % mod;
    a = 1LL * a * a % mod;
    b >>= 1;
  }
  return ans;
}
void fwht(int* a, int val) {
  for (int len = 2; len <= N; len *= 2)
    for (int i = 0; i < N; i += len) {
      int nxt = len / 2;
      for (int j = 0; j < nxt; j++) {
        int x = a[i + j], y = a[i + j + nxt];
        a[i + j] = (x + y) % mod;
        a[i + j + nxt] = (x - y + mod) % mod;
      }
    }
  if (val == -1) {
    int inv = bpw(N, mod - 2);
    for (int i = 0; i < N; i++) a[i] = 1LL * a[i] * inv % mod;
  }
}
int ans[2][N], cnt[N];
int32_t main() {
  ios::sync_with_stdio(0), cin.tie(0);
  int n, m;
  cin >> n >> m;
  int tot = 0;
  for (int i = 0; i < m; i++) {
    int u, v, w;
    cin >> u >> v >> w;
    u--, v--;
    g[u].push_back(v);
    g[v].push_back(u);
    we[{u, v}] = we[{v, u}] = w;
    tot ^= w;
  }
  for (int i = 0; i < n; i++) par[i] = i;
  vector<pair<int, int> > bads;
  for (int i = 0; i < n; i++) {
    for (auto j : g[i]) {
      if (mrg(i, j)) {
        tree[i].push_back(j);
        tree[j].push_back(i);
      } else if (i < j)
        bads.push_back({i, j});
    }
  }
  if (bads.size() == 0) {
    cout << tot << " " << 1 << '\n';
    return 0;
  }
  dfs(0, 0);
  for (int it = 0; it < 2; it++) {
    mod = mods[it];
    for (int i = 0; i < N; i++) ans[it][i] = 1;
    for (auto t : bads) {
      vector<int> p = get_path(t.first, t.second);
      p.push_back(p[0]);
      memset(cnt, 0, sizeof cnt);
      for (int i = 0; i + 1 < p.size(); i++) {
        int w = we[{p[i], p[i + 1]}];
        cnt[w]++;
      }
      fwht(cnt, 1);
      for (int i = 0; i < N; i++) ans[it][i] = 1LL * ans[it][i] * cnt[i] % mod;
    }
    fwht(ans[it], -1);
  }
  int jav = 1e9, who = -1;
  for (int i = 0; i < N; i++)
    if (ans[0][i] || ans[1][i]) {
      if ((i ^ tot) < jav) {
        jav = i ^ tot;
        who = i;
      }
    }
  assert(who != -1);
  cout << jav << " " << ans[0][who] << '\n';
}
