Problem:
B: Brilliant Stars
ICPC で良い成績を収めるには修行が欠かせない．うさぎは ICPC で勝ちたいので，今日も修行をすることにした．
今日の修行は，夜空に輝くたくさんの星たちを観測して，視力と集中力を鍛えようというものである．うさぎは独自のセンスで星の特徴を記録していくことができる．
うさぎは「星の観測日記」として記録した星の特徴をノートにつけていくことにした．ここで，「似ている」 2 つの星をともに記録することは避けたい．2 つの星が「似ている」かどうかは，すべてうさぎの判断で決まっている．「似ている」かどうかの関係はあまり複雑ではなく，以下の条件を満たす．
条件： 異なる 4 つの星 A, B, C, D があり，A と B，B と C，C と D がそれぞれ「似ている」とする．このとき，A と C が「似ている」か，B と D が「似ている」か，あるいはその両方が成り立つ．
うさぎは「似ている」 2 つの星を記録しないようになるべくたくさんの星を記録したい．また，そのようにする方法が何通りあるかも知りたい．
Input
N
M
X
1
Y
1
...
X
M
Y
M
N
は星の個数，
M
は「似ている」 2 つの星の組の個数である．星は 1 以上
N
以下の整数の番号により表され，
X
i
,
Y
i
(1 ≤
i
≤
M
) は星
X
i
と星
Y
i
が「似ている」ことを表す．
1 ≤
N
≤ 100,000，0 ≤
M
≤ 200,000，1 ≤
X
i
<
Y
i
≤
N
を満たす．(
X
i
,
Y
i
) として同一の組は複数回現れない．「似ている」かどうかの関係は，問題文で指定された条件を満たす．
Output
1 行目に，「似ている」 2 つの星を記録しないように記録できる星の個数の最大値を，2 行目に，その最大値を実現できる星の組み合わせの個数 (記録する順番のみを変えたものは同じと考える) を 1,000,000,009 で割った余りを出力せよ．
Sample Input 1
4 3
1 2
1 3
1 4
Sample Output 1
3
1
Sample Input 2
11 5
1 2
3 4
5 6
7 8
9 10
Sample Output 2
6
32
Sample Input 3
9 14
1 2
1 3
2 3
3 4
3 5
3 6
3 7
3 8
3 9
4 5
4 6
5 6
7 8
8 9
Sample Output 3
4
6

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = 1ll << 60;
#define REP(i, n) for(ll i=0; i <ll(n); i++)
template <class T> using V = vector<T>;
template <class A, class B>
bool chmax(A &a, B b) { return a < b && (a=b, true); }
template <class A, class B>
bool chmin(A &a, B b) { return b < a && (a=b, true); }


void testcase(){
  int N, M; cin >> N >> M;
  V<V<int>> adj(N);
  REP(i,M){
    int u,v; cin >> u >> v; u--; v--;
    adj[u].push_back(v);
    adj[v].push_back(u);
  }
  V<int> deg(N);
  REP(i,N) deg[i] = adj[i].size();
  V<V<int>> que(N);
  REP(i,N) REP(j,deg[i]+1) que[j].push_back(i);
  V<int> peo;
  for(int d=N-1; d>=0; d--) for(int v : que[d]) if(deg[v] == d){
    deg[v] = -1;
    peo.push_back(v);
    for(int w : adj[v]) deg[w]--;
  }
  reverse(peo.begin(), peo.end());
  V<int> hit(N), used(N), ord(N);
  REP(i,N) ord[peo[i]] = i;
  for(int v : peo) if(!hit[v]){
    hit[v] = used[v] = 1;
    for(int w : adj[v]) hit[w]++;
  }
  int val = 0;
  for(int x : used) val += x;
  ll cnt = 1;
  for(int v : peo) if(used[v]){
    ll t = 1;
    for(int w : adj[v]) if(ord[v] < ord[w] && hit[w] == 1) t++;
    cnt = cnt * t % 1000000009;
  }
  cout << val << "\n" << cnt << "\n";
}

int main() {
  cin.tie(nullptr)->sync_with_stdio(false);
  testcase();
  return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 15540
final_rank: 4

code_snippet: // AOJ #2291
// Brilliant Stars 2025.2.9

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

#define gc() getchar_unlocked()
#define pc(c) putchar_unlocked(c)

int Cin() {
	int n = 0, c = gc();
	if (c == '-') {	c = gc();
		do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
		return -n;
	}
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

void Cout(ll n) {
	char b[30];
	if (!n) pc('0');
	else {
		if (n < 0) pc('-'), n = -n;
		int i = 0; while (n) b[i++] = n % 10 + '0', n /= 10;
		while (i--) pc(b[i]);
	}
	pc('\n');
}

const ll MOD = 1000000009;
 
int N, M;
vector<vector<int>> adj;
 
inline bool isAdjacent(int u, int v) {
    return binary_search(adj[u].begin(), adj[u].end(), v);
}
 
pair<ll, ll> solveSubset(const vector<int>& V) {
    if (V.empty()) return {0, 1};
    if (V.size() == 1) return {1, 1};
 
    vector<bool> inLocal(N + 1, false);
    for (int v : V) inLocal[v] = true;
 
    vector<bool> visited(N + 1, false);
    vector<vector<int>> compList;
    for (int v : V) {
        if (!visited[v]) {
            vector<int> comp;
            queue<int> q;
            q.push(v);
            visited[v] = true;
            while (!q.empty()) {
                int cur = q.front();
                q.pop();
                comp.push_back(cur);
                for (int nb : adj[cur]) {
                    if (inLocal[nb] && !visited[nb]) {
                        visited[nb] = true;
                        q.push(nb);
                    }
                }
            }
            compList.push_back(comp);
        }
    }
 
    if (compList.size() > 1) {
        ll totalSize = 0, totalWays = 1;
        for (auto &comp : compList) {
            auto subRes = solveSubset(comp);
            totalSize += subRes.first;
            totalWays = (totalWays * subRes.second) % MOD;
        }
        return {totalSize, totalWays};
    }
 
    set<int> rem;
    for (int v : V) rem.insert(v);

    vector<vector<int>> compComp;
    while (!rem.empty()) {
        int start = *rem.begin();
        rem.erase(rem.begin());
        vector<int> comp;
        queue<int> q;
        q.push(start);
        comp.push_back(start);
        while (!q.empty()) {
            int cur = q.front();
            q.pop();
            for (auto it = rem.begin(); it != rem.end(); ) {
                int candidate = *it;
                if (!isAdjacent(cur, candidate)) {
                    q.push(candidate);
                    comp.push_back(candidate);
                    it = rem.erase(it);
                } else ++it;
            }
        }
        compComp.push_back(comp);
    }
 
    ll bestSize = 0, waysCount = 0;
    for (auto &comp : compComp) {
        auto subRes = solveSubset(comp);
        if (subRes.first > bestSize) {
            bestSize = subRes.first;
            waysCount = subRes.second;
        } else if (subRes.first == bestSize) {
            waysCount = (waysCount + subRes.second) % MOD;
        }
    }
    return {bestSize, waysCount};
}
 
int main() {
    N = Cin(), M = Cin();
    adj.resize(N + 1);
    for (int i = 0; i < M; i++){
        int u = Cin(), v = Cin();
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    for (int i = 1; i <= N; i++){
        sort(adj[i].begin(), adj[i].end());
    }
 
    vector<int> allVerts;
    allVerts.reserve(N);
    for (int i = 1; i <= N; i++){
        allVerts.push_back(i);
    }
 
    auto ans = solveSubset(allVerts);
    Cout(ans.first), Cout(ans.second % MOD);
    return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 26488
final_rank: 8

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

using ll = long long;
const ll MOD = 1e9 + 9;

using G = vector<vector<int>>;
struct SCC {
  int n;
  const G &g;
  G edge, redge;
  vector<int> comp, order, used;
  
  SCC(int n, G &g) : n(n), g(g), edge(n), redge(n), comp(n, -1), used(n) {
    for (int i = 0; i < n; ++i) {
      for (auto e : g[i]) {
        edge[i].emplace_back(e);
        redge[e].emplace_back(i);
      }
    }
  }
  
  void dfs(int idx) {
    if (used[idx]) return;
    used[idx] = true;
    for (int to : edge[idx]) dfs(to);
    order.emplace_back(idx);
  }
  
  void rdfs(int idx, int cnt) {
    if (comp[idx] != -1) return;
    comp[idx] = cnt;
    for (int to : redge[idx]) rdfs(to, cnt);
  }
  
  G build() {
    G t;
    for (int i = 0; i < n; ++i) dfs(i);
    reverse(order.begin(), order.end());
    int ptr = 0;
    for (int i  : order) {
      if (comp[i] == -1) {
        rdfs(i, ptr), ptr++;
      }
    }
    
    t.resize(ptr);
    for (int i = 0; i < n; ++i) {
      t[comp[i]].emplace_back(i);
    }
    return t;
  }
  
};


int main() {
  ll N, M; cin >> N >> M;
  vector<int> deg(N, 0);
  vector< array<int, 2> > edge(M);
  for (int i = 0; i < M; ++i) {
    int x, y; cin >> x >> y;
    x--, y--;
    edge[i] = {x, y};
    deg[x]++;
    deg[y]++;
  }
  
  G graph(N);
  for (auto [x, y] : edge) {
    if (deg[x] <= deg[y]) graph[x].emplace_back(y);
    if (deg[y] <= deg[x]) graph[y].emplace_back(x);
  }
  vector<int> in(N, 0), out(N, 0);
  for (int u = 0; u < N; ++u) {
    for (auto v : graph[u]) {
      in[v]++;
      out[u]++;
    }
  }
  
  SCC hoge(N, graph);
  G scc = hoge.build();
  
  ll mx = 0, mult = 1;
  for (auto vec : scc) {
    int n = vec.size();
    int v = vec[0];
    
    if (in[v] == n-1) {
      mx++;
      mult *= n;
      mult %= MOD;
    }
  }
  cout << mx << endl;
  cout << mult << endl;
  
  return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 27472
final_rank: 7

code_snippet: #include <iostream>
#include <vector>
#include <queue>
#include <tuple>
using namespace std;

int N;
int M, X[200009], Y[200009];
int Deg[200009];
int Col[200009], NumCol;
int Sta[200009], NumSta;
int Height[200009];
vector<int> G[200009];
vector<int> H[200009];
vector<int> I[200009];
queue<tuple<vector<int>, vector<pair<int, int>>, int>> Q;

void dfs(int pos) {
	Col[pos] = NumCol;
	for (int to : G[pos]) {
		if (Col[to] != -1) continue;
		dfs(to);
	}
}

void dfs2(int pos) {
	Sta[pos] = NumSta;
	for (int to : I[pos]) {
		if (Sta[to] != -1) continue;
		dfs2(to);
	}
}

void dfs3(int pos, int dep) {
	Height[pos] = dep;
	for (int to : H[pos]) {
		int nex_dep = dep + 1; if (H[to].size() >= 2) nex_dep = 0;
		dfs3(to, nex_dep);
	}
}

int MakeTree(vector<int> V1, vector<pair<int, int>> E1) {
	Q.push(make_tuple(V1, E1, -1));
	int Root = -1;

	while (!Q.empty()) {
		vector<int> V = get<0>(Q.front());
		vector<pair<int, int>> E = get<1>(Q.front());
		int Parent = get<2>(Q.front());
		Q.pop();

		// Step A. Find Degree
		for (int i : V) Deg[i] = 0;
		for (int i = 0; i < E.size(); i++) Deg[E[i].first] += 1;
		for (int i = 0; i < E.size(); i++) Deg[E[i].second] += 1;

		// Step B. Get Maximum
		int MaxID = -1;
		for (int i = 0; i < V.size(); i++) {
			if (Deg[V[i]] == V.size() - 1) { MaxID = V[i]; break; }
		}
		if (Parent == -1) Root = MaxID;
		if (Parent != -1) H[Parent].push_back(MaxID);
		if (V.size() == 1) continue;

		// Step C. Make Graph
		for (int i : V) G[i].clear();
		for (int i : V) Col[i] = -1;
		for (pair<int, int> i : E) {
			if (i.first != MaxID && i.second != MaxID) {
				G[i.first].push_back(i.second);
				G[i.second].push_back(i.first);
			}
		}

		// Step D. DFS
		NumCol = 0;
		for (int i : V) {
			if (Col[i] != -1 || i == MaxID) continue;
			dfs(i);
			NumCol += 1;
		}

		// Step E. Recursion
		vector<vector<int>> V2(NumCol);
		vector<vector<pair<int, int>>> E2(NumCol);
		for (int i : V) {
			if (i != MaxID) V2[Col[i]].push_back(i);
		}
		for (pair<int, int> i : E) {
			if (i.first == MaxID || i.second == MaxID) continue;
			E2[Col[i.first]].push_back(i);
		}
		for (int i = 0; i < V2.size(); i++) Q.push(make_tuple(V2[i], E2[i], MaxID));
	}

	// Return
	return Root;
}

int main() {
	// Step 1. Input
	cin >> N >> M;
	for (int i = 1; i <= M; i++) cin >> X[i] >> Y[i];
	for (int i = 1; i <= M; i++) I[X[i]].push_back(Y[i]);
	for (int i = 1; i <= M; i++) I[Y[i]].push_back(X[i]);

	// Step 2. Connected Components
	for (int i = 1; i <= N; i++) Sta[i] = -1;
	for (int i = 1; i <= N; i++) {
		if (Sta[i] != -1) continue;
		dfs2(i);
		NumSta += 1;
	}

	// Step 3. Make Tree
	vector<vector<int>> V(NumSta);
	vector<vector<pair<int, int>>> E(NumSta);
	vector<int> Root;
	for (int i = 1; i <= N; i++) V[Sta[i]].push_back(i);
	for (int i = 1; i <= M; i++) E[Sta[X[i]]].push_back(make_pair(X[i], Y[i]));
	for (int i = 0; i < NumSta; i++) {
		int ret = MakeTree(V[i], E[i]);
		Root.push_back(ret);
	}

	// Step 4. Calculate Answer
	long long mod = 1000000009;
	long long Answer1 = 0;
	long long Answer2 = 1;
	for (int i : Root) dfs3(i, (H[i].size() >= 2 ? 0 : 1));
	for (int i = 1; i <= N; i++) {
		if (H[i].size() >= 1) continue;
		Answer1 += 1;
		Answer2 *= (long long)Height[i];
		Answer2 %= mod;
	}
	cout << Answer1 << endl;
	cout << Answer2 << endl;
	return 0;
}
accuracy: 1
time_ms: 680
memory_kb: 44116
final_rank: 14

code_snippet: //#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
const ll mod = 1000000009;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);

ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 10;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

using mp = pair<int, modint>;
void merge(mp& a, mp b) {
	if (a.first < b.first)a = b;
	else if (a.first == b.first)a.second += b.second;
}
void solve() {
	int n, m; cin >> n >> m;
	vector<vector<int>> G(n);
	rep(i, m) {
		int a, b; cin >> a >> b; a--; b--;
		G[a].push_back(b);
		G[b].push_back(a);
	}
	auto comp = [&](int i, int j) {
		return G[i].size() < G[j].size();
	};
	vector<int> ori(n); rep(i, n)ori[i] = i;
	sort(all(ori), comp);
	vector<int> rev(n); rep(i, n)rev[ori[i]] = i;
	vector<bool> ban(n);
	vector<mp> dp(n);
	rep(i, n) {
		int id = ori[i];
		mp s2 = { 0,1 };
		for (int to : G[id]) {
			int j = rev[to];
			if (j < i && !ban[j]) {
				s2.first += dp[j].first;
				s2.second *= dp[j].second;
				ban[j] = true;
			}
		}
		mp s1 = { 1,1 };
		merge(s1, s2);
		dp[i] = s1;
	}
	int ans1 = 0;
	modint ans2 = 1;
	rep(i, n)if (!ban[i]) {
		ans1 += dp[i].first;
		ans2 *= dp[i].second;
	}
	cout << ans1 << "\n";
	cout << ans2 << "\n";
}



signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(8);
	//init_f();
	//init();
	//int t; cin >> t; rep(i, t)
	solve();
	return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 11008
final_rank: 2

code_snippet: //#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
const ll mod = 1000000009;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);

ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 10;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

using mp = pair<int, modint>;
void merge(mp& a, mp b) {
	if (a.first < b.first)a = b;
	else if (a.first == b.first)a.second += b.second;
}
void solve() {
	int n, m; cin >> n >> m;
	vector<set<int>> G(n);
	rep(i, m) {
		int a, b; cin >> a >> b; a--; b--;
		G[a].insert(b);
		G[b].insert(a);
	}
	vector<int> trans(n);
	vector<bool> ban(n);
	function<mp(vector<int>)> calc = [&](vector<int> ids)->mp {
		rep(j, ids.size()) {
			trans[ids[j]] = j;
		}
		vector<bool> used(ids.size());
		pair<int, modint> res = { 0,1 };
		rep(i, ids.size()) {
			if (used[i])continue;
			queue<int> q; q.push(ids[i]); used[i] = true;
			vector<int> nids;
			while (!q.empty()) {
				int id = q.front(); q.pop();
				nids.push_back(id);
				for (int to : G[id])if (!used[trans[to]]) {
					used[trans[to]] = true;
					q.push(to);
				}
			}
			if (nids.size() == 1) {
				res.first++;
				continue;
			}
			//cout << nids.size() << "\n";
			vector<int> ones;
			rep(j, nids.size())if (G[nids[j]].size() == nids.size() - 1) {
				ones.push_back(nids[j]);
				ban[nids[j]] = true;
			}
			assert(ones.size());
			mp s1 = { 1,ones.size() };
			vector<int> nv;
			rep(j, nids.size())if (G[nids[j]].size() < nids.size() - 1)nv.push_back(nids[j]);
			for (int id : ones)for (int to : G[id])if (!ban[to])G[to].erase(id);
			mp s2 = calc(nv);
			merge(s1, s2);
			res.first += s1.first;
			res.second *= s1.second;
		}
		return res;
	};
	vector<int> ori(n); rep(i, n)ori[i] = i;
	mp p = calc(ori);
	int ans1 = p.first;
	modint ans2 = p.second;
	cout << ans1 << "\n";
	cout << ans2 << "\n";
}



signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(8);
	//init_f();
	//init();
	//int t; cin >> t; rep(i, t)
	solve();
	return 0;
}
accuracy: 1
time_ms: 1660
memory_kb: 29688
final_rank: 15

code_snippet: #include <bits/stdc++.h>
#define FOR(i, n, m) for(ll i = (n); i < (ll)(m); i++)
#define REP(i, n) FOR(i, 0, n)
#define ALL(v) v.begin(), v.end()
#define pb push_back
using namespace std;
using ll = long long;
using ld = long double;
using P = pair<ll, ll>;
constexpr ll inf = 1000000000;
constexpr ll mod = 1000000009;
constexpr long double eps = 1e-6;
 
template<typename T1, typename T2>
ostream& operator<<(ostream& os, pair<T1, T2> p) {
    os << to_string(p.first) << " " << to_string(p.second);
    return os;
}
template<typename T>
ostream& operator<<(ostream& os, vector<T>& v) {
    REP(i, v.size()) {
        if(i) os << " ";
        os << v[i];
    }
    return os;
}
 
struct modint {
    ll n;
public:
    modint(const ll n = 0) : n((n % mod + mod) % mod) {}
    static modint pow(modint a, int m) {
        modint r = 1;
        while(m > 0) {
            if(m & 1) { r *= a; }
            a = (a * a); m /= 2;
        }
        return r;
    }
    modint &operator++() { *this += 1; return *this; }
    modint &operator--() { *this -= 1; return *this; }
    modint operator++(int) { modint ret = *this; *this += 1; return ret; }
    modint operator--(int) { modint ret = *this; *this -= 1; return ret; }
    modint operator~() const { return (this -> pow(n, mod - 2)); } // inverse
    friend bool operator==(const modint& lhs, const modint& rhs) {
        return lhs.n == rhs.n;
    }
    friend bool operator<(const modint& lhs, const modint& rhs) {
        return lhs.n < rhs.n;
    }
    friend bool operator>(const modint& lhs, const modint& rhs) {
        return lhs.n > rhs.n;
    }
    friend modint &operator+=(modint& lhs, const modint& rhs) {
        lhs.n += rhs.n;
        if (lhs.n >= mod) lhs.n -= mod;
        return lhs;
    }
    friend modint &operator-=(modint& lhs, const modint& rhs) {
        lhs.n -= rhs.n;
        if (lhs.n < 0) lhs.n += mod;
        return lhs;
    }
    friend modint &operator*=(modint& lhs, const modint& rhs) {
        lhs.n = (lhs.n * rhs.n) % mod;
        return lhs;
    }
    friend modint &operator/=(modint& lhs, const modint& rhs) {
        lhs.n = (lhs.n * (~rhs).n) % mod;
        return lhs;
    }
    friend modint operator+(const modint& lhs, const modint& rhs) {
        return modint(lhs.n + rhs.n);
    }
    friend modint operator-(const modint& lhs, const modint& rhs) {
        return modint(lhs.n - rhs.n);
    }
    friend modint operator*(const modint& lhs, const modint& rhs) {
        return modint(lhs.n * rhs.n);
    }
    friend modint operator/(const modint& lhs, const modint& rhs) {
        return modint(lhs.n * (~rhs).n);
    }
};
istream& operator>>(istream& is, modint m) { is >> m.n; return is; }
ostream& operator<<(ostream& os, modint m) { os << m.n; return os; }
 
#define MAX_N 1010101
long long extgcd(long long a, long long b, long long& x, long long& y) {
    long long d = a;
    if (b != 0) {
        d = extgcd(b, a % b, y, x);
        y -= (a / b) * x;
    } else {
        x = 1; y = 0;
    }
    return d;
}
long long mod_inverse(long long a, long long m) {
    long long x, y;
    if(extgcd(a, m, x, y) == 1) return (m + x % m) % m;
    else return -1;
}
vector<long long> fact(MAX_N+1, inf);
long long mod_fact(long long n, long long& e) {
    if(fact[0] == inf) {
        fact[0]=1;
        if(MAX_N != 0) fact[1]=1;
        for(ll i = 2; i <= MAX_N; ++i) {
            fact[i] = (fact[i-1] * i) % mod;
        }
    }
    e = 0;
    if(n == 0) return 1;
    long long res = mod_fact(n / mod, e);
    e += n / mod;
    if((n / mod) % 2 != 0) return (res * (mod - fact[n % mod])) % mod;
    return (res * fact[n % mod]) % mod;
}
// return nCk
long long mod_comb(long long n, long long k) {
    if(n < 0 || k < 0 || n < k) return 0;
    long long e1, e2, e3;
    long long a1 = mod_fact(n, e1), a2 = mod_fact(k, e2), a3 = mod_fact(n - k, e3);
    if(e1 > e2 + e3) return 0;
    return (a1 * mod_inverse((a2 * a3) % mod, mod)) % mod;
}
 
using mi = modint;
 
mi mod_pow(mi a, ll n) {
    mi ret = 1;
    mi tmp = a;
    while(n > 0) {
        if(n % 2) ret *= tmp;
        tmp = tmp * tmp;
        n /= 2;
    }
    return ret;
}
 
ll gcd(ll a, ll b) {
    if (b == 0) return a;
    return gcd(b, a % b);
}

ll ans1 = 0;
mi ans2 = 1;

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int n, m;
    cin >> n >> m;
    vector<set<int>> g(n);
    REP(i, m) {
        int x, y;
        cin >> x >> y;
        x--; y--;
        g[x].insert(y);
        g[y].insert(x);
    }
    vector<int> deg(n, 0);
    REP(i, n) deg[i] = (int)g[i].size();
    vector<pair<int, int>> v(n);
    REP(i, n) v[i] = make_pair(deg[i], i);
    sort(ALL(v)); reverse(ALL(v));
    vector<bool> used(n, false);
    for(auto elm: v) {
        if(used[elm.second]) continue;
        bool k = true;
        for(auto adj: g[elm.second]) {
            if(deg[adj] != deg[elm.second]) k = false;
        }
        if(k) {
            ans1++;
            ans2 *= deg[elm.second] + 1;
            used[elm.second] = true;
            for(auto adj: g[elm.second]) used[adj] = true;
        } else {
            for(auto adj: g[elm.second]) {
                deg[adj]--;
                g[adj].erase(elm.second);
            }
        }
    }
    cout << ans1 << endl;
    cout << ans2 << endl;
    return 0;
}
accuracy: 1
time_ms: 220
memory_kb: 35608
final_rank: 11

code_snippet: #include <bits/stdc++.h>
#define ll long long
#define INF 1000000005
#define MOD 1000000009
#define EPS 1e-10
#define rep(i,n) for(int i=0;i<(int)(n);++i)
#define rrep(i,n) for(int i=(int)(n)-1;i>=0;--i)
#define srep(i,s,t) for(int i=(int)(s);i<(int)(t);++i)
#define each(a,b) for(const auto& (a): (b))
#define all(v) (v).begin(),(v).end()
#define len(v) (int)(v).size()
#define zip(v) sort(all(v)),v.erase(unique(all(v)),v.end())
#define cmx(x,y) x=max(x,y)
#define cmn(x,y) x=min(x,y)
#define fi first
#define se second
#define pb push_back
#define show(x) cout<<#x<<" = "<<(x)<<endl
#define sar(a,n) {cout<<#a<<":";rep(pachico,n)cout<<" "<<a[pachico];cout<<endl;}

using namespace std;

template<typename S,typename T>auto&operator<<(ostream&o,pair<S,T>p){return o<<"{"<<p.fi<<","<<p.se<<"}";}
template<typename T>auto&operator<<(ostream&o,set<T>s){for(auto&e:s)o<<e<<" ";return o;}
template<typename S,typename T,typename U>
auto&operator<<(ostream&o,priority_queue<S,T,U>q){while(!q.empty())o<<q.top()<<" ",q.pop();return o;}
template<typename K,typename T>auto&operator<<(ostream&o,map<K,T>&m){for(auto&e:m)o<<e<<" ";return o;}
template<typename T>auto&operator<<(ostream&o,vector<T>v){for(auto&e:v)o<<e<<" ";return o;}
void ashow(){cout<<endl;}template<typename T,typename...A>void ashow(T t,A...a){cout<<t<<" ";ashow(a...);}
template<typename S,typename T,typename U>
struct TRI{S fi;T se;U th;TRI(){}TRI(S f,T s,U t):fi(f),se(s),th(t){}
bool operator<(const TRI&_)const{return(fi==_.fi)?((se==_.se)?(th<_.th):(se<_.se)):(fi<_.fi);}};
template<typename S,typename T,typename U>
auto&operator<<(ostream&o,TRI<S,T,U>&t){return o<<"{"<<t.fi<<","<<t.se<<","<<t.th<<"}";}

typedef pair<int, int> P;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<double> vd;
typedef vector<P> vp;
typedef vector<string> vs;

const int MAX_N = 100005;

int visit[MAX_N];

void dfs(int u, int& deg, int& ver, int& cnt, vector<int>& vers, const int id, const vector<unordered_set<int> >& G){
    if(deg < (int)G[u].size()){
        deg = (int)G[u].size(), ver = u, cnt = 1;
    }else if(deg == (int)G[u].size()){
        ++cnt;
    }
    visit[u] = id, vers.push_back(u);
    for(const int v : G[u]){
        if(visit[v] != id) dfs(v, deg, ver, cnt, vers, id, G);
    }
}

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);
    int n, m;
    cin >> n >> m;
    vector<unordered_set<int> > G(n);
    unordered_set<int> st;
    rep(i,n) st.insert(i);
    int x, y;
    rep(i,m){
        cin >> x >> y;
        --x, --y;
        G[x].insert(y), G[y].insert(x);
    }
    int id = 1, hoge = 0, ans = 1;
    while(!st.empty()){
        const int v = *st.begin();
        // show(v);
        vector<int> vers;
        int deg = -1, ver = -1, cnt = 0;
        dfs(v, deg, ver, cnt, vers, id++, G);
        // show(vers), show(cnt);
        if(cnt == (int)vers.size()){
            ++hoge;
            ans = (ll)ans * cnt % MOD;
            if(vers.size() == st.size()) break;
            for(const int u : vers) st.erase(u);
        }else{
            for(const int u : G[ver]) G[u].erase(ver);
            st.erase(ver);
        }
    }
    cout << hoge << "\n";
    cout << ans << "\n";
    return 0;
}
accuracy: 1
time_ms: 1830
memory_kb: 30132
final_rank: 16

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
//#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define MOD 1000000009
#define SIZE 100005

struct Edge{
	void set(int arg_from,int arg_to){
		from = arg_from;
		to = arg_to;
	}
	int from,to;
};

int N,M;
ll degree[SIZE],size[SIZE];
bool DELETE[SIZE];
Edge edge[200005];

int main(){

	scanf("%d %d",&N,&M);

	for(int i = 0; i < N; i++){

		degree[i] = 0;
		size[i] = 1;
		DELETE[i] = false;
	}

	int from,to;

	for(int loop = 0; loop < M; loop++){

		scanf("%d %d",&from,&to);
		from--;
		to--;

		edge[loop].set(from,to);

		degree[from]++;
		degree[to]++;
	}

	for(int i = 0; i < M; i++){

		from = edge[i].from;
		to = edge[i].to;

		if((degree[from] < degree[to]) || (degree[from] == degree[to] && from < to)){

			DELETE[to] = true;
		}else{

			DELETE[from] = true;
		}

		if(degree[from] == degree[to]){

			size[from]++;
			size[to]++;
		}
	}

	ll ans_sum = 0,ans_num = 1;

	for(int i = 0; i < N; i++){
		if(DELETE[i])continue;

		ans_sum++;
		ans_num *= size[i];
		ans_num %= MOD;
	}

	printf("%lld\n",ans_sum);
	printf("%lld\n",ans_num);

	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 6440
final_rank: 1

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

class UnionFind {
private:
	vector< int > data;
	
public:
	UnionFind(int n) : data(n, -1) {}
	
	void unionSet(int x, int y) {
		x = root(x); y = root(y);
		if (data[y] < data[x]) swap(x, y);
		if (x != y) { data[x] += data[y]; data[y] = x; }
	}
	
	bool sameSet(int x, int y) { return root(x) == root(y); }
	int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
	int size(int x) { return -data[root(x)]; }
};

int N, M;
vector< vector< int > > aList;

vector< int > getDegOrder() {
	vector< int > deg(N, 0);
	for (int v=0; v<N; ++v) deg[v] = (int)aList[v].size();
	
	using pii = pair< int, int >;
	set< pii > que;
	for (int v=0; v<N; ++v) que.insert(pii(-deg[v], v));
	
	vector< int > ret;
	while (!que.empty()) {
		int v = que.begin()->second; que.erase(que.begin());	
		if (deg[v] < 0) continue;
		ret.push_back(v); deg[v] = -1;
		for (int u : aList[v]) {
			if (deg[u] < 0) continue;
			que.erase(pii(-deg[u], u));	--deg[u];
			que.insert(pii(-deg[u], u));
		}
	}
	return ret;
}

vector< int > constructCliques(const vector< int >& vertex_order) {
	vector< int > mark(N, 0);
	
	UnionFind uf(N);
	for (int v : vertex_order) {
		mark[v] = 1;
		int g = -1;
		for (int u : aList[v]) {
			if (mark[u] == 0) continue;
			int r = uf.root(u);
			if (g != r) g = (g == -1 ? r : -2);
		}
		if (g >= 0) uf.unionSet(g, v);
		if (g == -2) mark[v] = -1;
	}
	
	vector< int > ret;
	for (int v=0; v<N; ++v) {
		if (mark[uf.root(v)] == -1) continue;
		mark[uf.root(v)] = -1;
		ret.push_back(uf.size(v));
	}
	return ret;
}

int main() {
	cin >> N >> M;
	aList.assign(N, vector< int >());
	for (int i=0; i<M; ++i) {
		int u, v; cin >> u >> v; --u; --v;
		aList[u].push_back(v);
		aList[v].push_back(u);
	}
	
	vector< int > deg_order = getDegOrder();
	reverse(deg_order.begin(), deg_order.end());
	vector< int > cliqueSize = constructCliques(deg_order);
	
	using lint = long long int;
	lint ans = 1, MOD = (lint)1e9 + 9;
	for (int x : cliqueSize) ans = (ans * x) % MOD;
	cout << cliqueSize.size() << endl << ans << endl;
}
accuracy: 1
time_ms: 140
memory_kb: 14084
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll=long long;
#define int ll
#define FOR(i,a,b) for(int i=int(a);i<int(b);i++)
#define REP(i,b) FOR(i,0,b)
int read(){
	int i;
	scanf("%lld",&i);
	return i;
}
using vi=vector<int>;
#define PB push_back
#define ALL(x) x.begin(),x.end()
using pi=pair<int,int>;

struct UnionFind{
	vi rank,par;
	void Init(int n){
		rank.assign(n,0);
		par.assign(n,-1);
	}
	int Find(int a){
		return par[a]==-1?a:(par[a]=Find(par[a]));
	}
	bool Same(int a,int b){
		return Find(a)==Find(b);
	}
	void Unite(int a,int b){
		a=Find(a),b=Find(b);
		if(a==b)return;
		if(rank[a]<rank[b])swap(a,b);
		par[b]=a;
		if(rank[a]==rank[b])rank[a]++;
	}
};

const int mod=1000000009;

pi Merge(pi a,pi b){
	return pi(a.first+b.first,a.second*b.second%mod);
}

signed main(){
	int n=read(),m=read();
	vector<vi> g(n);
	vi deg(n,0);
	REP(_,m){
		int a=read()-1,b=read()-1;
		g[a].PB(b);
		g[b].PB(a);
		deg[a]++;
		deg[b]++;
	}
	priority_queue<pi> pq;
	REP(i,n)pq.push(pi(deg[i],i));
	vi used(n,0),ord;
	while(!pq.empty()){
		int v=pq.top().first,i=pq.top().second;
		pq.pop();
		if(deg[i]!=v)continue;
		ord.PB(i);
		for(auto j:g[i])if(!used[j])
			pq.push(pi(--deg[j],j));
		used[i]=1;
	}
	reverse(ALL(ord));
	vector<pi> ans(n);
	UnionFind uf;uf.Init(n);
	used.assign(n,0);
	for(auto i:ord){
		pi w(0,1);
		for(auto j:g[i])if(used[j])
			if(!uf.Same(i,j)){
				w=Merge(w,ans[uf.Find(j)]);
				uf.Unite(i,j);
			}
		if(w.first==0)
			w.first=1;
		else if(w.first==1)
			w.second=(w.second+1)%mod;
		ans[uf.Find(i)]=w;
		used[i]=1;
	}
	pi w=ans[uf.Find(0)];
	REP(i,n)if(!uf.Same(0,i)){
		w=Merge(w,ans[uf.Find(i)]);
		uf.Unite(0,i);
	}
	cout<<w.first<<endl<<w.second<<endl;
}
accuracy: 1
time_ms: 80
memory_kb: 19440
final_rank: 6

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

#define int long long
typedef vector<int>vint;
typedef pair<int,int>pint;
typedef vector<pint>vpint;
#define rep(i,n) for(int i=0;i<(n);i++)
#define reps(i,f,n) for(int i=(f);i<(n);i++)
#define all(v) (v).begin(),(v).end()
#define each(it,v) for(__typeof((v).begin()) it=(v).begin();it!=(v).end();it++)
#define pb push_back
#define fi first
#define se second
template<typename A,typename B>inline void chmin(A &a,B b){if(a>b)a=b;}
template<typename A,typename B>inline void chmax(A &a,B b){if(a<b)a=b;}

const int mod=1000000009;
typedef pair<vint,vpint>graph;
pint op(const pint &a,const pint &b){
    return {a.fi+b.fi,a.se*b.se%mod};
}

vint G[100000];
int deg[100000];
int mark[100000];
int sizev[100000];
int sizee[200000];
pint ans;
int que[100000],tail;

int vs_[100000];pint es_[200000];

void solve2(int N,int *vs,int M,pint *es);

void solve(int N,int *vs,int M,pint *es){
    rep(i,N)deg[vs[i]]=0,mark[vs[i]]=-1;

    for(int i=0;i<M;i++){
        G[es[i].fi][deg[es[i].fi]++]=es[i].se;
        G[es[i].se][deg[es[i].se]++]=es[i].fi;
    }

    vector<int>sizev,sizee;

    int cnt=0;
    for(int i=0;i<N;i++){
        if(mark[vs[i]]!=-1)continue;
        sizev.pb(0);sizee.pb(0);
        int c=cnt++;
        sizev[c]++;
        mark[vs[i]]=c;
        tail=1;
        que[0]=vs[i];
        for(int j=0;j<tail;j++){
            int v=que[j];
            for(int k=0;k<deg[v];k++){
                int u=G[v][k];
                if(mark[u]!=-1)continue;
                mark[u]=c;
                sizev[c]++;
                que[tail++]=u;
            }
        }
    }

    for(int i=0;i<M;i++)sizee[mark[es[i].fi]]++;
    rep(i,N)vs_[i]=vs[i];
    rep(i,M)es_[i]=es[i];

    int c=0;
    for(int i=0;i<cnt;i++){
        int nc=sizev[i]+c;
        sizev[i]=c;
        c=nc;
    }

    c=0;
    for(int i=0;i<cnt;i++){
        int nc=sizee[i]+c;
        sizee[i]=c;
        c=nc;
    }

    rep(i,N){
        int tmp=sizev[mark[vs_[i]]]++;
        vs[tmp]=vs_[i];
    }

    rep(i,M){
        int tmp=sizee[mark[es_[i].fi]]++;
        es[tmp]=es_[i];
    }

    rep(i,cnt){
        int t=i?sizev[i-1]:0;
        int s=i?sizee[i-1]:0;
        solve2(sizev[i]-t,vs+t,sizee[i]-s,es+s);
    }
}

void solve2(int N,int *vs,int M,pint *es){
    if(N*(N-1)/2==M){
        ans=op(ans,{1,N});
        return;
    }

    rep(i,N)deg[vs[i]]=0;

    for(int i=0;i<M;i++)deg[es[i].fi]++,deg[es[i].se]++;
    int cent=-1;
    rep(i,N){
        if(deg[vs[i]]==N-1)cent=vs[i];
        deg[vs[i]]=0;
    }
    assert(cent!=-1);

    int t=0;
    rep(i,N){
        if(vs[i]==cent)continue;
        vs[t++]=vs[i];
    }

    int s=0;
    rep(i,M){
        if(es[i].fi==cent||es[i].se==cent)continue;
        es[s++]=es[i];
    }
    solve(t,vs,s,es);
}

signed main(){
    int N,M;
    scanf("%lld%lld",&N,&M);


    static int vs[100000];
    static pint es[200000];
    rep(i,N)vs[i]=i;
    rep(i,M){
        int a,b;
        scanf("%lld%lld",&a,&b);
        a--;b--;
        es[i]={a,b};
        G[a].pb(b);G[b].pb(a);
    }

    memset(mark,-1,sizeof(mark));
    ans={0,1};
    solve(N,vs,M,es);
    printf("%lld\n%lld\n",ans.fi,ans.se);
    return 0;
}
accuracy: 1
time_ms: 490
memory_kb: 21960
final_rank: 9

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

#define int long long
typedef vector<int>vint;
typedef pair<int,int>pint;
typedef vector<pint>vpint;
#define rep(i,n) for(int i=0;i<(n);i++)
#define reps(i,f,n) for(int i=(f);i<(n);i++)
#define all(v) (v).begin(),(v).end()
#define each(it,v) for(__typeof((v).begin()) it=(v).begin();it!=(v).end();it++)
#define pb push_back
#define fi first
#define se second
template<typename A,typename B>inline void chmin(A &a,B b){if(a>b)a=b;}
template<typename A,typename B>inline void chmax(A &a,B b){if(a<b)a=b;}

const int mod=1000000009;

pint op(const pint &a,const pint &b){
    return {a.fi+b.fi,a.se*b.se%mod};
}

vint G[100000];
int deg[100000];
int mark[100000];
int sizev[100000];
int sizee[200000];
pint ans;
int que[100000],tail;

int vs_[100000];pint es_[200000];

void solve2(int N,int *vs,int M,pint *es);

void solve(int N,int *vs,int M,pint *es){
    rep(i,N)deg[vs[i]]=0,mark[vs[i]]=-1;

    for(int i=0;i<M;i++){
        G[es[i].fi][deg[es[i].fi]++]=es[i].se;
        G[es[i].se][deg[es[i].se]++]=es[i].fi;
    }

    int cnt=0;
    for(int i=0;i<N;i++){
        if(mark[vs[i]]!=-1)continue;
        sizev[cnt]=sizee[cnt]=0;
        int c=cnt++;
        sizev[c]++;
        mark[vs[i]]=c;
        tail=1;
        que[0]=vs[i];
        for(int j=0;j<tail;j++){
            int v=que[j];
            for(int k=0;k<deg[v];k++){
                int u=G[v][k];
                if(mark[u]!=-1)continue;
                mark[u]=c;
                sizev[c]++;
                que[tail++]=u;
            }
        }
    }

    for(int i=0;i<M;i++)sizee[mark[es[i].fi]]++;
    rep(i,N)vs_[i]=vs[i];
    rep(i,M)es_[i]=es[i];

    int c=0;
    for(int i=0;i<cnt;i++){
        int nc=sizev[i]+c;
        sizev[i]=c;
        c=nc;
    }

    c=0;
    for(int i=0;i<cnt;i++){
        int nc=sizee[i]+c;
        sizee[i]=c;
        c=nc;
    }

    rep(i,N){
        int tmp=sizev[mark[vs_[i]]]++;
        vs[tmp]=vs_[i];
    }

    rep(i,M){
        int tmp=sizee[mark[es_[i].fi]]++;
        es[tmp]=es_[i];
    }

    rep(i,cnt){
        int t=i?sizev[i-1]:0;
        int s=i?sizee[i-1]:0;
        solve2(sizev[i]-t,vs+t,sizee[i]-s,es+s);
    }
}

void solve2(int N,int *vs,int M,pint *es){
    if(N*(N-1)/2==M){
        ans=op(ans,{1,N});
        return;
    }

    rep(i,N)deg[vs[i]]=0;

    for(int i=0;i<M;i++)deg[es[i].fi]++,deg[es[i].se]++;
    int cent=-1;
    rep(i,N){
        if(deg[vs[i]]==N-1)cent=vs[i];
    }

    int t=0;
    rep(i,N){
        if(vs[i]==cent)continue;
        vs[t++]=vs[i];
    }

    int s=0;
    rep(i,M){
        if(es[i].fi==cent||es[i].se==cent)continue;
        es[s++]=es[i];
    }
    solve(t,vs,s,es);
}

signed main(){
    int N,M;
    scanf("%lld%lld",&N,&M);


    static int vs[100000];
    static pint es[200000];
    rep(i,N)vs[i]=i;
    rep(i,M){
        int a,b;
        scanf("%lld%lld",&a,&b);
        a--;b--;
        es[i]={a,b};
        G[a].pb(b);G[b].pb(a);
    }
    ans={0,1};
    solve(N,vs,M,es);
    printf("%lld\n%lld\n",ans.fi,ans.se);
    return 0;
}
accuracy: 0.175
time_ms: 260
memory_kb: 23380
final_rank: 20

code_snippet: #include <iostream>
#include <vector>
using namespace std;

typedef long long ll;
ll _MOD = 1000000009;

struct union_find {
	vector<int> v;
	union_find(int n) : v(n, -1) {}
	int find(int x) { return (v[x] < 0) ? x : (v[x] = find(v[x])); }
	void unite(int x, int y) {
		x = find(x); y = find(y);
		if (x != y) {
			if (-v[x] < -v[y]) swap(x, y);
			v[x] += v[y]; v[y] = x;
		}
	}
	bool same(int x, int y) { return find(x) == find(y); }
	int size(int x) { return -v[find(x)]; }
};

int main() {
	int n, m; cin >> n >> m;
	vector<int> a(m), b(m);
	for (int i = 0; i < m; i++) {
		scanf("%d%d", &a[i], &b[i]);
		a[i]--;
		b[i]--;
	}
	vector<bool> rm(n);
	for (;;) {
		vector<int> d(n);
		union_find uf(n);
		for (int i = 0; i < m; i++) {
			d[a[i]]++;
			d[b[i]]++;
			uf.unite(a[i], b[i]);
		}
		vector<vector<int> > v(n);
		for (int u = 0; u < n; u++) {
			if (rm[u]) continue;
			int p = uf.find(u);
			if (d[u] == uf.size(p) - 1)
				v[p].push_back(u);
		}
		bool updated = false;
		for (int p = 0; p < n; p++) {
			if (rm[p]) continue;
			if (uf.find(p) != p) continue;
			if (v[p].size() == uf.size(p)) continue;
			updated = true;
			for (int j = 0; j < v[p].size(); j++)
				rm[v[p][j]] = true;
		}
		if (!updated) {
			int x = 0, y = 1;
			for (int p = 0; p < n; p++) {
				if (rm[p]) continue;
				if (uf.find(p) != p) continue;
				x++;
				y = (ll)y * uf.size(p) % _MOD;
			}
			cout << x << endl << y << endl;
			return 0;
		}
		vector<int> _a, _b;
		for (int i = 0; i < m; i++)
			if (!rm[a[i]] && !rm[b[i]]) {
				_a.push_back(a[i]);
				_b.push_back(b[i]);
			}
		m = _a.size();
		a = _a;
		b = _b;
	}
}
accuracy: 1
time_ms: 1580
memory_kb: 11892
final_rank: 12

code_snippet: #define _USE_MATH_DEFINES
#include <algorithm>
#include <cstdio>
#include <fstream>
#include <functional>
#include <iostream>
#include <cfloat>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <time.h>
#include <vector>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> i_i;
typedef pair<ll, int> ll_i;
typedef pair<double, int> d_i;
typedef pair<ll, ll> ll_ll;
typedef pair<double, double> d_d;
struct edge { int v, w; };

ll MOD = 1000000007;
ll _MOD = 1000000009;
double EPS = 1e-10;

struct union_find {
	vector<int> v;
	union_find(int n) : v(n, -1) {}
	int find(int x) { return (v[x] < 0) ? x : (v[x] = find(v[x])); }
	void unite(int x, int y) {
		x = find(x); y = find(y);
		if (x != y) {
			if (-v[x] < -v[y]) swap(x, y);
			v[x] += v[y]; v[y] = x;
		}
	}
	bool same(int x, int y) { return find(x) == find(y); }
	int size(int x) { return -v[find(x)]; }
};

int main() {
	int n, m; cin >> n >> m;
	vector<int> a(m), b(m);
	for (int i = 0; i < m; i++) {
		scanf("%d%d", &a[i], &b[i]);
		a[i]--;
		b[i]--;
	}
	vector<bool> rm(n);
	for (;;) {
		vector<int> d(n);
		union_find uf(n);
		for (int i = 0; i < m; i++) {
			d[a[i]]++;
			d[b[i]]++;
			uf.unite(a[i], b[i]);
		}
		vector<vector<int> > v(n);
		for (int u = 0; u < n; u++) {
			if (rm[u]) continue;
			int p = uf.find(u);
			if (d[u] == uf.size(p) - 1)
				v[p].push_back(u);
		}
		bool updated = false;
		for (int p = 0; p < n; p++) {
			if (rm[p]) continue;
			if (uf.find(p) != p) continue;
			if (v[p].size() == uf.size(p)) continue;
			updated = true;
			for (int j = 0; j < v[p].size(); j++)
				rm[v[p][j]] = true;
		}
		if (!updated) {
			int x = 0, y = 1;
			for (int p = 0; p < n; p++) {
				if (rm[p]) continue;
				if (uf.find(p) != p) continue;
				x++;
				y = (ll)y * uf.size(p) % _MOD;
			}
			cout << x << endl << y << endl;
			return 0;
		}
		vector<int> _a, _b;
		for (int i = 0; i < m; i++)
			if (!rm[a[i]] && !rm[b[i]]) {
				_a.push_back(a[i]);
				_b.push_back(b[i]);
			}
		m = _a.size();
		a = _a;
		b = _b;
	}
}
accuracy: 1
time_ms: 1590
memory_kb: 11892
final_rank: 13

code_snippet: #define _USE_MATH_DEFINES
#include <algorithm>
#include <cstdio>
#include <fstream>
#include <functional>
#include <iostream>
#include <cfloat>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <time.h>
#include <vector>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> i_i;
typedef pair<ll, int> ll_i;
typedef pair<double, int> d_i;
typedef pair<ll, ll> ll_ll;
typedef pair<double, double> d_d;
struct edge { int v, w; };

ll MOD = 1000000007;
ll _MOD = 1000000009;
double EPS = 1e-10;

struct union_find {
	vector<int> v;
	union_find(int n) : v(n, -1) {}
	int find(int x) { return (v[x] < 0) ? x : (v[x] = find(v[x])); }
	void unite(int x, int y) {
		x = find(x); y = find(y);
		if (x != y) {
			if (-v[x] < -v[y]) swap(x, y);
			v[x] += v[y]; v[y] = x;
		}
	}
	bool same(int x, int y) { return find(x) == find(y); }
	int size(int x) { return -v[find(x)]; }
};

i_i g(vector<int> a, vector<int> b);

i_i f(int n, vector<int> a, vector<int> b) {
	int m = a.size();
	union_find uf(n);
	for (int i = 0; i < m; i++)
		uf.unite(a[i], b[i]);
	vector<vector<int> > as(n), bs(n);
	for (int i = 0; i < m; i++) {
		int u = uf.find(a[i]);
		as[u].push_back(a[i]);
		bs[u].push_back(b[i]);
	}
	i_i ans(0, 1);
	for (int u = 0; u < n; u++) {
		if (uf.find(u) != u) continue;
		i_i p = g(as[u], bs[u]);
		ans.first += p.first;
		ans.second = (ll)ans.second * p.second % MOD;
	}
	return ans;
}

i_i g(vector<int> a, vector<int> b) {
	int m = a.size();
	vector<int> v;
	for (int i = 0; i < m; i++) {
		v.push_back(a[i]);
		v.push_back(b[i]);
	}
	sort(v.begin(), v.end());
	v.erase(unique(v.begin(), v.end()), v.end());
	int n = v.size();
	if (!n) n = 1;
	for (int i = 0; i < m; i++) {
		a[i] = lower_bound(v.begin(), v.end(), a[i]) - v.begin();
		b[i] = lower_bound(v.begin(), v.end(), b[i]) - v.begin();
	}
	if (m == (ll)n * (n - 1) / 2)
		return i_i(1, n);
	vector<int> d(n);
	for (int i = 0; i < m; i++) {
		d[a[i]]++;
		d[b[i]]++;
	}
	int _u;
	for (int u = 0; u < n; u++)
		if (d[u] == n - 1)
			_u = u;
	vector<int> _a, _b;
	for (int i = 0; i < m; i++)
		if (a[i] != _u && b[i] != _u) {
			_a.push_back(a[i] < _u ? a[i] : a[i] - 1);
			_b.push_back(b[i] < _u ? b[i] : b[i] - 1);
		}
	return f(n - 1, _a, _b);
}

int main() {
	int n, m; cin >> n >> m;
	vector<int> a(m), b(m);
	for (int i = 0; i < m; i++) {
		scanf("%d%d", &a[i], &b[i]);
		a[i]--;
		b[i]--;
	}
	i_i p = f(n, a, b);
	cout << p.first << endl;
	cout << p.second << endl;
}
accuracy: 0.175
time_ms: 80
memory_kb: 21792
final_rank: 19

code_snippet: #include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <ctime>
#include <queue>
#include <stack>
#include <algorithm>
#include <list>
#include <vector>
#include <set>
#include <map>
#include <iostream>
#include <deque>
#include <complex>
#include <string>
#include <iomanip>
#include <sstream>
#include <bitset>
#include <valarray>
#include <unordered_map>
#include <iterator>
#include <functional>
#include <cassert>
using namespace std;
typedef long long int ll;
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;

#define REP(i,x) for(int i=0;i<(int)(x);i++)
#define REPS(i,x) for(int i=1;i<=(int)(x);i++)
#define RREP(i,x) for(int i=((int)(x)-1);i>=0;i--)
#define RREPS(i,x) for(int i=((int)(x));i>0;i--)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();i++)
#define RFOR(i,c) for(__typeof((c).rbegin())i=(c).rbegin();i!=(c).rend();i++)
#define ALL(container) (container).begin(), (container).end()
#define RALL(container) (container).rbegin(), (container).rend()
#define SZ(container) ((int)container.size())
#define mp(a,b) make_pair(a, b)
#define pb push_back
#define eb emplace_back
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );

template<class T> bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T> bool chmin(T &a, const T &b) { if (a>b) { a=b; return 1; } return 0; }
template<class T> ostream& operator<<(ostream &os, const vector<T> &t) {
os<<"["; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"]"; return os;
}
template<class T> ostream& operator<<(ostream &os, const set<T> &t) {
os<<"{"; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"}"; return os;
}
template<class S, class T> ostream& operator<<(ostream &os, const pair<S,T> &t) { return os<<"("<<t.first<<","<<t.second<<")";}
template<class S, class T> pair<S,T> operator+(const pair<S,T> &s, const pair<S,T> &t){ return pair<S,T>(s.first+t.first, s.second+t.second);}
template<class S, class T> pair<S,T> operator-(const pair<S,T> &s, const pair<S,T> &t){ return pair<S,T>(s.first-t.first, s.second-t.second);}

const int INF = 1<<28;
const double EPS = 1e-8;
const int MOD = 1000000009;


int T, n, m;

int main(int argc, char *argv[]){
	ios::sync_with_stdio(false);
	cin >> n >> m;
	vector<set<int>> g(n);
	vi deg(n);
	REP(i, m){
		int u, v;
		cin >> u >> v; u--; v--;
		g[u].insert(v); g[v].insert(u);
	}
	set<pii> s;
	REP(i, n) s.insert(pii(g[i].size(), i));
	int c = 0;
	ll ans = 1;
	while(!s.empty()){
		int u = s.rbegin()->second;
		int deg = g[u].size();
		s.erase(pii(deg, u));
		if([&](){
			for(int v : g[u]) if(g[v].size() != deg) return 0;
			return 1;
		}()){
			ans = ans * (deg + 1) % MOD;
			for(int v : g[u]) s.erase(pii(deg, v));
			c ++;
		}else{
			for(int v : g[u]){
				s.erase(pii(g[v].size(), v));
				g[v].erase(u);
				s.insert(pii(g[v].size(), v));
			}
		}
	}
	cout << c << endl;
	cout << ans << endl;
	return 0;
}
accuracy: 1
time_ms: 320
memory_kb: 29704
final_rank: 10

code_snippet: #include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <ctime>
#include <queue>
#include <stack>
#include <algorithm>
#include <list>
#include <vector>
#include <set>
#include <map>
#include <iostream>
#include <deque>
#include <complex>
#include <string>
#include <iomanip>
#include <sstream>
#include <bitset>
#include <valarray>
#include <unordered_map>
#include <iterator>
#include <functional>
#include <cassert>
using namespace std;
typedef long long int ll;
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;

#define REP(i,x) for(int i=0;i<(int)(x);i++)
#define REPS(i,x) for(int i=1;i<=(int)(x);i++)
#define RREP(i,x) for(int i=((int)(x)-1);i>=0;i--)
#define RREPS(i,x) for(int i=((int)(x));i>0;i--)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();i++)
#define RFOR(i,c) for(__typeof((c).rbegin())i=(c).rbegin();i!=(c).rend();i++)
#define ALL(container) (container).begin(), (container).end()
#define RALL(container) (container).rbegin(), (container).rend()
#define SZ(container) ((int)container.size())
#define mp(a,b) make_pair(a, b)
#define pb push_back
#define eb emplace_back
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );

template<class T> bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T> bool chmin(T &a, const T &b) { if (a>b) { a=b; return 1; } return 0; }
template<class T> ostream& operator<<(ostream &os, const vector<T> &t) {
os<<"["; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"]"; return os;
}
template<class T> ostream& operator<<(ostream &os, const set<T> &t) {
os<<"{"; FOR(it,t) {if(it!=t.begin()) os<<","; os<<*it;} os<<"}"; return os;
}
template<class S, class T> ostream& operator<<(ostream &os, const pair<S,T> &t) { return os<<"("<<t.first<<","<<t.second<<")";}
template<class S, class T> pair<S,T> operator+(const pair<S,T> &s, const pair<S,T> &t){ return pair<S,T>(s.first+t.first, s.second+t.second);}
template<class S, class T> pair<S,T> operator-(const pair<S,T> &s, const pair<S,T> &t){ return pair<S,T>(s.first-t.first, s.second-t.second);}

const int INF = 1<<28;
const double EPS = 1e-8;
const int MOD = 1000000007;


int T, n, m;

int main(int argc, char *argv[]){
	ios::sync_with_stdio(false);
	cin >> n >> m;
	vector<set<int>> g(n);
	vi deg(n);
	REP(i, m){
		int u, v;
		cin >> u >> v; u--; v--;
		g[u].insert(v); g[v].insert(u);
	}
	set<pii> s;
	REP(i, n) s.insert(pii(g[i].size(), i));
	int c = 0;
	ll ans = 1;
	while(!s.empty()){
		int u = s.rbegin()->second;
		int deg = g[u].size();
		s.erase(pii(deg, u));
		if([&](){
			for(int v : g[u]) if(g[v].size() != deg) return 0;
			return 1;
		}()){
			ans = ans * (deg + 1) % MOD;
			for(int v : g[u]) s.erase(pii(deg, v));
			c ++;
		}else{
			for(int v : g[u]){
				s.erase(pii(g[v].size(), v));
				g[v].erase(u);
				s.insert(pii(g[v].size(), v));
			}
		}
	}
	cout << c << endl;
	cout << ans << endl;
	return 0;
}
accuracy: 0.175
time_ms: 20
memory_kb: 4128
final_rank: 17

code_snippet: #include <iostream>
#include <cstdio>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <cstring>
#include <functional>
#include <cmath>
#include <complex>
#include <cassert>
using namespace std;
#define rep(i,n) for(int i=0;i<(n);++i)
#define rep1(i,n) for(int i=1;i<=(n);++i)
#define all(c) (c).begin(),(c).end()
#define fs first
#define sc second
#define pb push_back
#define show(x) cout << #x << " " << x << endl
typedef long long ll;
typedef pair<int,int> P;
ll mod=1e9+9;
int N,M,deg[100001];
int ans=0;
ll num=1;
vector<int> G[100001];	//id,to
bool done[100001]={};
bool comp(const int& x,const int& y){return deg[x]>deg[y];}
void add_edge(int x,int y){
	G[x].pb(y);
	G[y].pb(x);
	deg[x]++,deg[y]++;
}
int main(){
	cin>>N>>M;
	if((ll)N*(N-1)/2==M){
		cout<<1<<endl<<N<<endl;
		return 0;
	}
	rep(i,M){
		int x,y;
		cin>>x>>y;
		add_edge(x,y);
	}
	rep1(i,N) add_edge(0,i);
	vector<int> vc;
	rep(i,N+1) vc.pb(i);
	sort(all(vc),comp);
	for(int a:vc){
		if(done[a]) continue;
		done[a]=true;
		bool cl=true;
		for(int v:G[a]){
			if(done[v]) continue;
			if(deg[v]!=deg[a]) cl=false;
			deg[v]--;
		}
		if(cl){
			int cnt=1;
			done[a]=true;
			for(int v:G[a]){
				if(done[v]) continue;
				done[v]=true;
				cnt++;
			}
			ans++;
			num=num*cnt%mod;
		}
	}
	cout<<ans<<endl<<num<<endl;
}
accuracy: 1
time_ms: 120
memory_kb: 10624
final_rank: 3

code_snippet: #include <iostream>
#include <cstdio>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <cstring>
#include <functional>
#include <cmath>
#include <complex>
#include <cassert>
using namespace std;
#define rep(i,n) for(int i=0;i<(n);++i)
#define rep1(i,n) for(int i=1;i<=(n);++i)
#define all(c) (c).begin(),(c).end()
#define fs first
#define sc second
#define pb push_back
#define show(x) cout << #x << " " << x << endl
int par[100001];
void init(int n) { rep(i,n) par[i]=i; }
int find(int x){
	if(x==par[x]) return x;
	return par[x]=find(par[x]);
}
void unite(int x,int y){
	x=find(x);
	y=find(y);
	if(x==y) return;
	par[x]=y;
}
bool same(int x,int y) { return find(x)==find(y); }

typedef long long ll;
ll mod=1e9+7;
int N,M;
int ans=0;
ll cnt=1;
set<int> G[100001];
void dfs(set<int> vc){
	ll s=vc.size();
	int u=-1;
	bool cl=true;
	for(int v:vc){
		if(G[v].size()==s-1&&u==-1) u=v;
		if(G[v].size()<s-1) cl=false;
	}
	if(cl){
		ans++;
		cnt*=s;
		cnt%=mod;
		return;
	}
	assert(u!=-1);
	for(int v:G[u]) G[v].erase(u);
	G[u].clear();
	vc.erase(u);
	init(N+1);
	for(int v:vc){
		for(int u:G[v]) unite(u,v);
	}
	map< int,set<int> > sets;
	for(int v:vc){
		sets[find(v)].insert(v);
	}
	for(auto it:sets){
		dfs(it.sc);
	}
}
int main(){
	cin>>N>>M;
	if((ll)N*(N-1)/2==M){
		cout<<1<<endl<<N<<endl;
		return 0;
	}
	rep(i,M){
		int x,y;
		cin>>x>>y;
		G[x].insert(y);
		G[y].insert(x);
	}
	rep1(i,N){
		G[0].insert(i);
		G[i].insert(0);
	}
	set<int> be;
	rep(i,N+1) be.insert(i);
	dfs(be);
	cout<<ans<<endl<<cnt<<endl;
}
accuracy: 0.175
time_ms: 50
memory_kb: 9648
final_rank: 18