#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <cstdlib>
#include <cassert>
#include <algorithm>
using namespace std;

const int MAXN = 20000 + 10;
int r;

struct Hungary {
	bool vis[MAXN];
	vector<int> G[MAXN];
	int n, col[MAXN], match[MAXN];
	void init(int n) {
		this->n = n;
		for (int i = 1; i <= n; ++ i) G[i].clear();
	}
	void addedge(int a, int b) {
		G[a].push_back(b);
		G[b].push_back(a);
	}
	bool dfs(int x) {
		vis[x] = true;
		for (int i = 0; i < (int)G[x].size(); ++ i) {
			int y = G[x][i], z = match[y];
			vis[y] = true;
			if (z < 0 || (!vis[z] && dfs(z))) {
				match[x] = y; match[y] = x;
				return true;
			}
		}
		return false;
	}
	int max_matching() {
		int ret = 0;
		memset(match, -1, sizeof(match));
		for (int i = 1; i <= n; ++ i) {
			if (match[i] < 0) {
				memset(vis, 0, sizeof(vis));
				if (dfs(i)) ++ ret;
			}
		}
		return ret;
	}
	void color() {
		for (int i = 1; i <= n; ++ i) {
			if (i <= r) col[i] = 0;
			else col[i] = 1;
		}
	}
	int solve(int arr[]) {
		for (int i = 1; i <= n; ++ i) {
			sort(G[i].begin(), G[i].end());
			G[i].erase(unique(G[i].begin(), G[i].end()), G[i].end());
		}
		max_matching();
		color();
		memset(vis, 0, sizeof(vis));
		for (int i = 1; i <= n; ++ i) {
			if (col[i] == 0 && match[i] == -1) dfs(i);
		}
		int p = 0;
		for (int i = 1; i <= n; ++ i) {
			if ((col[i] == 0 && !vis[i]) || (col[i] == 1 && vis[i])) {
				arr[p ++] = i;
			}
		}
		return p;
	}
} Task;

typedef pair<string, int> PSI;
vector<int> Belong[MAXN];
vector<PSI> chain;
vector<int> cluster[MAXN];
int ret[MAXN], m;
char st[10000];

bool check(string &s1, string &s2, int k) {
	for (int i = 0; i < k; ++ i) {
		if (s1[i] != s2[i]) return false;
	}
	return true;
}

int main() {
	freopen("heavy.in", "r", stdin);
	freopen("heavy.out", "w", stdout);
	int n, k; scanf("%d%d", &n, &k);
	chain.clear();
	for (int i = 1; i <= n; ++ i) {
		scanf("%s", st);
		chain.push_back(PSI(st, i));
		Belong[i].clear();
	}
	
	// deal with prefix
	sort(chain.begin(), chain.end());
	m = 1; cluster[m].clear();
	cluster[m].push_back(chain[0].second);
	Belong[chain[0].second].push_back(m);
	
	for (int i = 1; i < n; ++ i) {
		if (!check(chain[i].first, chain[i - 1].first, k)) ++ m, cluster[m].clear();
		cluster[m].push_back(chain[i].second);
		Belong[chain[i].second].push_back(m);
	}
	r = m;
	
	
	// deal with suffix
	for (int i = 0; i < n; ++ i) {
		reverse(chain[i].first.begin(), chain[i].first.end());
	}
	sort(chain.begin(), chain.end());
	++ m; cluster[m].clear();
	cluster[m].push_back(chain[0].second);
	Belong[chain[0].second].push_back(m);
	for (int i = 1; i < n; ++ i) {
		if (!check(chain[i].first, chain[i - 1].first, k)) ++ m, cluster[m].clear();
		cluster[m].push_back(chain[i].second);
		Belong[chain[i].second].push_back(m);
	}
	
	Task.init(m);
	for (int i = 1; i <= n; ++ i) {
		assert(Belong[i].size() == 2);
		int u = Belong[i][0], v = Belong[i][1];
		Task.addedge(u, v);
	}
	m = Task.solve(ret);
	printf("%d\n", m);
	bool vis[MAXN];
	memset(vis, 0, sizeof(vis));
	for (int i = 0; i < m; ++ i) {
		vector<int> &now = cluster[ret[i]];
		vector<int> tmp; tmp.clear();
		//printf("%d", (int)now.size());
		for (int i = 0; i < (int)now.size(); ++ i) {
			if (!vis[now[i]]) tmp.push_back(now[i]);
			vis[now[i]] = true;
			//printf(" %d", now[i]);
		}
		printf("%d", (int)tmp.size());
		for (int i = 0; i < (int)tmp.size(); ++ i) {
			printf(" %d", tmp[i]);
		}
		puts("");
	}
	fclose(stdin); fclose(stdout);
	return 0;
}
