#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using Vi = vector<int>;
using Pii = pair<int, int>;
template <class t, class u, class... w>
auto operator<<(t& o, u a) -> decltype(a.print(), o) {
  o << "{";
  a.print();
  o << "}";
  return o;
};
template <class t, class u, class... w>
auto operator<<(t& o, u a) -> decltype(a.second, o) {
  o << "(" << a.first << ", " << a.second << ")";
  return o;
};
template <class t, class u, class... w>
auto operator<<(t& o, u a) -> decltype((a).begin(), (a).end(), o) {
  o << "[";
  auto d = "";
  for (auto i : a) (o << d << i, d = ", ");
  o << "]";
  return o;
};
void DD(...) {}
template <class t, class u, class... w>
void DD(t s, u a, w... k) {
  int b = 44;
  while (*s && *s != b) {
    b += (*s == 40 ? 50 : *s == 41 ? -50 : 0);
    cerr << *s++;
  }
  cerr << ": " << a << *s++;
  DD(s, k...);
}
template <class t, class u, class... w>
vector<t> span(const t* a, u n) {
  return {a, a + n};
}
constexpr int MOD = 1e9 + 7;
constexpr int MAX_W = 1 << 17;
vector<vector<Pii>> G;
vector<Pii> par;
Vi depth;
vector<vector<ll>> options;
ll modInv(ll a, ll m) {
  if (a == 1) return 1;
  return ((a - modInv(m % a, a)) * m + 1) / a;
}
void dfs(int v) {
  for (auto& e : (G[v])) {
    if (par[e.first].second == -1) {
      par[e.first] = {v, e.second};
      depth[e.first] = depth[v] + 1;
      dfs(e.first);
    } else if (depth[e.first] > depth[v] + 1) {
      options.emplace_back(MAX_W);
      auto& out = options.back();
      out[e.second]++;
      for (int u = e.first; u != v; u = par[u].first) {
        out[par[u].second]++;
      }
    }
  }
}
template <bool inv, bool doMod>
void fwht(vector<ll>& a) {
  for (int n = int((a).size()), step = 1; step < n; step *= 2) {
    for (int i = 0; i < n; i += 2 * step) {
      for (int j = (i); j < (i + step); j++) {
        ll &u = a[j], &v = a[j + step];
        tie(u, v) = pair<ll, ll>(u + v, u - v);
        if (doMod) {
          u %= MOD;
          v %= MOD;
        }
      }
    }
  }
  if (inv) {
    if (doMod) {
      ll mult = modInv(int((a).size()), MOD);
      for (auto& first : (a)) first = first * mult % MOD;
    } else {
      for (auto& first : (a)) first /= int((a).size());
    }
  }
}
void convMod(vector<ll>& a, vector<ll>& b) {
  for (int i = (0); i < (int((a).size())); i++) a[i] = a[i] * b[i] % MOD;
}
void convOnes(vector<ll>& a, vector<ll>& b) {
  for (auto& first : (a)) first = (first != 0);
  fwht<0, 0>(a);
  for (int i = (0); i < (int((a).size())); i++) a[i] = a[i] * b[i] % MOD;
  fwht<1, 0>(a);
}
void printUsed(vector<ll>& vec) {
  for (int i = (0); i < (int((vec).size())); i++) {
    if (vec[i]) cout << i << ' ';
  }
  cout << '\n';
}
int main() {
  cin.sync_with_stdio(0);
  cin.tie(0);
  cout << fixed << setprecision(18);
  int n, m;
  cin >> n >> m;
  int full = 0;
  G.resize(n);
  for (int i = (0); i < (m); i++) {
    int u, v, w;
    cin >> u >> v >> w;
    u--;
    v--;
    G[u].push_back({v, w});
    G[v].push_back({u, w});
    full ^= w;
  }
  if (m == n - 1) {
    cout << full << '\n';
    return 0;
  }
  par.resize(n, {-1, -1});
  depth.resize(n);
  par[0].second = 0;
  dfs(0);
  vector<ll> ones = options[0], kek = options[0];
  fwht<0, 1>(kek);
  for (int i = (1); i < (int((options).size())); i++) {
    fwht<0, 0>(options[i]);
    convOnes(ones, options[i]);
    convMod(kek, options[i]);
  }
  for (auto& first : (ones)) first = (first != 0);
  fwht<1, 1>(kek);
  ll bestCost = INT64_MAX, ways = 0;
  for (int i = (0); i < (int((ones).size())); i++) {
    if (!ones[i]) continue;
    if ((i ^ full) < bestCost) {
      bestCost = i ^ full;
      ways = kek[i];
    }
  }
  ways %= MOD;
  if (ways < 0) ways += MOD;
  cout << bestCost << ' ' << ways << '\n';
}
