#include <bits/stdc++.h>
using namespace std;
const int DN = 1e5 + 5;
int n, m, niv[DN];
int f, g, low[DN], cnt;
vector<int> v[DN], r[DN];
stack<int> stk;
void dfs(int nod) {
  stk.push(nod);
  low[nod] = niv[nod];
  for (auto i : v[nod]) {
    if (niv[i]) {
      low[nod] = min(low[nod], niv[i]);
      continue;
    }
    niv[i] = niv[nod] + 1;
    dfs(i);
    low[nod] = min(low[nod], low[i]);
    if (low[i] >= niv[nod]) {
      cnt++;
      r[cnt].push_back(nod);
      do {
        f = stk.top();
        stk.pop();
        r[cnt].push_back(f);
      } while (f != i);
    }
  }
}
map<pair<int, int>, int> mp;
int cost, lst, sol;
const int N = (1 << 17);
int M;
int dp[N + 5], z[N + 5], dp0[N + 5], Z, L[N + 5];
inline void fft(int in[], int out[], int n, int put, bool type) {
  for (int i = 0; i < N; i++) out[i] = in[i];
  for (int len = 1; 2 * len <= N; len <<= 1) {
    for (int i = 0; i < N; i += 2 * len) {
      for (int j = 0; j < len; j++) {
        int a = out[i + j];
        int b = out[i + j + len];
        out[i + j] = a + b;
        if (out[i + j] > M) out[i + j] -= M;
        out[i + j + len] = a - b;
        if (out[i + j + len] < 0) out[i + j + len] += M;
      }
    }
  }
}
void mul(int A[], int B[], int R[]) {
  fft(A, R, N, 1, 1);
  fft(B, A, N, 1, 1);
  for (int i = 0; i < N; i++) B[i] = (1LL * A[i] * R[i]) % M;
  fft(B, R, N, 1, 0);
  for (int i = 0; i < N; i++) R[i] = (1LL * R[i] * Z) % M;
}
int poww(int a, int b, int M) {
  int r = 1, c = a, p = 1;
  while (p <= b) {
    if (p & b) r = (1LL * r * c) % M;
    c = (1LL * c * c) % M;
    p *= 2;
  }
  return r;
}
void solve(int vl) {
  M = vl;
  Z = poww((1LL << 17), 1LL * M - 2, M);
  for (int i = 0; i < N + 5; i++) dp[i] = 0;
  dp[sol] = 1;
  for (int i = 1; i <= cnt; i++) {
    if (r[i].size() < 3) continue;
    lst = 0;
    for (int j = 0; j < N + 5; j++) {
      dp0[j] = dp[j];
      z[j] = 0;
      dp[j] = 0;
    }
    int abc = r[i][0];
    if (M != 1e9 + 7) r[i].push_back(abc);
    for (auto j : r[i]) {
      if (lst != 0) {
        cost = mp[{lst, j}];
        z[cost]++;
      }
      lst = j;
    }
    mul(dp0, z, dp);
  }
}
string s;
int ptr = 0;
int citire() {
  int f = 0;
  while (!isdigit(s[ptr])) ptr++;
  while (isdigit(s[ptr])) {
    f = f * 10 + s[ptr] - '0';
    ptr++;
  }
  return f;
}
int main() {
  cin.sync_with_stdio(false);
  cout.sync_with_stdio(false);
  ptr = 0;
  getline(cin, s);
  s += 'a';
  n = citire();
  m = citire();
  while (m--) {
    getline(cin, s);
    s += 'a';
    ptr = 0;
    f = citire();
    g = citire();
    cost = citire();
    mp[{f, g}] = cost;
    mp[{g, f}] = cost;
    sol ^= cost;
    v[f].push_back(g);
    v[g].push_back(f);
  }
  for (int i = 1; i <= n; i++)
    if (!niv[i]) {
      niv[i] = 1;
      dfs(i);
    }
  solve(1e9 + 11);
  for (int i = 0; i < N + 5; i++) L[i] = dp[i];
  solve(1e9 + 7);
  for (int i = 0; i < N + 5; i++)
    if (dp[i] || L[i]) {
      cout << i << ' ' << dp[i];
      return 0;
    }
}
