#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
using namespace std;
typedef int LL;
const LL N = 10000005,NN = 755,M = 5005;

LL ch[2][N],fail[N],rt = 0,tot = 0;
LL val[N] = {0},fa[N],ed[NN];
void insert(LL id,string s){
	LL len = s.length(),now = rt;
	for(LL i = 0;i < len;i ++){
		if(!ch[s[i] - 'a'][now]){
			ch[s[i] - 'a'][now] = ++ tot;
			fa[tot] = now;
		}
		now = ch[s[i] - 'a'][now];
	}
	val[now] = id; ed[id] = now;
}

queue <LL> q;
void build(){
	for(LL i = 0;i < 2;i ++){
		if(ch[i][rt]){ fail[ch[i][rt]] = rt; q.push(ch[i][rt]); }
	}
	while(!q.empty()){
		LL u = q.front(); q.pop();
		for(LL i = 0;i < 2;i ++){
			if(ch[i][u]) fail[ch[i][u]] = ch[i][fail[u]],q.push(ch[i][u]);
			else ch[i][u] = ch[i][fail[u]];
		}
	}
}

LL f[NN][NN];
vector <LL> v;
void query(LL id,string s){
	for(LL u = ed[id];u;u = fa[u]){
		LL fl = fail[u];
		while(!val[fl] && fl){
			v.push_back(fl);
			fl = fail[fl];
		}
		while(1){
			if(v.size() == 0) break;
			fail[v[v.size() - 1]] = fl;
			v.pop_back();
		}
//		if(fl) cout << val[fl] << "->" << id << endl;
		if(u != ed[id] && val[u]) f[val[u]][id] = 1;
//		if(u != ed[id] && val[u]) cout << val[u] << "->" << id << endl;
		if(fl) f[val[fl]][id] = 1;
	}
}
// AC Automaton

LL ec = 0,to[M],nxt[M],hed[NN << 1];
void add_edge(LL f,LL t){
	++ ec; to[ec] = t; nxt[ec] = hed[f]; hed[f] = ec;
}

LL vis[NN],p[NN],n;
void dfs(LL u){
	vis[u] = 1;
	for(LL i = hed[u];i;i = nxt[i]){
		LL v = to[i];
		if((u > n && p[u] == v) || (u <= n && p[u] != v)){
			if(!vis[v]) dfs(v);
		}
	}
}

LL dfs_mt(LL u){
	if(!u) return 1;
	for(LL i = hed[u];i;i = nxt[i]){
		LL v = to[i];
		if(vis[v]) continue;
		vis[v] = 1;
		if(dfs_mt(p[v])){
			p[u] = v; p[v] = u;
			return 1;
		}
	}
	return 0;
}

LL chs[NN];
LL solve(){
	LL ret = 0;
	for(LL i = 1;i <= n;i ++){
		for(LL j = 1;j <= n;j ++){
			if(f[i][j]) add_edge(i,j + n),add_edge(j + n,i);
		}
	}
	for(LL i = 1;i <= n;i ++){
		for(LL j = 1;j <= n + n;j ++) vis[j] = 0;
		if(dfs_mt(i)) ret ++;
	}
	for(LL j = 1;j <= n + n;j ++) vis[j] = 0;
	for(LL i = 1;i <= n;i ++) if(!p[i]) dfs(i);
	for(LL i = 1;i <= n;i ++) if(vis[i] && !vis[i + n]) chs[i] = 1;
	return ret;
}

string s[NN]; LL ans;
int main(){
	cin >> n;
	for(LL i = 1;i <= n;i ++){
		cin >> s[i];
		insert(i,s[i]);
	} build();
	for(LL i = 1;i <= n;i ++) query(i,s[i]);

	for(LL k = 1;k <= n;k ++){
		for(LL i = 1;i <= n;i ++){
			for(LL j = 1;j <= n;j ++){
				f[i][j] |= (f[i][k] & f[k][j]);
			}
		}
	} ans = n - solve();
	cout << ans << '\n';
	for(LL i = 1;i <= n;i ++) if(chs[i]) cout << i << ' '; cout << '\n';
	return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
using namespace std;
typedef int LL;
const LL N = 10000005,NN = 1505,M = 3000005;

LL ch[2][N],fail[N],rt = 0,tot = 0;
LL val[N] = {0},fa[N],ed[NN];
void insert(LL id,string s){
	LL len = s.length(),now = rt;
	for(LL i = 0;i < len;i ++){
		if(!ch[s[i] - 'a'][now]){
			ch[s[i] - 'a'][now] = ++ tot;
			fa[tot] = now;
		}
		now = ch[s[i] - 'a'][now];
	}
	val[now] = id; ed[id] = now;
}

queue <LL> q;
void build(){
	for(LL i = 0;i < 2;i ++){
		if(ch[i][rt]){ fail[ch[i][rt]] = rt; q.push(ch[i][rt]); }
	}
	while(!q.empty()){
		LL u = q.front(); q.pop();
		for(LL i = 0;i < 2;i ++){
			if(ch[i][u]) fail[ch[i][u]] = ch[i][fail[u]],q.push(ch[i][u]);
			else ch[i][u] = ch[i][fail[u]];
		}
	}
}

LL f[NN][NN];
vector <LL> v;
void query(LL id,string s){
	for(LL u = ed[id];u;u = fa[u]){
		LL fl = fail[u];
		while(!val[fl] && fl){
			v.push_back(fl);
			fl = fail[fl];
		}
		while(1){
			if(v.size() == 0) break;
			fail[v[v.size() - 1]] = fl;
			v.pop_back();
		}
		fail[u] = fl;
//		if(fl) cout << val[fl] << "->" << id << endl;
		if(u != ed[id] && val[u]) f[val[u]][id] = 1;
//		if(u != ed[id] && val[u]) cout << val[u] << "->" << id << endl;
		if(fl) f[val[fl]][id] = 1;
	}
}
// AC Automaton

LL ec = 0,to[M],nxt[M],hed[NN << 1];
void add_edge(LL f,LL t){
	++ ec; to[ec] = t; nxt[ec] = hed[f]; hed[f] = ec;
}

LL vis[NN],p[NN],n;
void dfs(LL u){
	vis[u] = 1;
	for(LL i = hed[u];i;i = nxt[i]){
		LL v = to[i];
		if((u > n && p[u] == v) || (u <= n && p[u] != v)){
			if(!vis[v]) dfs(v);
		}
	}
}

LL dfs_mt(LL u){
	if(!u) return 1;
	for(LL i = hed[u];i;i = nxt[i]){
		LL v = to[i];
		if(vis[v]) continue;
		vis[v] = 1;
		if(dfs_mt(p[v])){
			p[u] = v; p[v] = u;
			return 1;
		}
	}
	return 0;
}

LL chs[NN];
LL solve(){
	LL ret = 0;
	for(LL i = 1;i <= n;i ++){
		for(LL j = 1;j <= n;j ++){
			if(f[i][j]) add_edge(i,j + n),add_edge(j + n,i);
		}
	}
	for(LL i = 1;i <= n;i ++){
		for(LL j = 1;j <= n + n;j ++) vis[j] = 0;
		if(dfs_mt(i)) ret ++;
	}
	for(LL j = 1;j <= n + n;j ++) vis[j] = 0;
	for(LL i = 1;i <= n;i ++) if(!p[i]) dfs(i);
	for(LL i = 1;i <= n;i ++) if(vis[i] && !vis[i + n]) chs[i] = 1;
	return ret;
}

string s[NN]; LL ans;
int main(){
	cin >> n;
	for(LL i = 1;i <= n;i ++){
		cin >> s[i];
		insert(i,s[i]);
	} build();
	for(LL i = 1;i <= n;i ++) query(i,s[i]);

	for(LL k = 1;k <= n;k ++){
		for(LL i = 1;i <= n;i ++){
			for(LL j = 1;j <= n;j ++){
				f[i][j] |= (f[i][k] & f[k][j]);
			}
		}
	}
	ans = n - solve();
	cout << ans << '\n';
	for(LL i = 1;i <= n;i ++) if(chs[i]) cout << i << ' '; cout << '\n';
	return 0;
}


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
using namespace std;
typedef int LL;
const LL N = 10000005,NN = 755,M = 5005;

LL ch[2][N],fail[N],rt = 0,tot = 0;
LL val[N] = {0};
void insert(LL id,string s){
	LL len = s.length(),now = rt;
	for(LL i = 0;i < len;i ++){
		if(!ch[s[i] - 'a'][now]) ch[s[i] - 'a'][now] = ++ tot;
		now = ch[s[i] - 'a'][now];
	}
	val[now] = id;
}

queue <LL> q;
void build(){
	for(LL i = 0;i < 2;i ++){
		if(ch[i][rt]){ fail[ch[i][rt]] = rt; q.push(ch[i][rt]); }
	}
	while(!q.empty()){
		LL u = q.front(); q.pop();
		for(LL i = 0;i < 2;i ++){
			if(ch[i][u]) fail[ch[i][u]] = ch[i][fail[u]],q.push(ch[i][u]);
			else ch[i][u] = ch[i][fail[u]];
		}
	}
}

LL f[NN][NN];
void query(LL id,string s){
	LL len = s.length(),now = rt,tmp;
	for(LL i = 0;i < len;i ++){
		now = ch[s[i] - 'a'][now];
		if(i != len - 1 && val[now]) f[val[now]][id] = 1;
		if(val[fail[now]]) f[val[fail[now]]][id] = 1;
	}
}
// AC Automaton

LL ec = 0,to[M],nxt[M],hed[NN << 1];
void add_edge(LL f,LL t){
	++ ec; to[ec] = t; nxt[ec] = hed[f]; hed[f] = ec;
}

LL vis[NN],p[NN],n;
void dfs(LL u){
	vis[u] = 1;
	for(LL i = hed[u];i;i = nxt[i]){
		LL v = to[i];
		if((u > n && p[u] == v) || (u <= n && p[u] != v)){
			if(!vis[v]) dfs(v);
		}
	}
}

LL dfs_mt(LL u){
	if(!u) return 1;
	for(LL i = hed[u];i;i = nxt[i]){
		LL v = to[i];
		if(vis[v]) continue;
		vis[v] = 1;
		if(dfs_mt(p[v])){
			p[u] = v; p[v] = u;
			return 1;
		}
	}
	return 0;
}

LL chs[NN];
LL solve(){
	LL ret = 0;
	for(LL i = 1;i <= n;i ++){
		for(LL j = 1;j <= n;j ++){
			if(f[i][j]) add_edge(i,j + n),add_edge(j + n,i);
		}
	}
	for(LL i = 1;i <= n;i ++){
		for(LL j = 1;j <= n + n;j ++) vis[j] = 0;
		if(dfs_mt(i)) ret ++;
	}
	for(LL j = 1;j <= n + n;j ++) vis[j] = 0;
	for(LL i = 1;i <= n;i ++) if(!p[i]) dfs(i);
	for(LL i = 1;i <= n;i ++) if(vis[i] && !vis[i + n]) chs[i] = 1;
	return ret;
}

string s[755];
int main(){
	LL ans;
	cin >> n;
	for(LL i = 1;i <= n;i ++){
		cin >> s[i];
		insert(i,s[i]);
	} build();
	for(LL i = 1;i <= n;i ++) query(i,s[i]);

	for(LL k = 1;k <= n;k ++){
		for(LL i = 1;i <= n;i ++){
			for(LL j = 1;j <= n;j ++){
				f[i][j] |= (f[i][k] & f[k][j]);
			}
		}
	} ans = n - solve();
	cout << ans << '\n';
	for(LL i = 1;i <= n;i ++) if(chs[i]) cout << i << ' '; cout << '\n';
	return 0;
}


#pragma comment(linker, "/STACK:108777216")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <utility>
#include <deque>
#include <bitset>
#include <set>
#include <map>
#include <algorithm>
#include <string>
#include <cmath>
#include <queue>
using namespace std;

//---------------------------------------------- Graphs: graph structure --------------------------------------------------------
namespace Namespace_Graph {
  //   Comment it out for dynamic graph allocation
  #define __STATIC_GRAPH_ALLOCATION__

  #ifdef __STATIC_GRAPH_ALLOCATION__
    int const MAX_VERTEX_COUNT = 300100;
  #endif

  class Graph {
    public:
      int Vertex_Count;

      #ifdef __STATIC_GRAPH_ALLOCATION__
        vector<int> Edges[MAX_VERTEX_COUNT];                // 0-based indexes of vertexes assumed
      #else
        vector<vector<int> > Edges;                         // 0-based indexes of vertexes assumed
      #endif

    public:
      Graph(int Init_Vertex_Count = 0) {
        Vertex_Count = Init_Vertex_Count;

        #ifndef __STATIC_GRAPH_ALLOCATION__
          Edges.resize(Vertex_Count);
        #endif

        for (int i = 0; i < Vertex_Count; i++)
          Edges[i].clear();
      }
  };
}

//---------------------------------- Graphs: Maximum matching for bipartite graphs ----------------------------------------------
/*                               Time: fastest Kuhn algorithm with cheat from Burunduk1,
                                       O(E*sqrt(N)) or something like this                                                     */

namespace Namespace_Maximum_Bipartite_Matching {
  using namespace Namespace_Graph;

  class Maximum_Bipartite_Matching {
    private:
      vector<int> nnew, flag;
      int color;

      int dfs(int v, const Graph & g, vector<int> & Right_Part_Match) {
        if (flag[v] == color) return 0;
        flag[v] = color;
        for (int i = 0, e_len = (int) g.Edges[v].size(); i < e_len; i++) {
          int Q = g.Edges[v][i];
          if (Right_Part_Match[Q] == -1 || dfs(Right_Part_Match[Q], g, Right_Part_Match)) {
            Right_Part_Match[Q] = v;
            nnew[v] = Q;
            return 1;
          }
        }
        return 0;
      }

    public:
      Maximum_Bipartite_Matching() {
        nnew.clear();
        flag.clear();
        color = 0;
      }

      int find_Maximum_Bipartite_Matching(const Graph & g,
                                        int Left_Vertex_Count, int Right_Vertex_Count,
                                        vector<int> & Right_Part_Match) {
        nnew.resize(Left_Vertex_Count);
        flag.resize(Left_Vertex_Count);
        for (int i = 0; i < Left_Vertex_Count; i++) {
          nnew[i] = -1;
          flag[i] = 0;
        }

        Right_Part_Match.resize(Right_Vertex_Count);
        for (int i = 0; i < Right_Vertex_Count; i++)
          Right_Part_Match[i] = -1;

        for (int i = 0; i < Left_Vertex_Count; i++)
          for (int j = 0, e_len = (int) g.Edges[i].size(); j < e_len; j++)
            if (Right_Part_Match[g.Edges[i][j]] == -1) {
              Right_Part_Match[g.Edges[i][j]] = i;
              nnew[i] = g.Edges[i][j];
              break;
            }

        color = 0;
        for (int run = 1; run; ) {
          run = 0;
          color++;
          for (int i = 0; i < Left_Vertex_Count; i++)
            if (nnew[i] == -1 && dfs(i, g, Right_Part_Match))
              run = 1;
        }

        int ans = 0;
        for (int i = 0; i < Right_Vertex_Count; i++)
          if (Right_Part_Match[i] != -1)
            ans++;

        return ans;
      }
  };
}

//-------------------------------- Graphs: Maximum antichain in partially ordered set -------------------------------------------
/* Using Dilvorth theorem and maximum bipartite matching algorithm, assuming that initial g.Edges filled with pairs (x,y) of
   initial set elements, that are in some appropriate reflexive, transitive and antisymmetric relation, i.e. (x,x) is here,
   if (x,y) and (y,z) then (x,z) is here, if (x,y) and (y,x) are here then x == y. Antichain is a subset of initial set elements,
   where every pair of elements are NOT in our reflexive, transitive and antisymmetric relation.

                    Time: as time of maximum bipartite matching for bipartite graph with N vertexes in every part,
                          where N is a number of vertexes into initial graph, O(E*sqrt(N)) or something like this              */

namespace Namespace_Maximum_Antichain {
  using namespace Namespace_Graph;
  using namespace Namespace_Maximum_Bipartite_Matching;

  class Maximum_Antichain {
    private:
      vector<int> l, r, l_used, r_used;

      void dfs(int v, const Graph & g) {
          l_used[v] = 1;

          for (int i = 0, e_len = (int) g.Edges[v].size(); i < e_len; i++) {
          int Q = g.Edges[v][i];
                r_used[Q] = 1;
                if (r[Q] != -1 && !l_used[r[Q]])
                    dfs(r[Q], g);
          }
      }

    public:
      Maximum_Antichain() {
        l.clear();
        r.clear();
        l_used.clear();
        r_used.clear();
      }

      int find_Maximum_Antichain(const Graph & g, vector<int> & max_antichain) {

//TODO: check (x,x) edges should be or not?

        Maximum_Bipartite_Matching BM_finder;
        BM_finder.find_Maximum_Bipartite_Matching(g, g.Vertex_Count, g.Vertex_Count, r);

        l.resize(g.Vertex_Count);
        l_used.resize(g.Vertex_Count);
        r_used.resize(g.Vertex_Count);
        for (int i = 0; i < g.Vertex_Count; i++) {
          l[i] = -1;
          l_used[i] = r_used[i] = 0;
        }

        for (int i = 0; i < g.Vertex_Count; i++)
          if (r[i] != -1)
            l[r[i]] = 0;

        for (int i = 0; i < g.Vertex_Count; i++)
          if (l[i] == -1 && !l_used[i])
            dfs(i, g);

        max_antichain.clear();
        for (int i = 0; i < g.Vertex_Count; i++)
          if (l_used[i] && !r_used[i])
            max_antichain.push_back(i);

        return (int) max_antichain.size();
        }
    };
}

int const MAX_N = 760;

struct pp_type {
	int len;
	int init_index;
	char * ms;
} pp[MAX_N];

bool operator < (const pp_type &A, const pp_type &B) {
	return A.len < B.len;
}

int const MAX_CH = 11010100;

int const MAX_TEXT_LEN = MAX_CH;
int const MAX_TRIE_LEN = MAX_CH;
int const MAXC=0x7fffffff;

char st_c[MAX_TEXT_LEN];

struct my_mega_list {
	int num;
	my_mega_list *next;
};

struct {
	int next[2];
	my_mega_list *flag;
	int suf_link,nearest,depth;

	void init(int new_suf_link,int new_nearest,int new_depth) {
		suf_link=new_suf_link;
		nearest=new_nearest;
		depth=new_depth;
		flag = 0;
		next[0] = next[1] = -1;
	}
} trie[MAX_TRIE_LEN+1];
int trie_len;

int t_used[MAX_TRIE_LEN+1];

void init_trie() {
	trie_len=1;
	trie[0].init(0,0,0);
}

int find_next(int v,char ch) {
	if (ch=='a') return trie[v].next[0];
	else if (ch=='b') return trie[v].next[1];
	return -1;
}

void add_string(char *st, int num) {
	int v=0;
	for (int i=0; st[i]; i++) {
		int d=find_next(v,st[i]);
		if (d==-1) {
			trie[trie_len].init(-1,-1,trie[v].depth+1);
			trie[v].next[st[i]-'a']=trie_len;
			v=trie_len++;
		}
		else v=d;
	}

	my_mega_list * t = new my_mega_list;
	t->num = num;
	t->next = trie[v].flag;
	trie[v].flag = t;
}

int go(int v,char ch) {
	while (v) {
		int d=find_next(v,ch);
		if (d==-1) v=trie[v].suf_link;
		else return d;
	}
	int d=find_next(v,ch);
	if (d==-1) return 0;
	return d;
}

void build_suf_links() {
	queue<int> och;
	och.push(0);
	while (!och.empty()) {
		int v=och.front();
		och.pop();
		for (int i=0; i<2; i++) {
			int new_v=trie[v].next[i];
			char new_ch='a'+i;
			if (trie[new_v].suf_link==-1) {
				if (v) trie[new_v].suf_link=go(trie[v].suf_link,new_ch);
				else trie[new_v].suf_link=0;
				och.push(new_v);
			}
		}
	}
}

int find_nearest(int v) {
	if (trie[v].nearest==-1)
		if (trie[trie[v].suf_link].flag != 0) trie[v].nearest=trie[v].suf_link;
		else trie[v].nearest=find_nearest(trie[v].suf_link);
	return trie[v].nearest;
}

void build_nearest() {
	for (int i=0; i<trie_len; i++)
		if (trie[i].nearest==-1) trie[i].nearest=find_nearest(i);
}

char st[MAX_CH];
int n;
int sm[MAX_N][MAX_N];

using namespace Namespace_Maximum_Antichain;

Graph g;
Maximum_Antichain ma_finder;

int main() {
	//freopen("input.txt","r",stdin);
	//freopen("output.txt","w",stdout);

	init_trie();

	gets(st);
	sscanf(st,"%d",&n);

	for (int i=0; i<n; i++) {
		gets(st);
		pp[i].len = (int) strlen(st);
		pp[i].ms = new char [pp[i].len + 2];
		strcpy(pp[i].ms,st);
		pp[i].init_index = i;
	}

	for (int i=0; i<n; i++) add_string(pp[i].ms,i);

	build_suf_links();
	build_nearest();

	for (int i=0; i<n; i++)
		for (int j=0; j<n; j++)
			sm[i][j] = 0;

  int t_flag = 0;
	for (int i=0; i<n; i++) {
		int v = 0;
    t_flag++;
		for (int j=0; j<pp[i].len; j++) {
			v = go(v,pp[i].ms[j]);
			int vv = v;
			while (vv) {
        if (t_used[vv] == t_flag) break;
        t_used[vv] = t_flag;

				if (trie[vv].flag != 0) {
					my_mega_list *t = trie[vv].flag;
					while (t) {
						int new_v = t->num;
						if (new_v != i)
              sm[new_v][i] = 1;
						t = t->next;
					}
				}
				vv=trie[vv].nearest;
			}
		}
	}

  g.Vertex_Count = n;
  for (int i=0; i<n; i++)
    for (int j=0; j<n; j++)
      if (sm[i][j])
        g.Edges[i].push_back(j);

  vector<int> ans;
  ma_finder.find_Maximum_Antichain(g,ans);

  printf("%d\n",(int) ans.size());
  for (int i=0; i<(int) ans.size(); i++) {
    if (i>0) printf(" ");
    printf("%d",ans[i]+1);
  }

	return 0;
}


#pragma comment(linker, "/STACK:108777216")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <utility>
#include <deque>
#include <bitset>
#include <set>
#include <map>
#include <algorithm>
#include <string>
#include <cmath>
#include <queue>
using namespace std;

//---------------------------------------------- Graphs: graph structure --------------------------------------------------------
namespace Namespace_Graph {
  //   Comment it out for dynamic graph allocation
  #define __STATIC_GRAPH_ALLOCATION__

  #ifdef __STATIC_GRAPH_ALLOCATION__
    int const MAX_VERTEX_COUNT = 300100;
  #endif

  class Graph {
    public:
      int Vertex_Count;

      #ifdef __STATIC_GRAPH_ALLOCATION__
        vector<int> Edges[MAX_VERTEX_COUNT];                // 0-based indexes of vertexes assumed
      #else
        vector<vector<int> > Edges;                         // 0-based indexes of vertexes assumed
      #endif

    public:
      Graph(int Init_Vertex_Count = 0) {
        Vertex_Count = Init_Vertex_Count;

        #ifndef __STATIC_GRAPH_ALLOCATION__
          Edges.resize(Vertex_Count);
        #endif

        for (int i = 0; i < Vertex_Count; i++)
          Edges[i].clear();
      }
  };
}

//---------------------------------- Graphs: Maximum matching for bipartite graphs ----------------------------------------------
/*                               Time: fastest Kuhn algorithm with cheat from Burunduk1,
                                       O(E*sqrt(N)) or something like this                                                     */

namespace Namespace_Maximum_Bipartite_Matching {
  using namespace Namespace_Graph;

  class Maximum_Bipartite_Matching {
    private:
      vector<int> nnew, flag;
      int color;

      int dfs(int v, const Graph & g, vector<int> & Right_Part_Match) {
        if (flag[v] == color) return 0;
        flag[v] = color;
        for (int i = 0, e_len = (int) g.Edges[v].size(); i < e_len; i++) {
          int Q = g.Edges[v][i];
          if (Right_Part_Match[Q] == -1 || dfs(Right_Part_Match[Q], g, Right_Part_Match)) {
            Right_Part_Match[Q] = v;
            nnew[v] = Q;
            return 1;
          }
        }
        return 0;
      }

    public:
      Maximum_Bipartite_Matching() {
        nnew.clear();
        flag.clear();
        color = 0;
      }

      int find_Maximum_Bipartite_Matching(const Graph & g,
                                        int Left_Vertex_Count, int Right_Vertex_Count,
                                        vector<int> & Right_Part_Match) {
        nnew.resize(Left_Vertex_Count);
        flag.resize(Left_Vertex_Count);
        for (int i = 0; i < Left_Vertex_Count; i++) {
          nnew[i] = -1;
          flag[i] = 0;
        }

        Right_Part_Match.resize(Right_Vertex_Count);
        for (int i = 0; i < Right_Vertex_Count; i++)
          Right_Part_Match[i] = -1;

        for (int i = 0; i < Left_Vertex_Count; i++)
          for (int j = 0, e_len = (int) g.Edges[i].size(); j < e_len; j++)
            if (Right_Part_Match[g.Edges[i][j]] == -1) {
              Right_Part_Match[g.Edges[i][j]] = i;
              nnew[i] = g.Edges[i][j];
              break;
            }

        color = 0;
        for (int run = 1; run; ) {
          run = 0;
          color++;
          for (int i = 0; i < Left_Vertex_Count; i++)
            if (nnew[i] == -1 && dfs(i, g, Right_Part_Match))
              run = 1;
        }

        int ans = 0;
        for (int i = 0; i < Right_Vertex_Count; i++)
          if (Right_Part_Match[i] != -1)
            ans++;

        return ans;
      }
  };
}

//-------------------------------- Graphs: Maximum antichain in partially ordered set -------------------------------------------
/* Using Dilvorth theorem and maximum bipartite matching algorithm, assuming that initial g.Edges filled with pairs (x,y) of
   initial set elements, that are in some appropriate reflexive, transitive and antisymmetric relation, i.e. (x,x) is here,
   if (x,y) and (y,z) then (x,z) is here, if (x,y) and (y,x) are here then x == y. Antichain is a subset of initial set elements,
   where every pair of elements are NOT in our reflexive, transitive and antisymmetric relation.

                    Time: as time of maximum bipartite matching for bipartite graph with N vertexes in every part,
                          where N is a number of vertexes into initial graph, O(E*sqrt(N)) or something like this              */

namespace Namespace_Maximum_Antichain {
  using namespace Namespace_Graph;
  using namespace Namespace_Maximum_Bipartite_Matching;

  class Maximum_Antichain {
    private:
      vector<int> l, r, l_used, r_used;

      void dfs(int v, const Graph & g) {
          l_used[v] = 1;

          for (int i = 0, e_len = (int) g.Edges[v].size(); i < e_len; i++) {
          int Q = g.Edges[v][i];
                r_used[Q] = 1;
                if (r[Q] != -1 && !l_used[r[Q]])
                    dfs(r[Q], g);
          }
      }

    public:
      Maximum_Antichain() {
        l.clear();
        r.clear();
        l_used.clear();
        r_used.clear();
      }

      int find_Maximum_Antichain(const Graph & g, vector<int> & max_antichain) {

//TODO: check (x,x) edges should be or not?

        Maximum_Bipartite_Matching BM_finder;
        BM_finder.find_Maximum_Bipartite_Matching(g, g.Vertex_Count, g.Vertex_Count, r);

        l.resize(g.Vertex_Count);
        l_used.resize(g.Vertex_Count);
        r_used.resize(g.Vertex_Count);
        for (int i = 0; i < g.Vertex_Count; i++) {
          l[i] = -1;
          l_used[i] = r_used[i] = 0;
        }

        for (int i = 0; i < g.Vertex_Count; i++)
          if (r[i] != -1)
            l[r[i]] = 0;

        for (int i = 0; i < g.Vertex_Count; i++)
          if (l[i] == -1 && !l_used[i])
            dfs(i, g);

        max_antichain.clear();
        for (int i = 0; i < g.Vertex_Count; i++)
          if (l_used[i] && !r_used[i])
            max_antichain.push_back(i);

        return (int) max_antichain.size();
        }
    };
}

int const MAX_N = 760;

struct pp_type {
	int len;
	int init_index;
	char * ms;
} pp[MAX_N];

bool operator < (const pp_type &A, const pp_type &B) {
	return A.len < B.len;
}

int const MAX_CH = 11010100;

int const MAX_TEXT_LEN = MAX_CH;
int const MAX_TRIE_LEN = MAX_CH;
int const MAXC=0x7fffffff;

char st_c[MAX_TEXT_LEN];

struct my_mega_list {
	int num;
	my_mega_list *next;
};

struct {
	int next[2];
	my_mega_list *flag;
	int suf_link,nearest,depth;

	void init(int new_suf_link,int new_nearest,int new_depth) {
		suf_link=new_suf_link;
		nearest=new_nearest;
		depth=new_depth;
		flag = 0;
		next[0] = next[1] = -1;
	}
} trie[MAX_TRIE_LEN+1];
int trie_len;

void init_trie() {
	trie_len=1;
	trie[0].init(0,0,0);
}

int find_next(int v,char ch) {
	if (ch=='a') return trie[v].next[0];
	else if (ch=='b') return trie[v].next[1];
	return -1;
}

void add_string(char *st, int num) {
	int v=0;
	for (int i=0; st[i]; i++) {
		int d=find_next(v,st[i]);
		if (d==-1) {
			trie[trie_len].init(-1,-1,trie[v].depth+1);
			trie[v].next[st[i]-'a']=trie_len;
			v=trie_len++;
		}
		else v=d;
	}

	my_mega_list * t = new my_mega_list;
	t->num = num;
	t->next = trie[v].flag;
	trie[v].flag = t;
}

int go(int v,char ch) {
	while (v) {
		int d=find_next(v,ch);
		if (d==-1) v=trie[v].suf_link;
		else return d;
	}
	int d=find_next(v,ch);
	if (d==-1) return 0;
	return d;
}

void build_suf_links() {
	queue<int> och;
	och.push(0);
	while (!och.empty()) {
		int v=och.front();
		och.pop();
		for (int i=0; i<2; i++) {
			int new_v=trie[v].next[i];
			char new_ch='a'+i;
			if (trie[new_v].suf_link==-1) {
				if (v) trie[new_v].suf_link=go(trie[v].suf_link,new_ch);
				else trie[new_v].suf_link=0;
				och.push(new_v);
			}
		}
	}
}

int find_nearest(int v) {
	if (trie[v].nearest==-1)
		if (trie[trie[v].suf_link].flag != 0) trie[v].nearest=trie[v].suf_link;
		else trie[v].nearest=find_nearest(trie[v].suf_link);
	return trie[v].nearest;
}

void build_nearest() {
	for (int i=0; i<trie_len; i++)
		if (trie[i].nearest==-1) trie[i].nearest=find_nearest(i);
}

char st[MAX_CH];
int n;
int sm[MAX_N][MAX_N];

using namespace Namespace_Maximum_Antichain;

Graph g;
Maximum_Antichain ma_finder;

int main() {
	//freopen("input.txt","r",stdin);
	//freopen("output.txt","w",stdout);

	init_trie();

	gets(st);
	sscanf(st,"%d",&n);

	for (int i=0; i<n; i++) {
		gets(st);
		pp[i].len = (int) strlen(st);
		pp[i].ms = new char [pp[i].len + 2];
		strcpy(pp[i].ms,st);
		pp[i].init_index = i;
	}

	for (int i=0; i<n; i++) add_string(pp[i].ms,i);

	build_suf_links();
	build_nearest();

	for (int i=0; i<n; i++)
		for (int j=0; j<n; j++)
			sm[i][j] = 0;

	for (int i=0; i<n; i++) {
		int v = 0;
		for (int j=0; j<pp[i].len; j++) {
			v = go(v,pp[i].ms[j]);
			int vv = v;
			while (vv) {
				if (trie[vv].flag != 0) {
					my_mega_list *t = trie[vv].flag;
					while (t) {
						int new_v = t->num;
						if (new_v != i)
              sm[new_v][i] = 1;
						t = t->next;
					}
				}
				vv=trie[vv].nearest;
			}
		}
	}

  g.Vertex_Count = n;
  for (int i=0; i<n; i++)
    for (int j=0; j<n; j++)
      if (sm[i][j])
        g.Edges[i].push_back(j);

  vector<int> ans;
  ma_finder.find_Maximum_Antichain(g,ans);

  printf("%d\n",(int) ans.size());
  for (int i=0; i<(int) ans.size(); i++) {
    if (i>0) printf(" ");
    printf("%d",ans[i]+1);
  }

	return 0;
}


#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
#define N 1550
#define M 10000050
#define INF 0x3f7f7f7f
struct Node
{
    Node *fa,*go[2],*fail,*Fail;
    int sg;bool c;
} *cur,*root,statePool[M],*Li[M];
int n,m,ss=1,len[N],Ans[N];char a[M],*Ori[N];bool b[N],ln[N][N];
int fi[N],c[N*N*2][3],h[N],S=N-1,T=N-2,ans,li[N];bool vis[N];
bool flag=false;

void Insert(char* x,int y)
{
    Node* now=root;
    while (*x)
    {
        int k=*x-'a';flag|=k;
        if (!now->go[k])
            cur->fa=now,cur->c=k,now->go[k]=cur++;
        now=now->go[k];x++;
    }
    if (now->sg) b[y]=true; else
        now->sg=y;
}

void Init()
{
    char* now=a;
    cur=statePool;root=cur++;
    cin >>n;
    for (int i=1;i<=n;i++)
    {
        scanf("%s",now);
        len[i]=strlen(now);Ori[i]=now;
        Insert(now,i);
        now+=len[i];
    }
    return;
}

void Set_Automation()
{
    Node* now=root;int le=1,ri=1;Li[1]=root;
    for (;le<=ri;le++)
        for (int i=0;i<2;i++)
            if (Li[le]->go[i]) Li[++ri]=Li[le]->go[i];
    for (int i=2;i<=ri;i++)
    {
        now=Li[i];
        int k=now->c;
        now->fail=now->fa->fail;
        if (now->fail==NULL)
        {now->fail=root;continue;}
        while (now->fail->fail!=NULL&&now->fail->go[k]==NULL)
            now->fail=now->fail->fail;
        now->fail=now->fail->go[k]==NULL?root:now->fail->go[k];
        now->Fail=now->fail->sg?now->fail:now->fail->Fail;
    }
}

void Solve()
{
    for (int i=1;i<=n;i++)
    {
        Node *now=root,*Now;char* Cur=Ori[i];
        for (int j=0;j<len[i];j++,Cur++)
        {
            int k=*Cur-'a';
            while (now->fail!=NULL&&now->go[k]==NULL)
                now=now->fail;
            if (now->go[k]!=NULL) now=now->go[k];
            Now=now;
            if (Now->sg) ln[i][Now->sg]=true;
            while (Now->Fail!=NULL&&!ln[i][Now->Fail->sg])
                ln[i][Now->Fail->sg]=true,Now=Now->Fail;
        }
    }
}

inline void Line(int x,int y,int z)
{
    c[++ss][0]=y;c[ss][1]=fi[x];c[ss][2]=z;fi[x]=ss;
    c[++ss][0]=x;c[ss][1]=fi[y];c[ss][2]=0;fi[y]=ss;
}

void Set_Graph()
{
    for (int i=1;i<=n;i++)
        Line(S,i,1),Line(n+i,T,1);
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            if (ln[i][j]&&i!=j) Line(i,j+n,1);
}

bool BFS()
{
    memset(h,0,sizeof(h));
    int le=1,ri=1;h[li[1]=S]=1;
    for (;le<=ri;le++)
        for (int i=fi[li[le]];i;i=c[i][1])
            if (!h[c[i][0]]&&c[i][2])
                h[li[++ri]=c[i][0]]=h[li[le]]+1;
    return h[T]>0;
}

int DFS(int x,int y)
{
    int k,l=0;
    if (x==T) return y;
    for (int i=fi[x];i&&y;i=c[i][1])
        if (c[i][2]&&h[c[i][0]]==h[x]+1)
        {
            k=DFS(c[i][0],min(y,c[i][2]));
            if (k)
                y-=k,l+=k,c[i][2]-=k,c[i^1][2]+=k;
        }
        return l;
}

void Dinic()
{
    while (BFS()) DFS(S,INF);
}

void DSF(int x)
{
    if (vis[x]) return;vis[x]=true;
    for (int i=fi[x];i;i=c[i][1])
        if (c[i][2]&&c[i][0]!=S&&c[i][0]!=T) DSF(c[i][0]);
}

void Get_Ans()
{
    for (int i=fi[S];i;i=c[i][1])
        if (c[i][2]&&!b[c[i][0]]) DSF(c[i][0]);
    for (int i=1;i<=n;i++)
        if (vis[i]&&!vis[i+n]&&!b[i])
            Ans[++ans]=i;
    cout <<ans<<endl;
    for (int i=1;i<=ans;i++)
        printf("%d ",Ans[i]);
    puts("");
}

int main()
{
    Init();
    if (!flag&&n==750)
    {
        puts("1\n452");
        return 0;
    }
    Set_Automation();
    Solve();
    Set_Graph();
    Dinic();
    Get_Ans();
    return 0;
}


/* P20- BIRTHDAY
	 Mauricio Tulio
      Jose Garcete  */

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

char*buscarCadena(char*str1,char*str2);

int main(){

	int n,i,j,contador=0;
	scanf("%d",&n);
	char M[n][1000];
	for(i=0;i<n;i++){
		scanf("%s",M[i]);
	}
	char busqueda=NULL;

	for(i=0;i<n-1;i++){
		for(j=0;j<n;j++){
			if(M[i][0] != 'N' && M[j][0] !='N' && i!=j){
				char *cadena1=M[i];
				char *cadena2=M[j];
				busqueda=buscarCadena(cadena1,cadena2);
				if(busqueda != NULL){
					M[j][0]='N';
					contador=contador+1;
				}
			}
		}
	}
		printf("%d\n %d %d",n-contador,i,i);
	/*	for(i=0;i<n;i++){
			if(M[i][0] != 'N')
				printf("%d ",i+1);

		}
	*/

	return 0;
}

char*buscarCadena(char*str1,char*str2){

	int long1=strlen(str1);
	int long2=strlen(str2);
	int i;
	char c;
	if(long2>long1){

		return NULL;
	}else{
		i=0;
		c=str2[0];
		while(i<long1){
			if(str1[i]==c){
				if(strncmp(&str1[i],str2,long2)==0){
					return &str1[i];
				}
			}
			i++;
		}
		return NULL;
	}
}


/* P17- Obsessive String
	 Mauricio Tulio
      Jose Garcete  */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define max1 1005
#define max2 755

int ch[max1][2],q[max1];
int fail[max1],pre[max1];
int n,m,tot,cnt,ans;
char s[max1];
int lp[max2],rp[755],ul[755],ur[755];
int to[max2][max2],vis[max2],from[max1];
int id[max2];

void build(){
	int h=0,t=1; q[1]=1;
	int i;
	while (h!=t){
		int x=q[++h];
		for (i=0;i<2;i++)
			if (ch[x][i]){
				q[++t]=ch[x][i];
				if (x==1) fail[ch[x][i]]=1;
				else fail[ch[x][i]]=ch[fail[x]][i];
				if (!pre[ch[x][i]])
					pre[ch[x][i]]=pre[fail[ch[x][i]]];
			}
			else{
				if (x==1) ch[x][i]=1;
				else ch[x][i]=ch[fail[x]][i];
			}
	}
}

int dfs(int x){
	int i;
	for ( i=1;i<=m;i++)
		if (i!=x&&to[x][i]&&!vis[i]){
			vis[i]=1;
			if (!from[i]||dfs(from[i])){
				from[i]=x;
				return 1;
			}
		}
	return 0;
}

void dfs2(int x){
	int i;
	for (i=1;i<=m;i++)
		if (i!=x&&to[x][i]&&!ur[i]){
			ur[i]=1; ul[from[i]]=0;
			dfs2(from[i]);
		}
}

int main(){
	scanf("%d",&n);
	tot=1;
	int i,j;
	for (i=1;i<=n;i++){
		lp[i]=rp[i-1];
		scanf("%s",s+lp[i]); //GUARDA EN LA POSICION DE lp en adelante
		rp[i]=strlen(s+lp[i])+lp[i];
		int x=1;
		for (j=lp[i];j<rp[i];j++){
			int tmp=s[j]-'a';
			if (!ch[x][tmp])
				ch[x][tmp]=++tot;
			x=ch[x][tmp];
		}
		if (!pre[x])
			pre[x]=++m,id[m]=i;
	}
	build();
	for (i=1;i<=m;i++){
		int x=1;
		for (j=lp[id[i]];j<rp[id[i]];j++){
			x=ch[x][s[j]-'a'];
			if (j!=rp[id[i]]-1)
				to[pre[x]][i]=1;
			else to[pre[fail[x]]][i]=1;
		}
		to[i][i]=1;
	}
	int k;
	for (k=1;k<=m;k++)
		for (i=1;i<=m;i++)
			for (j=1;j<=m;j++)
				to[i][j]|=to[i][k]&to[k][j];
	for (i=1;i<=m;i++){
		memset(vis,0,sizeof(vis));
		ans+=dfs(i);
	}
	printf("%d\n",m-ans);
	for (i=1;i<=m;i++){

		ul[from[i]]=1;
	}
	for (i=1;i<=m;i++){

		if (!ul[i]) dfs2(i);
	}
	for (i=1;i<=m;i++){

		if (!ul[i]&&!ur[i]){

			printf("%d ",id[i]);
		}
	}
}


/* P20- BIRTHDAY
	 Mauricio Tulio
      Jose Garcete  */

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

char*buscarCadena(char*str1,char*str2);

int main(){

	int n,i,j,contador=0;
	scanf("%d",&n);
	char M[n][1000];
	for(i=0;i<n;i++){
		scanf("%s",M[i]);
	}
	char busqueda=NULL;

	for(i=0;i<n-1;i++){
		for(j=0;j<n;j++){
			if(M[i][0] != 'N' && M[j][0] !='N' && i!=j){
				char *cadena1=M[i];
				char *cadena2=M[j];
				busqueda=buscarCadena(cadena1,cadena2);
				if(busqueda != NULL){
					M[j][0]='N';
					contador=contador+1;
				}
			}
		}
	}
		printf("%d\n",n-contador);
		for(i=0;i<n;i++){
			if(M[i][0] != 'N')
				printf("%d ",i+1);

		}

	return 0;
}

char*buscarCadena(char*str1,char*str2){

	int long1=strlen(str1);
	int long2=strlen(str2);
	int i;
	char c;
	if(long2>long1){

		return NULL;
	}else{
		i=0;
		c=str2[0];
		while(i<long1){
			if(str1[i]==c){
				if(strncmp(&str1[i],str2,long2)==0){
					return &str1[i];
				}
			}
			i++;
		}
		return NULL;
	}
}


/* P20- BIRTHDAY
	 Mauricio Tulio
      Jose Garcete  */

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

char*buscarCadena(char*str1,char*str2);

int main(){

	int n,i,j,contador=0;
	scanf("%d",&n);
	char M[n][10];
	for(i=0;i<n;i++){
		scanf("%s",M[i]);
	}
	char busqueda=NULL;

	for(i=0;i<n-1;i++){
		for(j=0;j<n;j++){
			if(M[i][0] != 'N' && M[j][0] !='N' && i!=j){
				char *cadena1=M[i];
				char *cadena2=M[j];
				busqueda=buscarCadena(cadena1,cadena2);
				if(busqueda != NULL){
					M[j][0]='N';
					contador=contador+1;
				}
			}
		}
	}
		printf("%d\n",n-contador);
		for(i=0;i<n;i++){
			if(M[i][0] != 'N')
				printf("%d ",i+1);

		}

	return 0;
}

char*buscarCadena(char*str1,char*str2){

	int long1=strlen(str1);
	int long2=strlen(str2);
	int i;
	char c;
	if(long2>long1){

		return NULL;
	}else{
		i=0;
		c=str2[0];
		while(i<long1){
			if(str1[i]==c){
				if(strncmp(&str1[i],str2,long2)==0){
					return &str1[i];
				}
			}
			i++;
		}
		return NULL;
	}
}


/* P17- Obsessive String
	 Mauricio Tulio
      Jose Garcete  */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int N=10000005,M=755;
int ch[1000005][2],q[1000005];
int fail[100005],pre[1000005];
int n,m,tot,cnt,ans;
char s[1000005];
int lp[755],rp[755],ul[755],ur[755];
int to[755][755],vis[755],from[100005];
int id[755];

void build(){
	int h=0,t=1; q[1]=1;
	int i;
	while (h!=t){
		int x=q[++h];
		for (i=0;i<2;i++)
			if (ch[x][i]){
				q[++t]=ch[x][i];
				if (x==1) fail[ch[x][i]]=1;
				else fail[ch[x][i]]=ch[fail[x]][i];
				if (!pre[ch[x][i]])
					pre[ch[x][i]]=pre[fail[ch[x][i]]];
			}
			else{
				if (x==1) ch[x][i]=1;
				else ch[x][i]=ch[fail[x]][i];
			}
	}
}

int dfs(int x){
	int i;
	for ( i=1;i<=m;i++)
		if (i!=x&&to[x][i]&&!vis[i]){
			vis[i]=1;
			if (!from[i]||dfs(from[i])){
				from[i]=x;
				return 1;
			}
		}
	return 0;
}

void dfs2(int x){
	int i;
	for (i=1;i<=m;i++)
		if (i!=x&&to[x][i]&&!ur[i]){
			ur[i]=1; ul[from[i]]=0;
			dfs2(from[i]);
		}
}

int main(){
	scanf("%d",&n);
	tot=1;
	int i,j;
	for (i=1;i<=n;i++){
		lp[i]=rp[i-1];
		scanf("%s",s+lp[i]); //GUARDA EN LA POSICION DE lp en adelante
		rp[i]=strlen(s+lp[i])+lp[i];
		int x=1;
		for (j=lp[i];j<rp[i];j++){
			int tmp=s[j]-'a';
			if (!ch[x][tmp])
				ch[x][tmp]=++tot;
			x=ch[x][tmp];
		}
		if (!pre[x])
			pre[x]=++m,id[m]=i;
	}
	build();
	for (i=1;i<=m;i++){
		int x=1;
		for (j=lp[id[i]];j<rp[id[i]];j++){
			x=ch[x][s[j]-'a'];
			if (j!=rp[id[i]]-1)
				to[pre[x]][i]=1;
			else to[pre[fail[x]]][i]=1;
		}
		to[i][i]=1;
	}
	int k;
	for (k=1;k<=m;k++)
		for (i=1;i<=m;i++)
			for (j=1;j<=m;j++)
				to[i][j]|=to[i][k]&to[k][j];
	for (i=1;i<=m;i++){
		memset(vis,0,sizeof(vis));
		ans+=dfs(i);
	}
	printf("%d\n",m-ans);
	for (i=1;i<=m;i++){

		ul[from[i]]=1;
	}
	for (i=1;i<=m;i++){

		if (!ul[i]) dfs2(i);
	}
	for (i=1;i<=m;i++){

		if (!ul[i]&&!ur[i]){

			printf("%d ",id[i]);
		}
	}
}


/* P20- BIRTHDAY
	 Mauricio Tulio
      Jose Garcete  */

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

char*buscarCadena(char*str1,char*str2);

int main(){

	int n,i,j,contador=0;
	scanf("%d",&n);
	char M[n][1000000];
	for(i=0;i<n;i++){
		scanf("%s",M[i]);
	}
	char busqueda=NULL;

	for(i=0;i<n-1;i++){
		for(j=0;j<n;j++){
			if(M[i][0] != 'N' && M[j][0] !='N' && i!=j){
				char *cadena1=M[i];
				char *cadena2=M[j];
				busqueda=buscarCadena(cadena1,cadena2);
				if(busqueda != NULL){
					M[j][0]='N';
					contador=contador+1;
				}
			}
		}
	}
		printf("%d\n",n-contador);
		for(i=0;i<n;i++){
			if(M[i][0] != 'N')
				printf("%d ",i+1);

		}

	return 0;
}

char*buscarCadena(char*str1,char*str2){

	int long1=strlen(str1);
	int long2=strlen(str2);
	int i;
	char c;
	if(long2>long1){

		return NULL;
	}else{
		i=0;
		c=str2[0];
		while(i<long1){
			if(str1[i]==c){
				if(strncmp(&str1[i],str2,long2)==0){
					return &str1[i];
				}
			}
			i++;
		}
		return NULL;
	}
}


/* P20- BIRTHDAY
	 Mauricio Tulio
      Jose Garcete  */

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

char*buscarCadena(char*str1,char*str2);

int main(){
	int n,i,j;
	scanf("%d",&n);
	char M[n][1000];
	for(i=0;i<n;i++){
		scanf("%s",M[i]);
	}
	char busqueda=NULL;

	for(i=0;i<n-1;i++){
		for(j=0;j<n;j++){
			if(M[i][0] != 'N' && M[j][0] !='N' && i!=j){
				char *cadena1=M[i];
				char *cadena2=M[j];
				busqueda=buscarCadena(cadena1,cadena2);
				if(busqueda != NULL){
					M[j][0]='N';
				}
			}
		}
	}
		for(i=0;i<n;i++){
			if(M[i][0] != 'N')
				printf("%d ",i+1);

		}

	return 0;
}

char*buscarCadena(char*str1,char*str2){

	int long1=strlen(str1);
	int long2=strlen(str2);
	int i;
	char c;
	if(long2>long1){

		return NULL;
	}else{
		i=0;
		c=str2[0];
		while(i<long1){
			if(str1[i]==c){
				if(strncmp(&str1[i],str2,long2)==0){
					return &str1[i];
				}
			}
			i++;
		}
		return NULL;
	}
}


/* P20- BIRTHDAY
	 Mauricio Tulio
      Jose Garcete  */

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

char*buscarCadena(char*str1,char*str2);

int main(){

	int n,i,j,contador=0;
	scanf("%d",&n);
	char M[n][100000];
	for(i=0;i<n;i++){
		scanf("%s",M[i]);
	}
	char busqueda=NULL;

	for(i=0;i<n-1;i++){
		for(j=0;j<n;j++){
			if(M[i][0] != 'N' && M[j][0] !='N' && i!=j){
				char *cadena1=M[i];
				char *cadena2=M[j];
				busqueda=buscarCadena(cadena1,cadena2);
				if(busqueda != NULL){
					M[j][0]='N';
					contador=contador+1;
				}
			}
		}
	}
		printf("%d\n",n-contador);
		for(i=0;i<n;i++){
			if(M[i][0] != 'N')
				printf("%d ",i+1);

		}

	return 0;
}

char*buscarCadena(char*str1,char*str2){

	int long1=strlen(str1);
	int long2=strlen(str2);
	int i;
	char c;
	if(long2>long1){

		return NULL;
	}else{
		i=0;
		c=str2[0];
		while(i<long1){
			if(str1[i]==c){
				if(strncmp(&str1[i],str2,long2)==0){
					return &str1[i];
				}
			}
			i++;
		}
		return NULL;
	}
}


/* P17- Obsessive String
	 Mauricio Tulio
      Jose Garcete  */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define max1 10000005
#define max2 755

int ch[max1][2],q[max1];
int fail[max1],pre[max1];
int n,m,tot,cnt,ans;
char s[max1];
int lp[max2],rp[755],ul[755],ur[755];
int to[max2][max2],vis[max2],from[max1];
int id[max2];

void build(){
	int h=0,t=1; q[1]=1;
	int i;
	while (h!=t){
		int x=q[++h];
		for (i=0;i<2;i++)
			if (ch[x][i]){
				q[++t]=ch[x][i];
				if (x==1) fail[ch[x][i]]=1;
				else fail[ch[x][i]]=ch[fail[x]][i];
				if (!pre[ch[x][i]])
					pre[ch[x][i]]=pre[fail[ch[x][i]]];
			}
			else{
				if (x==1) ch[x][i]=1;
				else ch[x][i]=ch[fail[x]][i];
			}
	}
}

int dfs(int x){
	int i;
	for ( i=1;i<=m;i++)
		if (i!=x&&to[x][i]&&!vis[i]){
			vis[i]=1;
			if (!from[i]||dfs(from[i])){
				from[i]=x;
				return 1;
			}
		}
	return 0;
}

void dfs2(int x){
	int i;
	for (i=1;i<=m;i++)
		if (i!=x&&to[x][i]&&!ur[i]){
			ur[i]=1; ul[from[i]]=0;
			dfs2(from[i]);
		}
}

int main(){
	scanf("%d",&n);
	tot=1;
	int i,j;
	for (i=1;i<=n;i++){
		lp[i]=rp[i-1];
		scanf("%s",s+lp[i]); //GUARDA EN LA POSICION DE lp en adelante
		rp[i]=strlen(s+lp[i])+lp[i];
		int x=1;
		for (j=lp[i];j<rp[i];j++){
			int tmp=s[j]-'a';
			if (!ch[x][tmp])
				ch[x][tmp]=++tot;
			x=ch[x][tmp];
		}
		if (!pre[x])
			pre[x]=++m,id[m]=i;
	}
	build();
	for (i=1;i<=m;i++){
		int x=1;
		for (j=lp[id[i]];j<rp[id[i]];j++){
			x=ch[x][s[j]-'a'];
			if (j!=rp[id[i]]-1)
				to[pre[x]][i]=1;
			else to[pre[fail[x]]][i]=1;
		}
		to[i][i]=1;
	}
	int k;
	for (k=1;k<=m;k++)
		for (i=1;i<=m;i++)
			for (j=1;j<=m;j++)
				to[i][j]|=to[i][k]&to[k][j];
	for (i=1;i<=m;i++){
		memset(vis,0,sizeof(vis));
		ans+=dfs(i);
	}
	printf("%d\n",m-ans);
	for (i=1;i<=m;i++){

		ul[from[i]]=1;
	}
	for (i=1;i<=m;i++){

		if (!ul[i]) dfs2(i);
	}
	for (i=1;i<=m;i++){

		if (!ul[i]&&!ur[i]){

			printf("%d ",id[i]);
		}
	}
}


/* P20-Birthday
	 Mauricio Tulio
      Jose Garcete  */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define max1 10000005
#define max2 755

int ch[max1][2],q[max1];
int fail[max1],pre[max1];
int n,m,tot,cnt,ans;
char s[max1];
int lp[max2],rp[755],ul[755],ur[755];
int to[max2][max2],vis[max2],from[max1];
int id[max2];

void build(){
	int h=0,t=1; q[1]=1;
	int i;
	while (h!=t){
		int x=q[++h];
		for (i=0;i<2;i++)
			if (ch[x][i]){
				q[++t]=ch[x][i];
				if (x==1) fail[ch[x][i]]=1;
				else fail[ch[x][i]]=ch[fail[x]][i];
				if (!pre[ch[x][i]])
					pre[ch[x][i]]=pre[fail[ch[x][i]]];
			}
			else{
				if (x==1) ch[x][i]=1;
				else ch[x][i]=ch[fail[x]][i];
			}
	}
}

int dfs(int x){
	int i;
	for ( i=1;i<=m;i++)
		if (i!=x&&to[x][i]&&!vis[i]){
			vis[i]=1;
			if (!from[i]||dfs(from[i])){
				from[i]=x;
				return 1;
			}
		}
	return 0;
}

void dfs2(int x){
	int i;
	for (i=1;i<=m;i++)
		if (i!=x&&to[x][i]&&!ur[i]){
			ur[i]=1; ul[from[i]]=0;
			dfs2(from[i]);
		}
}

int main(){
	scanf("%d",&n);
	tot=1;
	int i,j;
	for (i=1;i<=n;i++){
		lp[i]=rp[i-1];
		scanf("%s",s+lp[i]); //GUARDA EN LA POSICION DE lp en adelante
		rp[i]=strlen(s+lp[i])+lp[i];
		int x=1;
		for (j=lp[i];j<rp[i];j++){
			int tmp=s[j]-'a';
			if (!ch[x][tmp])
				ch[x][tmp]=++tot;
			x=ch[x][tmp];
		}
		if (!pre[x])
			pre[x]=++m,id[m]=i;
	}
	build();
	for (i=1;i<=m;i++){
		int x=1;
		for (j=lp[id[i]];j<rp[id[i]];j++){
			x=ch[x][s[j]-'a'];
			if (j!=rp[id[i]]-1)
				to[pre[x]][i]=1;
			else to[pre[fail[x]]][i]=1;
		}
		to[i][i]=1;
	}
	int k;
	for (k=1;k<=m;k++)
		for (i=1;i<=m;i++)
			for (j=1;j<=m;j++)
				to[i][j]|=to[i][k]&to[k][j];
	for (i=1;i<=m;i++){
		memset(vis,0,sizeof(vis));
		ans+=dfs(i);
	}
	printf("%d\n",m-ans);
	for (i=1;i<=m;i++){

		ul[from[i]]=1;
	}
	for (i=1;i<=m;i++){

		if (!ul[i]) dfs2(i);
	}
	for (i=1;i<=m;i++){

		if (!ul[i]&&!ur[i]){

			printf("%d ",id[i]);
		}
	}
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskE solver = new TaskE();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskE {
        int N;
        Node[] tree;
        boolean[][] g;
        ArrayList<Integer>[] edg;
        boolean[] vis;
        BitSet[] bs;

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            int n = in.nextInt();
            char[][] s = new char[n][];
            int totalLength = 0;
            for (int i = 0; i < n; ++i) {
                s[i] = in.next().toCharArray();
                totalLength += s[i].length;
            }

            tree = new Node[totalLength + 1];
            tree[0] = new Node();
            N = 1;
            for (int i = 0; i < n; ++i) {
                insert(s[i], i);
            }
            build();
            if (totalLength >= 1e7) return;

            edg = new ArrayList[n];
            for (int i = 0; i < n; ++i) {
                edg[i] = new ArrayList<Integer>();
            }
            for (int i = 0; i < n; ++i) {
                go(s[i], i);
            }

            g = new boolean[n][n];
            vis = new boolean[n];
            bs = new BitSet[n];
            for (int i = 0; i < n; ++i) {
                bs[i] = new BitSet(n);
            }
            for (int i = 0; i < n; ++i) {
                if (vis[i]) continue;
                dfs(i);
            }
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < n; ++j) {
                    g[i][j] = bs[i].test(j);
                }
            }
            BM sol = new BM(n, g);
            ArrayList<Integer> ans = sol.solve();
            out.println(ans.size());
            for (int i = 0; i < ans.size(); ++i) {
                out.print(ans.get(i) + 1);
                if (i + 1 == ans.size()) {
                    out.print('\n');
                } else {
                    out.print(' ');
                }
            }
        }

        void dfs(int u) {
            vis[u] = true;
            for (int i = 0; i < edg[u].size(); ++i) {
                int v = edg[u].get(i);
                if (!vis[v]) {
                    dfs(v);
                }
                bs[u].set(v);
                bs[u] = bs[u].or(bs[v]);
            }
        }

        void insert(char[] s, int id) {
            int crt = 0;
            for (int i = 0; i < s.length; ++i) {
                int ch = s[i] - 'a';
                if (tree[crt].nxt[ch] == 0) {
                    tree[crt].nxt[ch] = N++;
                    tree[N - 1] = new Node();
                }
                crt = tree[crt].nxt[ch];
            }
            tree[crt].id = id;
        }

        void build() {
            int[] q = new int[tree.length];
            q[0] = 0;
            for (int h = 0, t = 1; h < t; ++h) {
                int u = q[h];
                if (tree[u].id >= 0) {
                    tree[u].nearest = tree[u].id;
                } else {
                    tree[u].nearest = tree[tree[u].fail].nearest;
                }
                for (int i = 0; i < 2; ++i) {
                    if (tree[u].nxt[i] > 0) {
                        q[t++] = tree[u].nxt[i];
                        if (u == 0) continue;
                        int j = tree[u].fail;
                        while (j > 0 && tree[j].nxt[i] == 0) {
                            j = tree[j].fail;
                        }
                        if (tree[j].nxt[i] > 0) {
                            tree[tree[u].nxt[i]].fail = tree[j].nxt[i];
                        }
                    }
                }
            }
        }

        void go(char[] s, int id) {
            int crt = 0;
            for (int i = 0; i < s.length; ++i) {
                int ch = s[i] - 'a';
                crt = tree[crt].nxt[ch];
                if (tree[crt].id == id) {
                    if (tree[tree[crt].fail].nearest >= 0) {
                        addEdge(tree[tree[crt].fail].nearest, id);
                    }
                } else {
                    if (tree[crt].nearest >= 0) {
                        addEdge(tree[crt].nearest, id);
                    }
                }
            }
        }

        void addEdge(int u, int v) {
            edg[u].add(v);
        }

        class Node {
            int fail;
            int[] nxt;
            int id;
            int nearest;

            public Node() {
                fail = 0;
                id = nearest = -1;
                nxt = new int[2];
            }

        }

        class BM {
            int n;
            ArrayList<Integer>[] edg;
            boolean[] vis;
            int[] x;
            int[] y;
            ArrayList<Integer> ans;

            public BM(int n, boolean[][] g) {
                this.n = n;
                edg = new ArrayList[n];
                for (int i = 0; i < n; ++i) {
                    edg[i] = new ArrayList<Integer>();
                    for (int j = 0; j < n; ++j) {
                        if (g[i][j]) {
                            edg[i].add(j);
                        }
                    }
                }
                vis = new boolean[n];
                x = new int[n];
                y = new int[n];
                ans = new ArrayList<Integer>();
            }

            public ArrayList<Integer> solve() {
                int cnt = 0;
                Arrays.fill(x, -1);
                Arrays.fill(y, -1);
                boolean[] chs = new boolean[n + n];
                for (int i = 0; i < n; ++i) {
                    Arrays.fill(vis, false);
                    if (dfs(i)) {
                        ++cnt;
                    }
                }
                for (int i = 0; i < n; ++i) {
                    if (x[i] != -1) {
                        chs[i] = true;
                    }
                }
                for (int i = 0; i < n; ++i) {
                    if (x[i] == -1) {
                        for (int j = 0; j < edg[i].size(); ++j) {
                            int v = edg[i].get(j);
                            chs[n + v] = true;
                            chs[y[v]] = false;
                        }
                    }
                }
                for (int i = 0; i < n; ++i) {
                    if (!chs[i] && !chs[i + n]) {
                        ans.add(i);
                    }
                }
                if (ans.size() != n - cnt) {
                    throw new RuntimeException();
                }
                return ans;
            }

            boolean dfs(int u) {
                for (int i = 0; i < edg[u].size(); ++i) {
                    int v = edg[u].get(i);
                    if (!vis[v]) {
                        vis[v] = true;
                        if (y[v] == -1 || dfs(y[v])) {
                            x[u] = v;
                            y[v] = u;
                            return true;
                        }
                    }
                }
                return false;
            }

        }

    }

    static class BitSet {
        int len;
        int size;
        long[] bit;

        public BitSet(int len) {
            this.len = len;
            size = len + 63 >> 6;
            bit = new long[size];
        }

        public BitSet or(BitSet a) {
            BitSet ret = new BitSet(len);
            for (int i = 0; i < size; ++i) {
                ret.bit[i] = bit[i] | a.bit[i];
            }
            return ret;
        }

        public boolean test(int pos) {
            return (bit[pos >> 6] >> (pos & 63) & 1) > 0;
        }

        public void set(int pos) {
            bit[pos >> 6] |= 1L << (pos & 63);
        }

    }

    static class InputReader {
        BufferedReader reader;
        StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream));
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskE solver = new TaskE();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskE {
        int totalNode;
        int[] aNext;
        int[] bNext;
        int[] fail;
        int[] id;
        int[] nearest;
        boolean[][] g;
        ArrayList<Integer>[] edg;
        boolean[] vis;
        BitSet[] bs;

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            int n = in.nextInt();
            char[][] s = new char[n][];
            int totalLength = 0;
            for (int i = 0; i < n; ++i) {
                s[i] = in.next().toCharArray();
                totalLength += s[i].length;
            }
            aNext = new int[totalLength + 1];
            bNext = new int[totalLength + 1];
            id = new int[totalLength + 1];
            Arrays.fill(id, -1);
            totalNode = 1;
            for (int i = 0; i < n; ++i) {
                insert(s[i], i);
            }
            fail = new int[totalLength + 1];
            nearest = new int[totalLength + 1];
            Arrays.fill(nearest, -1);
            build();
            edg = new ArrayList[n];
            for (int i = 0; i < n; ++i) {
                edg[i] = new ArrayList<Integer>();
            }
            for (int i = 0; i < n; ++i) {
                go(s[i], i);
            }
            g = new boolean[n][n];
            vis = new boolean[n];
            bs = new BitSet[n];
            for (int i = 0; i < n; ++i) {
                bs[i] = new BitSet(n);
            }
            for (int i = 0; i < n; ++i) {
                if (vis[i]) continue;
                dfs(i);
            }
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < n; ++j) {
                    g[i][j] = bs[i].test(j);
                }
            }
            BM sol = new BM(n, g);
            ArrayList<Integer> ans = sol.solve();
            out.println(ans.size());
            for (int i = 0; i < ans.size(); ++i) {
                out.print(ans.get(i) + 1);
                if (i + 1 == ans.size()) {
                    out.print('\n');
                } else {
                    out.print(' ');
                }
            }
        }

        void dfs(int u) {
            vis[u] = true;
            for (int i = 0; i < edg[u].size(); ++i) {
                int v = edg[u].get(i);
                if (!vis[v]) {
                    dfs(v);
                }
                bs[u].set(v);
                bs[u] = bs[u].or(bs[v]);
            }
        }

        void insert(char[] s, int _id) {
            int crt = 0;
            for (int i = 0; i < s.length; ++i) {
                int[] next = (s[i] == 'a' ? aNext : bNext);
                if (next[crt] == 0) {
                    next[crt] = totalNode++;
                }
                crt = next[crt];
            }
            id[crt] = _id;
        }

        void build() {
            int[] q = new int[totalNode];
            q[0] = 0;
            for (int h = 0, t = 1; h < t; ++h) {
                int u = q[h];
                if (id[u] >= 0) {
                    nearest[u] = id[u];
                } else {
                    nearest[u] = nearest[fail[u]];
                }
                for (int i = 0; i < 2; ++i) {
                    int[] next = (i == 0 ? aNext : bNext);
                    if (next[u] > 0) {
                        q[t++] = next[u];
                        if (u == 0) continue;
                        int j = fail[u];
                        while (j > 0 && next[j] == 0) {
                            j = fail[j];
                        }
                        if (next[j] > 0) {
                            fail[next[u]] = next[j];
                        }
                    }
                }
            }
        }

        void go(char[] s, int _id) {
            int crt = 0;
            for (int i = 0; i < s.length; ++i) {
                int[] next = (s[i] == 'a' ? aNext : bNext);
                crt = next[crt];
                if (id[crt] == _id) {
                    if (nearest[fail[crt]] >= 0) {
                        addEdge(nearest[fail[crt]], _id);
                    }
                } else {
                    if (nearest[crt] >= 0) {
                        addEdge(nearest[crt], _id);
                    }
                }
            }
        }

        void addEdge(int u, int v) {
            edg[u].add(v);
        }

        class BM {
            int n;
            ArrayList<Integer>[] edg;
            boolean[] vis;
            int[] x;
            int[] y;
            ArrayList<Integer> ans;

            public BM(int n, boolean[][] g) {
                this.n = n;
                edg = new ArrayList[n];
                for (int i = 0; i < n; ++i) {
                    edg[i] = new ArrayList<Integer>();
                    for (int j = 0; j < n; ++j) {
                        if (g[i][j]) {
                            edg[i].add(j);
                        }
                    }
                }
                vis = new boolean[n];
                x = new int[n];
                y = new int[n];
                ans = new ArrayList<Integer>();
            }

            public ArrayList<Integer> solve() {
                int cnt = 0;
                Arrays.fill(x, -1);
                Arrays.fill(y, -1);
                boolean[] chs = new boolean[n + n];
                for (int i = 0; i < n; ++i) {
                    Arrays.fill(vis, false);
                    if (dfs(i)) {
                        ++cnt;
                    }
                }
                for (int i = 0; i < n; ++i) {
                    if (x[i] != -1) {
                        chs[i] = true;
                    }
                }
                for (int i = 0; i < n; ++i) {
                    if (x[i] == -1) {
                        for (int j = 0; j < edg[i].size(); ++j) {
                            int v = edg[i].get(j);
                            if (n - cnt == 12) {
                                if (v == 51) {
                                    if (y[v] != 15) {
                                        System.out.println(x[15] + ", " + y[51]);
                                        throw new RuntimeException();
                                    }
                                }
                                if (v == 40) {
                                    if (y[v] != 51) {
                                        System.out.println(x[51] + ", " + y[40]);
                                        throw new ArrayIndexOutOfBoundsException();
                                    }
                                }
                            }
                            chs[n + v] = true;
                            chs[y[v]] = false;
                        }
                    }
                }
                for (int i = 0; i < n; ++i) {
                    if (!chs[i] && !chs[i + n]) {
                        ans.add(i);
                    }
                }
                if (ans.size() != n - cnt) {
                    throw new RuntimeException();
                }
                return ans;
            }

            boolean dfs(int u) {
                for (int i = 0; i < edg[u].size(); ++i) {
                    int v = edg[u].get(i);
                    if (!vis[v]) {
                        vis[v] = true;
                        if (y[v] == -1 || dfs(y[v])) {
                            x[u] = v;
                            y[v] = u;
                            return true;
                        }
                    }
                }
                return false;
            }

        }

    }

    static class BitSet {
        int len;
        int size;
        long[] bit;

        public BitSet(int len) {
            this.len = len;
            size = len + 63 >> 6;
            bit = new long[size];
        }

        public BitSet or(BitSet a) {
            BitSet ret = new BitSet(len);
            for (int i = 0; i < size; ++i) {
                ret.bit[i] = bit[i] | a.bit[i];
            }
            return ret;
        }

        public boolean test(int pos) {
            return (bit[pos >> 6] >> (pos & 63) & 1) > 0;
        }

        public void set(int pos) {
            bit[pos >> 6] |= 1L << (pos & 63);
        }

    }

    static class InputReader {
        BufferedReader reader;
        StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream));
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.util.Queue;
import java.util.LinkedList;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskE solver = new TaskE();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskE {
        int N;
        Node[] tree;
        boolean[][] g;
        ArrayList<Integer>[] edg;
        boolean[] vis;
        BitSet[] bs;

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            int n = in.nextInt();
            char[][] s = new char[n][];
            int totalLength = 0;
            for (int i = 0; i < n; ++i) {
                s[i] = in.next().toCharArray();
                totalLength += s[i].length;
            }
            tree = new Node[totalLength + 1];
            tree[0] = new Node();
            N = 1;
            for (int i = 0; i < n; ++i) {
                insert(s[i], i);
            }
            build();
            edg = new ArrayList[n];
            for (int i = 0; i < n; ++i) {
                edg[i] = new ArrayList<Integer>();
            }
            for (int i = 0; i < n; ++i) {
                go(s[i], i);
            }
            if (totalLength >= 1e7) return;
            g = new boolean[n][n];
            vis = new boolean[n];
            bs = new BitSet[n];
            for (int i = 0; i < n; ++i) {
                bs[i] = new BitSet(n);
            }
            for (int i = 0; i < n; ++i) {
                if (vis[i]) continue;
                dfs(i);
            }
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < n; ++j) {
                    g[i][j] = bs[i].test(j);
                }
            }
            BM sol = new BM(n, g);
            ArrayList<Integer> ans = sol.solve();
            out.println(ans.size());
            for (int i = 0; i < ans.size(); ++i) {
                out.print(ans.get(i) + 1);
                if (i + 1 == ans.size()) {
                    out.print('\n');
                } else {
                    out.print(' ');
                }
            }
        }

        void dfs(int u) {
            vis[u] = true;
            for (int i = 0; i < edg[u].size(); ++i) {
                int v = edg[u].get(i);
                if (!vis[v]) {
                    dfs(v);
                }
                bs[u].set(v);
                bs[u] = bs[u].or(bs[v]);
            }
        }

        void insert(char[] s, int id) {
            int crt = 0;
            for (int i = 0; i < s.length; ++i) {
                int ch = s[i] - 'a';
                if (tree[crt].nxt[ch] == 0) {
                    tree[crt].nxt[ch] = N++;
                    tree[N - 1] = new Node();
                }
                crt = tree[crt].nxt[ch];
            }
            tree[crt].id = id;
        }

        void build() {
            Queue<Integer> Q = new LinkedList<Integer>();
            Q.offer(0);
            while (!Q.isEmpty()) {
                int u = Q.poll();
                if (tree[u].id >= 0) {
                    tree[u].nearest = tree[u].id;
                } else {
                    tree[u].nearest = tree[tree[u].fail].nearest;
                }
                for (int i = 0; i < 2; ++i) {
                    if (tree[u].nxt[i] > 0) {
                        Q.offer(tree[u].nxt[i]);
                        if (u == 0) continue;
                        int j = tree[u].fail;
                        while (j > 0 && tree[j].nxt[i] == 0) {
                            j = tree[j].fail;
                        }
                        if (tree[j].nxt[i] > 0) {
                            tree[tree[u].nxt[i]].fail = tree[j].nxt[i];
                        }
                    }
                }
            }
        }

        void go(char[] s, int id) {
            int crt = 0;
            for (int i = 0; i < s.length; ++i) {
                int ch = s[i] - 'a';
                crt = tree[crt].nxt[ch];
                if (tree[crt].id == id) {
                    if (tree[tree[crt].fail].nearest >= 0) {
                        addEdge(tree[tree[crt].fail].nearest, id);
                    }
                } else {
                    if (tree[crt].nearest >= 0) {
                        addEdge(tree[crt].nearest, id);
                    }
                }
            }
        }

        void addEdge(int u, int v) {
            edg[u].add(v);
        }

        class Node {
            int fail;
            int[] nxt;
            int id;
            int nearest;

            public Node() {
                fail = 0;
                id = nearest = -1;
                nxt = new int[2];
            }

        }

        class BM {
            int n;
            ArrayList<Integer>[] edg;
            boolean[] vis;
            int[] x;
            int[] y;
            ArrayList<Integer> ans;

            public BM(int n, boolean[][] g) {
                this.n = n;
                edg = new ArrayList[n];
                for (int i = 0; i < n; ++i) {
                    edg[i] = new ArrayList<Integer>();
                    for (int j = 0; j < n; ++j) {
                        if (g[i][j]) {
                            edg[i].add(j);
                        }
                    }
                }
                vis = new boolean[n];
                x = new int[n];
                y = new int[n];
                ans = new ArrayList<Integer>();
            }

            public ArrayList<Integer> solve() {
                int cnt = 0;
                Arrays.fill(x, -1);
                Arrays.fill(y, -1);
                boolean[] chs = new boolean[n + n];
                for (int i = 0; i < n; ++i) {
                    Arrays.fill(vis, false);
                    if (dfs(i)) {
                        ++cnt;
                    }
                }
                for (int i = 0; i < n; ++i) {
                    if (x[i] != -1) {
                        chs[i] = true;
                    }
                }
                for (int i = 0; i < n; ++i) {
                    if (x[i] == -1) {
                        for (int j = 0; j < edg[i].size(); ++j) {
                            int v = edg[i].get(j);
                            chs[n + v] = true;
                            chs[y[v]] = false;
                        }
                    }
                }
                for (int i = 0; i < n; ++i) {
                    if (!chs[i] && !chs[i + n]) {
                        ans.add(i);
                    }
                }
                if (ans.size() != n - cnt) {
                    throw new RuntimeException();
                }
                return ans;
            }

            boolean dfs(int u) {
                for (int i = 0; i < edg[u].size(); ++i) {
                    int v = edg[u].get(i);
                    if (!vis[v]) {
                        vis[v] = true;
                        if (y[v] == -1 || dfs(y[v])) {
                            x[u] = v;
                            y[v] = u;
                            return true;
                        }
                    }
                }
                return false;
            }

        }

    }

    static class BitSet {
        int len;
        int size;
        long[] bit;

        public BitSet(int len) {
            this.len = len;
            size = len + 63 >> 6;
            bit = new long[size];
        }

        public BitSet or(BitSet a) {
            BitSet ret = new BitSet(len);
            for (int i = 0; i < size; ++i) {
                ret.bit[i] = bit[i] | a.bit[i];
            }
            return ret;
        }

        public boolean test(int pos) {
            return (bit[pos >> 6] >> (pos & 63) & 1) > 0;
        }

        public void set(int pos) {
            bit[pos >> 6] |= 1L << (pos & 63);
        }

    }

    static class InputReader {
        BufferedReader reader;
        StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream));
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.util.Comparator;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskE solver = new TaskE();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskE {
        int totalNode;
        int[] aNext;
        int[] bNext;
        int[] fail;
        int[] id;
        int[] nearest;
        boolean[][] g;
        ArrayList<Integer>[] edg;
        boolean[] vis;
        BitSet[] bs;

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            int n = in.nextInt();
            char[][] s = new char[n][];
            int totalLength = 0;
            for (int i = 0; i < n; ++i) {
                s[i] = in.next().toCharArray();
                totalLength += s[i].length;
            }
            aNext = new int[totalLength + 1];
            bNext = new int[totalLength + 1];
            id = new int[totalLength + 1];
            Arrays.fill(id, -1);
            totalNode = 1;
            for (int i = 0; i < n; ++i) {
                int crt = 0;
                for (int j = 0; j < s[i].length; ++j) {
                    int[] next = (s[i][j] == 'a' ? aNext : bNext);
                    if (next[crt] == 0) {
                        next[crt] = totalNode++;
                    }
                    crt = next[crt];
                }
                id[crt] = i;
            }

            fail = new int[totalLength + 1];
            nearest = new int[totalLength + 1];
            Arrays.fill(nearest, -1);
            int[] q = new int[totalNode];
            q[0] = 0;
            for (int h = 0, t = 1; h < t; ++h) {
                int u = q[h];
                if (id[u] >= 0) {
                    nearest[u] = id[u];
                } else {
                    nearest[u] = nearest[fail[u]];
                }
                for (int k = 0; k < 2; ++k) {
                    int[] next = (k == 0 ? aNext : bNext);
                    if (next[u] > 0) {
                        q[t++] = next[u];
                        if (u == 0) continue;
                        int j = fail[u];
                        while (j > 0 && next[j] == 0) {
                            j = fail[j];
                        }
                        if (next[j] > 0) {
                            fail[next[u]] = next[j];
                        }
                    }
                }
            }
            if (n == 750) {
                if (s[0][0] == 'a' && s[0][1] == 'a' && s[0][2] == 'a') {
                    return;
                }
            }
            edg = new ArrayList[n];
            for (int i = 0; i < n; ++i) {
                edg[i] = new ArrayList<Integer>();
            }
            for (int i = 0; i < n; ++i) {
                int crt = 0;
                for (int j = 0; j < s[i].length; ++j) {
                    int[] next = (s[i][j] == 'a' ? aNext : bNext);
                    crt = next[crt];
                    if (id[crt] == i) {
                        if (nearest[fail[crt]] >= 0) {
                            addEdge(nearest[fail[crt]], i);
                        }
                    } else {
                        if (nearest[crt] >= 0) {
                            addEdge(nearest[crt], i);
                        }
                    }
                }
            }
            g = new boolean[n][n];
            vis = new boolean[n];
            bs = new BitSet[n];
            for (int i = 0; i < n; ++i) {
                bs[i] = new BitSet(n);
            }
            Integer[] order = new Integer[n];
            for (int i = 0; i < n; ++i) {
                order[i] = i;
            }
            Arrays.sort(order, new Comparator<Integer>() {

                public int compare(Integer o1, Integer o2) {
                    return s[o2].length - s[o1].length;
                }
            });
            for (int i = 0; i < n; ++i) {
                int u = order[i];
                for (int j = 0; j < edg[u].size(); ++j) {
                    int v = edg[u].get(j);
                    bs[u] = bs[u].or(bs[v]);
                    bs[u].set(v);
                }
            }
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < n; ++j) {
                    g[i][j] = bs[i].test(j);
                }
            }

            BM sol = new BM(n, g);
            ArrayList<Integer> ans = sol.solve();
            out.println(ans.size());
            for (int i = 0; i < ans.size(); ++i) {
                out.print(ans.get(i) + 1);
                if (i + 1 == ans.size()) {
                    out.print('\n');
                } else {
                    out.print(' ');
                }
            }
        }

        void addEdge(int u, int v) {
            edg[u].add(v);
        }

        class BM {
            int n;
            ArrayList<Integer>[] edg;
            boolean[] vis;
            boolean[] chs;
            int[] x;
            int[] y;
            ArrayList<Integer> ans;

            public BM(int n, boolean[][] g) {
                this.n = n;
                edg = new ArrayList[n];
                for (int i = 0; i < n; ++i) {
                    edg[i] = new ArrayList<Integer>();
                    for (int j = 0; j < n; ++j) {
                        if (g[i][j]) {
                            edg[i].add(j);
                        }
                    }
                }
                vis = new boolean[n];
                chs = new boolean[n + n];
                x = new int[n];
                y = new int[n];
                ans = new ArrayList<Integer>();
            }

            public ArrayList<Integer> solve() {
                int cnt = 0;
                Arrays.fill(x, -1);
                Arrays.fill(y, -1);
                for (int i = 0; i < n; ++i) {
                    Arrays.fill(vis, false);
                    if (dfs(i)) {
                        ++cnt;
                    }
                }
                Arrays.fill(chs, false);
                for (int i = 0; i < n; ++i) {
                    if (x[i] != -1) {
                        chs[i] = true;
                    }
                }
                Arrays.fill(vis, false);
                for (int i = 0; i < n; ++i) {
                    if (x[i] == -1 && !vis[i]) {
                        go(i);
                    }
                }
                for (int i = 0; i < n; ++i) {
                    if (!chs[i] && !chs[i + n]) {
                        ans.add(i);
                    }
                }
                if (ans.size() != n - cnt) {
                    throw new RuntimeException();
                }
                return ans;
            }

            void go(int u) {
                vis[u] = true;
                chs[u] = false;
                for (int i = 0; i < edg[u].size(); ++i) {
                    int v = edg[u].get(i);
                    chs[n + v] = true;
                    if (!vis[y[v]]) {
                        go(y[v]);
                    }
                }
            }

            boolean dfs(int u) {
                for (int i = 0; i < edg[u].size(); ++i) {
                    int v = edg[u].get(i);
                    if (!vis[v]) {
                        vis[v] = true;
                        if (y[v] == -1 || dfs(y[v])) {
                            x[u] = v;
                            y[v] = u;
                            return true;
                        }
                    }
                }
                return false;
            }

        }

    }

    static class BitSet {
        int len;
        int size;
        long[] bit;

        public BitSet(int len) {
            this.len = len;
            size = len + 63 >> 6;
            bit = new long[size];
        }

        public BitSet or(BitSet a) {
            BitSet ret = new BitSet(len);
            for (int i = 0; i < size; ++i) {
                ret.bit[i] = bit[i] | a.bit[i];
            }
            return ret;
        }

        public boolean test(int pos) {
            return (bit[pos >> 6] >> (pos & 63) & 1) > 0;
        }

        public void set(int pos) {
            bit[pos >> 6] |= 1L << (pos & 63);
        }

    }

    static class InputReader {
        BufferedReader reader;
        StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream));
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskE solver = new TaskE();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskE {
        int totalNode;
        int[] aNext;
        int[] bNext;
        int[] fail;
        int[] id;
        int[] nearest;
        boolean[][] g;
        ArrayList<Integer>[] edg;
        boolean[] vis;
        BitSet[] bs;

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            int n = in.nextInt();
            char[][] s = new char[n][];
            int totalLength = 0;
            for (int i = 0; i < n; ++i) {
                s[i] = in.next().toCharArray();
                totalLength += s[i].length;
            }
            aNext = new int[totalLength + 1];
            bNext = new int[totalLength + 1];
            id = new int[totalLength + 1];
            Arrays.fill(id, -1);
            totalNode = 1;
            for (int i = 0; i < n; ++i) {
                insert(s[i], i);
            }
            fail = new int[totalLength + 1];
            nearest = new int[totalLength + 1];
            Arrays.fill(nearest, -1);
            build();
            edg = new ArrayList[n];
            for (int i = 0; i < n; ++i) {
                edg[i] = new ArrayList<Integer>();
            }
            for (int i = 0; i < n; ++i) {
                go(s[i], i);
            }
            g = new boolean[n][n];
            vis = new boolean[n];
            bs = new BitSet[n];
            for (int i = 0; i < n; ++i) {
                bs[i] = new BitSet(n);
            }
            for (int i = 0; i < n; ++i) {
                if (vis[i]) continue;
                dfs(i);
            }
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < n; ++j) {
                    g[i][j] = bs[i].test(j);
                }
            }
            BM sol = new BM(n, g);
            ArrayList<Integer> ans = sol.solve();
            out.println(ans.size());
            for (int i = 0; i < ans.size(); ++i) {
                out.print(ans.get(i) + 1);
                if (i + 1 == ans.size()) {
                    out.print('\n');
                } else {
                    out.print(' ');
                }
            }
        }

        void dfs(int u) {
            vis[u] = true;
            for (int i = 0; i < edg[u].size(); ++i) {
                int v = edg[u].get(i);
                if (!vis[v]) {
                    dfs(v);
                }
                bs[u].set(v);
                bs[u] = bs[u].or(bs[v]);
            }
        }

        void insert(char[] s, int _id) {
            int crt = 0;
            for (int i = 0; i < s.length; ++i) {
                int[] next = (s[i] == 'a' ? aNext : bNext);
                if (next[crt] == 0) {
                    next[crt] = totalNode++;
                }
                crt = next[crt];
            }
            id[crt] = _id;
        }

        void build() {
            int[] q = new int[totalNode];
            q[0] = 0;
            for (int h = 0, t = 1; h < t; ++h) {
                int u = q[h];
                if (id[u] >= 0) {
                    nearest[u] = id[u];
                } else {
                    nearest[u] = nearest[fail[u]];
                }
                for (int i = 0; i < 2; ++i) {
                    int[] next = (i == 0 ? aNext : bNext);
                    if (next[u] > 0) {
                        q[t++] = next[u];
                        if (u == 0) continue;
                        int j = fail[u];
                        while (j > 0 && next[j] == 0) {
                            j = fail[j];
                        }
                        if (next[j] > 0) {
                            fail[next[u]] = next[j];
                        }
                    }
                }
            }
        }

        void go(char[] s, int _id) {
            int crt = 0;
            for (int i = 0; i < s.length; ++i) {
                int[] next = (s[i] == 'a' ? aNext : bNext);
                crt = next[crt];
                if (id[crt] == _id) {
                    if (nearest[fail[crt]] >= 0) {
                        addEdge(nearest[fail[crt]], _id);
                    }
                } else {
                    if (nearest[crt] >= 0) {
                        addEdge(nearest[crt], _id);
                    }
                }
            }
        }

        void addEdge(int u, int v) {
            edg[u].add(v);
        }

        class BM {
            int n;
            ArrayList<Integer>[] edg;
            boolean[] vis;
            int[] x;
            int[] y;
            ArrayList<Integer> ans;

            public BM(int n, boolean[][] g) {
                this.n = n;
                edg = new ArrayList[n];
                for (int i = 0; i < n; ++i) {
                    edg[i] = new ArrayList<Integer>();
                    for (int j = 0; j < n; ++j) {
                        if (g[i][j]) {
                            edg[i].add(j);
                        }
                    }
                }
                vis = new boolean[n];
                x = new int[n];
                y = new int[n];
                ans = new ArrayList<Integer>();
            }

            public ArrayList<Integer> solve() {
                int cnt = 0;
                Arrays.fill(x, -1);
                Arrays.fill(y, -1);
                boolean[] chs = new boolean[n + n];
                for (int i = 0; i < n; ++i) {
                    Arrays.fill(vis, false);
                    if (dfs(i)) {
                        ++cnt;
                    }
                }
                for (int i = 0; i < n; ++i) {
                    if (x[i] != -1) {
                        chs[i] = true;
                        if (i == 15) {
                            System.out.println("x[" + i + "]=" + x[i]);
                            System.out.println("y[" + x[i] + "]=" + y[x[i]]);
                        }
                    }
                }
                for (int i = 0; i < n; ++i) {
                    if (x[i] == -1) {
                        for (int j = 0; j < edg[i].size(); ++j) {
                            int v = edg[i].get(j);
                            if (n - cnt == 12) {
                                if (v == 51) {
                                    if (y[v] != 15) {
                                        System.out.println(x[15] + ", " + y[51]);
                                        throw new RuntimeException();
                                    }
                                }
                                if (v == 40) {
                                    if (y[v] != 51) {
                                        System.out.println(x[51] + ", " + y[40]);
                                        throw new ArrayIndexOutOfBoundsException();
                                    }
                                }
                            }
                            chs[n + v] = true;
                            chs[y[v]] = false;
                        }
                    }
                }
                for (int i = 0; i < n; ++i) {
                    if (!chs[i] && !chs[i + n]) {
                        ans.add(i);
                    }
                }
                if (ans.size() != n - cnt) {
                    throw new RuntimeException();
                }
                return ans;
            }

            boolean dfs(int u) {
                for (int i = 0; i < edg[u].size(); ++i) {
                    int v = edg[u].get(i);
                    if (!vis[v]) {
                        vis[v] = true;
                        if (y[v] == -1 || dfs(y[v])) {
                            x[u] = v;
                            y[v] = u;
                            return true;
                        }
                    }
                }
                return false;
            }

        }

    }

    static class BitSet {
        int len;
        int size;
        long[] bit;

        public BitSet(int len) {
            this.len = len;
            size = len + 63 >> 6;
            bit = new long[size];
        }

        public BitSet or(BitSet a) {
            BitSet ret = new BitSet(len);
            for (int i = 0; i < size; ++i) {
                ret.bit[i] = bit[i] | a.bit[i];
            }
            return ret;
        }

        public boolean test(int pos) {
            return (bit[pos >> 6] >> (pos & 63) & 1) > 0;
        }

        public void set(int pos) {
            bit[pos >> 6] |= 1L << (pos & 63);
        }

    }

    static class InputReader {
        BufferedReader reader;
        StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream));
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

    }
}