Problem:
アカベコ国王の配慮

アカベコ国の国王には２人の王子がいます。国王は自分が退位するときに国を２つに分割し、それぞれの王子に一つずつ国を治めさせることにしました。新しい国の名前はアカ国とベコ国です。アカベコ国には N 個の町と、２つの町を繋ぐ M 本の道があります。国王は、以下の手順でアカベコ国の町と一部の道を２つの国に配分することにしました。

(1)   町を２つ選び、それぞれアカ国とベコ国に配分する。

(2)   すでに配分された町sを選ぶ。さらに、町 s から１本の道で繋がっている、まだ配分されていない町 t を選ぶ。そして、町 s、t 間の道と町 t を、町 s が配分された国に配分する。

(3)   (2)を、行えなくなるまで繰り返す。

実は２人の王子はあまり仲が良くないので、国王は２つの国の距離をなるべく大きくしたいと考えています。ここで、２つの国の距離とは、アカ国の町とベコ国の町を繋ぐ道の中で、最も短い道の長さです。

アカベコ国の町と道の情報が与えられたとき、分配後のアカ国とベコ国の距離の最大値と、そのような距離になる配分が何通りあるかを求めるプログラムを作成してください。ただし、２つの配分結果は、アカ国とベコ国に異なる町か道が配分された場合に区別されます。

入力

入力は以下の形式で与えられる。

N M
s1 t1 d1
s2 t2 d2
:
sM tM dM

１行目は２つの整数からなる。N (2 ≤ N ≤ 100) は町の数、M (N-1 ≤ M ≤ N(N-1)/2) は道の数を表す。続くM 行に２つの町を繋ぐ道が与えられる。si と ti (1 ≤ si ≠ ti ≤ N) は i 番目の道が繋ぐ２つの町の番号を表す。di (1 ≤ di ≤ 109) は i 番目の道の長さを表す。

入力は以下の条件を満たす。

どの２つの町もいくつかの道を使い行き来が可能である。

どの２つの町の間にも２本以上の道はない。

同じ長さの道は５本以下である。

出力

分配後のアカ国とベコ国の距離の最大値と組み合わせの数を、空白区切りで１行に出力する。ただし、分配後の組み合わせの数は非常に大きくなりうるので、代わりに 1,000,000,007 で割った余りを出力する。

入出力例

入力例

6 7
1 2 1
2 3 2
3 1 3
4 5 4
5 6 5
6 4 6
1 4 7

出力例

7 18

Solution in C++11 (judge verdict: Accepted)

#include<unordered_map>
#include<utility>
template<typename T>
class UnionFind {
public:
  void unite(const T& a, const T& b) {
    T x = find(a), y = find(b);
    if(size_[x] < size_[y]) std::swap(x, y);
    if(x != y) parent_[y] = x, size_[x] += size_[y];
  }
  const T find(const T& x) {
    if(!parent_.count(x)) {
      size_[x] = 1;
      return parent_[x] = x;
    }
    return (parent_[x] == x) ? x : (parent_[x] = find(parent_[x]));
  }
  const int size(const T& x) {
    return size_[find(x)];
  }
private:
  std::unordered_map<T, T> parent_;
  std::unordered_map<T, int> size_;
};

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

using Weight = long long int;
using Vertex = int;
struct Edge {Vertex from, to; Weight weight;};
using Row = valarray<Weight>;
using Matrix = valarray<Row>;

const Weight MOD = 1e9 + 7;
int N, M;
vector<Vertex> root;
vector<Edge> E;

Weight power(Weight m, Weight n) {
  if(!n) return 1;
  if(n & 1) return (power(m, n - 1) * m) % MOD;
  return power((m * m) % MOD, n >> 1);
}

Weight determinant(Matrix A) {
  const int N = A.size() - 1;
  Weight det = 1;
  for(int i = 0; i < N; ++i) {
    for(int k = i; k < N; ++k) if(A[k][i] != 0) {
      if((k - i) & 1) det = -det + MOD;
      swap(A[i], A[k]);
      break;
    }
    if(A[i][i] == 0) return 0;
    det = (det * A[i][i]) % MOD;
    for(int k = i + 1; k < N; ++k) {
      auto c = (A[k][i] * power(A[i][i], MOD - 2)) % MOD;
      c = -c + MOD;
      for(int j = 0; j < N; ++j) A[k][j] = (A[k][j] + c * A[i][j] + MOD) % MOD;
    }
  }
  return det % MOD;
}

Matrix Laplacian(UnionFind<Vertex> cc, Vertex c) {
  Matrix L(Row(Weight(0), cc.size(c) - 1), cc.size(c) - 1);
  vector<Vertex> V;
  for(Vertex v = 0; v < N; ++v) if(cc.find(v) == cc.find(c)) V.push_back(v);
  vector<int> index(N, -1);
  for(int i = 0; i < V.size(); ++i) index[V[i]] = i;
  for(auto e: E) if(cc.find(e.from) == cc.find(c) && cc.find(e.to) == cc.find(c)) {
    L[index[e.from]][index[e.to]] = L[index[e.to]][index[e.from]] = -1 + MOD;
    ++L[index[e.from]][index[e.from]];
    ++L[index[e.to]][index[e.to]];
  }
  return L;
}

Weight spaninng_trees(UnionFind<Vertex> cc, vector<Vertex> root, int bit) {
  auto COUNTRY = {N, N + 1};
  for(int i = 0; i < root.size(); ++i) {
    if((bit >> i) & 1) cc.unite(root[i], N + 1);
    else               cc.unite(root[i], N);
  }
  vector<Weight> det;
  for(auto c: COUNTRY) det.push_back(determinant(Laplacian(cc, c)));
  return (det[0] * det[1]) % MOD;
}

Weight Kruskal() {
  sort(begin(E), end(E), [](Edge lhs, Edge rhs) {return lhs.weight < rhs.weight;});
  UnionFind<Vertex> group;
  for(auto e: E) {
    group.unite(e.from, e.to);
    if(group.size(e.from) == N) return e.weight;
  }
  exit(1);
}

void solve() {
  auto D = Kruskal();

  UnionFind<Vertex> cc;
  for(auto e: E) if(e.weight < D) cc.unite(e.from, e.to);

  set<Vertex> tmp;
  for(Vertex v = 0; v < N; ++v) tmp.insert(cc.find(v));
  vector<Vertex> root(begin(tmp), end(tmp));

  Weight res = 0;
  for(int bit = 1; bit < (1 << root.size()) - 1; ++bit) {
    res = (res + spaninng_trees(cc, root, bit)) % MOD;
  }
  cout << D << " " << res << endl;
}

int main() {
  cin >> N >> M;
  for(int i = 0; i < M; ++i) {
    Vertex s, t; Weight d;
    cin >> s >> t >> d;
    --s; --t;
    E.push_back({s, t, d});
  }
  solve();
}