#include <bits/stdc++.h>
const int MAXN = 1E5 + 5;
bool bipar[MAXN]{};
int color[MAXN]{};
std::vector<int> graph[MAXN]{};
int subtr[MAXN]{};
bool visit[MAXN]{};
int count[2], glblC;
int M, N, U, V;
long long Ans = 0;
inline long long sum(int N) { return 1LL * N * (N + 1) >> 1; }
void dfs(int cur) {
  visit[cur] = true;
  for (auto& nxt : graph[cur])
    if (!visit[nxt]) {
      color[nxt] = color[cur] ^ 1;
      dfs(nxt);
    } else if (color[nxt] == color[cur])
      bipar[glblC] = false;
  ++count[color[cur]];
  ++subtr[glblC];
}
int main() {
  scanf(" %d%d", &N, &M);
  for (int i = 0; i < M; ++i) {
    scanf(" %d%d", &U, &V);
    graph[U].push_back(V);
    graph[V].push_back(U);
  }
  if (M == 0) return printf("3 %lld\n", 1LL * N * (N - 1) * (N - 2) / 6) & 0;
  memset((color), (-1), sizeof(color));
  bool isBipar = true, overTwo = false;
  for (int i = 1; i <= N; ++i)
    if (!visit[i]) {
      glblC = i;
      bipar[i] = true;
      color[i] = count[0] = count[1] = 0;
      dfs(i);
      Ans += sum(count[0] - 1) + sum(count[1] - 1);
      isBipar &= bipar[i];
      overTwo |= (subtr[i] > 2);
    }
  if (!overTwo) return printf("2 %lld\n", 1LL * M * (N - 2)) & 0;
  if (!isBipar) return puts("0 1"), 0;
  printf("1 %lld\n", Ans);
  return 0;
}
