One unknown hacker wants to get the admin's password of AtForces testing system, to get problems from the next contest. To achieve that, he sneaked into the administrator's office and stole a piece of paper with a list of n passwords — strings, consists of small Latin letters.

Hacker went home and started preparing to hack AtForces. He found that the system contains only passwords from the stolen list and that the system determines the equivalence of the passwords a and b as follows:

  * two passwords a and b are equivalent if there is a letter, that exists in both a and b; 
  * two passwords a and b are equivalent if there is a password c from the list, which is equivalent to both a and b. 



If a password is set in the system and an equivalent one is applied to access the system, then the user is accessed into the system.

For example, if the list contain passwords "a", "b", "ab", "d", then passwords "a", "b", "ab" are equivalent to each other, but the password "d" is not equivalent to any other password from list. In other words, if:

  * admin's password is "b", then you can access to system by using any of this passwords: "a", "b", "ab"; 
  * admin's password is "d", then you can access to system by using only "d". 



Only one password from the list is the admin's password from the testing system. Help hacker to calculate the minimal number of passwords, required to guaranteed access to the system. Keep in mind that the hacker does not know which password is set in the system.

Input

The first line contain integer n (1 ≤ n ≤ 2 ⋅ 10^5) — number of passwords in the list. Next n lines contains passwords from the list – non-empty strings s_i, with length at most 50 letters. Some of the passwords may be equal.

It is guaranteed that the total length of all passwords does not exceed 10^6 letters. All of them consist only of lowercase Latin letters.

Output

In a single line print the minimal number of passwords, the use of which will allow guaranteed to access the system.

Examples

Input


4
a
b
ab
d


Output


2

Input


3
ab
bc
abc


Output


1

Input


1
codeforces


Output


1

Note

In the second example hacker need to use any of the passwords to access the system.
import java.io.*;
import java.math.*;
import java.util.*;

/**
 *
 * @author Saju
 *
 */

public class Main {

	private static int dx[] = { -2, -3, -2, -1, -1, 1};
	private static int dy[] = { 1, -1, -1, -2, -3, -2};

	private static final long INF = (long) (1e15);
	private static final int INT_INF = Integer.MAX_VALUE;
	private static final long NEG_INF = Long.MIN_VALUE;
	private static final double EPSILON = 1e-10;

	private static final int MAX = 1007;
	private static final int MOD = 10007;
	
	private static final int MAXN = 100007;
	private static final int MAXA = 10000009;
	private static final int MAXLOG = 22;

	public static void main(String[] args) {

		InputReader in = new InputReader(System.in);
//		PrintWriter out = new PrintWriter(System.out);
		

/*



*/
		
		int n = in.nextInt();
		
		List<Integer> adj[] = new ArrayList[26];
		for(int i = 0; i < 26; i++) {
			adj[i] = new ArrayList<Integer>();
		}
		
		int checker[][] = new int[26][26];
		Set<String> set1 = new HashSet<String>();
		for(int i = 0; i < n; i++) {
			String str = in.next();
			set1.add(str);
		}
		Iterator<String> it1 = set1.iterator();
		
		int brr[] = new int[26];
		while(it1.hasNext()) {
			String str = it1.next();
			if(str.length() == 1) {
				int a = str.charAt(0) - 'a';
				brr[a] = 1;
			}
			else {
				int count = 0;
				int arr[] = new int[26];
				for(int j = 0; j < str.length() - 1; j++) {
					int a = str.charAt(j) - 'a';
					int b = str.charAt(j + 1) - 'a';
					
					if(checker[a][b] == 1) {
						continue;
					}
					if(count == 26) {
						System.out.println("1");
						return;
					}
					if(arr[a] == 0) {
						arr[a] = 1;
						count++;
					}
					if(arr[b] == 0) {
						arr[b] = 1;
						count++;
					}
					checker[a][b] = 1;
					adj[a].add(b);
					adj[b].add(a);
					brr[a] = 1;
					brr[b] = 1;
				}
			}
			
		}
		
		boolean visited[] = new boolean[26];
		
		int count = 0;
		for(int i = 0; i < 26; i++) {
			if(brr[i] != 0 && !visited[i]) {
				count++;
				dfs(i, adj, visited);
			}
			
		}
		System.out.println(count);
		
//		out.flush();
//		out.close();
		System.exit(0);
	}
	
	private static void dfs(int u, List<Integer>[] adj, boolean[] visited) {
		visited[u] = true;
		for(int v : adj[u]) {
			if(!visited[v]) {
				dfs(v, adj, visited);
			}
			
		}
	}
	
	private static void generatePrime(int n) {
		 //O(NloglogN)
		boolean arr[] = new boolean[n + 5];
		Arrays.fill(arr, true);
		for(int i = 2; i * i <=n; i++){
			if(arr[i] == true){
				for(int j = i * i; j <= n; j+=i){
					arr[j] = false; 
				}
			}
		}
		int count = 0;
		int start = 0;
		for(int i = 2; i <= n; i++){
			if(arr[i] == true){
//				System.out.println(i + " ");
				count++;
			}
			if(count == (start * 100) + 1) {
//				System.out.println(i);
				start++;
			}
		}
		System.out.println();
		System.out.println(count);
		
	}
	
	private static Map<Integer, Integer> primeFactorization(long n){
		Map<Integer, Integer> map = new HashMap<Integer, Integer>();
		
		for(int i = 2; i <= Math.sqrt(n); i++){
			if(n % i == 0){
			int count = 0;
			while(n % i == 0){
				count++;
				n = n / i;
			}
			map.put(i, count);
//			System.out.println("i: " + i + ", count: " + count);
		}
			
		}
		if(n != 1) {
//			System.out.println(n);
			map.put((int)n, 1);
		}
		return map;
	}

	private static class Pair<T>{
		T a;
		T b;
		Pair(T a, T b){
			this.a = a;
			this.b = b;
		}
	}
	
	private static class SegmentTree{
		int n;
		private final int MAXN = 100007;
		private long[] tree = new long[MAXN << 2];
		private long[] lazy = new long[MAXN << 2];
		private long[] arr = new long[MAXN];
		
		
		/***
		 * 
		 * arr is 1 based index.
		 * 
		 * @param arr
		 * 
		 */
		SegmentTree(int n, long[] arr){
			this.n = n;
			for(int i = 0; i < arr.length; i++) {
				this.arr[i] = arr[i];
			}
		}
		
		void build(int index, int left, int right) {
			if(left == right) {
				tree[index] = arr[left];
			}
			else {
				int mid = (left + right) / 2;
				
				build(index * 2, left, mid);
				build((index * 2) + 1, mid + 1, right);
				tree[index] = max(tree[(index * 2)], tree[(index * 2) + 1]);
			}
		}
		
		long query(int node, int left, int right, int start, int end) {
			
			if(left > end || right < start) {
				return NEG_INF;
			}
			
			if(left >= start && right <= end) {
				return tree[node];
			}
			int mid = (left + right) / 2;
			long val1 = query(2 * node, left, mid, start, end);
			long val2 = query(2 * node + 1, mid + 1, right, start, end);
			
			return max(val1, val2);
		}
		
		void update(int node, int left, int right, int idx, long val) {
			if(left == right) {
				tree[node] += val;
			}
			else {
				int mid = (left + right) / 2;
				if(idx <= mid) {
					update(2 * node, left, mid, idx, val);
				}
				else {
					update(2 * node + 1, mid + 1, right, idx, val);
				}
				tree[node] = max(tree[(2 * node) + 1], tree[(2 * node)]);
			}
		}
		
		

		 void updateRange(int node, int start, int end, int l, int r, long val)
		{
		    if(lazy[node] != 0)
		    { 
		        // This node needs to be updated
		        tree[node] =  lazy[node];    // Update it
		        if(start != end)
		        {
		            lazy[node*2] = lazy[node];                  // Mark child as lazy
		            lazy[node*2+1] = lazy[node];                // Mark child as lazy
		        }
		        lazy[node] = 0;                                  // Reset it
		    }
		    if(start > end || start > r || end < l)              // Current segment is not within range [l, r]
		        return;
		    if(start >= l && end <= r)
		    {
		        // Segment is fully within range
		        tree[node] =  val;
		        if(start != end)
		        {
		            // Not leaf node
		            lazy[node*2] = val;
		            lazy[node*2+1] = val;
		        }
		        return;
		    }
		    int mid = (start + end) / 2;
		    updateRange(node*2, start, mid, l, r, val);        // Updating left child
		    updateRange(node*2 + 1, mid + 1, end, l, r, val);   // Updating right child
		    tree[node] = max(tree[node*2], tree[node*2+1]);        // Updating root with max value 
		}

		 long queryRange(int node, int start, int end, int l, int r)
		{
		    if(start > end || start > r || end < l)
		        return 0;         // Out of range
		    if(lazy[node] != 0)
		    {
		        // This node needs to be updated
		        tree[node] =  lazy[node];            // Update it
		        if(start != end)
		        {
		            lazy[node*2] = lazy[node];         // Mark child as lazy
		            lazy[node*2+1] = lazy[node];    // Mark child as lazy
		        }
		        lazy[node] = 0;                 // Reset it
		    }
		    if(start >= l && end <= r)             // Current segment is totally within range [l, r]
		        return tree[node];
		    int mid = (start + end) / 2;
		    long p1 = queryRange(node*2, start, mid, l, r);         // Query left child
		    long p2 = queryRange(node*2 + 1, mid + 1, end, l, r); // Query right child
		    return max(p1, p2);
		}
		
		 void buildRange(int node, int low, int high){
			if(low == high){
				tree[node] =  arr[low];
				return;
			}
			
			int mid = (low + high) / 2;
			int left = node << 1;
			int right = left | 1;
			buildRange(left, low, mid);
			buildRange(right, mid + 1, high);
			tree[node] = max(tree[left], tree[right]);
		}
		
		
		void printSegmentTree() {
			System.out.println(Arrays.toString(tree));
		}
		
	}
	
	private static class KMP{
		
		private static char[] t;
		private static char[] s;
		
		public int kmp(char[]t, char[]s) {
			this.t = t;
			this.s = s;
			return this.kmp();
		}
		
		private int kmp() {
			
			List<Integer> prefixTable = getPrefixTable(s);
			
			int match = 0;
			int i = 0;
			int j = 0;
			
			int n = t.length;
			int m = s.length;
			while(i < n) {
				if(t[i] == s[j]) {
					if(j == m - 1) {
						match++;
						j = prefixTable.get(j - 1);
						continue;
					}
					i++;
					j++;
				}
				else if(j > 0) {
					j = prefixTable.get(j - 1);
				}
				else {
					i++;
				}
			}
			
			return match;
		}

		/***
		1. We compute the prefix values π[i] in a loop by iterating 	<br/>
				from i=1 to i=n−1 (π[0] just gets assigned with 0).		<br/><br/>
		2. To calculate the current value π[i] we set the variable j 	<br/>
				denoting the length of the best suffix for i−1. Initially j=π[i−1].	<br/>
		3. Test if the suffix of length j+1 is also a prefix by		 <br/><br/>
				comparing s[j] and s[i]. If they are equal then we assign π[i]=j+1, 	<br/>
				otherwise we reduce j to π[j−1] and repeat this step.		<br/><br/>
		4. If we have reached the length j=0 and still don't have a match,	<br/> 
				then we assign π[i]=0 and go to the next index i+1.		<br/><br/>
				
		@param
	 	pattern(String)
	***/
		private List<Integer> getPrefixTable(char[] pattern){
			
			List<Integer> prefixTable = new ArrayList<Integer>();
			int n = pattern.length;
			for(int i = 0; i < n; i++) {
				prefixTable.add(0);
			}
			
			for(int i = 1; i < n; i++) {
				for(int j = prefixTable.get(i - 1); j >= 0;) {
					if(pattern[j] == pattern[i]) {
						prefixTable.set(i, j + 1);
						break;
					}
					else if(j > 0){
						j = prefixTable.get(j - 1);
					}
					else {
						break;
					}
				}
			}
			
			return prefixTable;
		}
	}
	


	private static class Point {
		int x;
		int y;
		Point(int x, int y){
			this.x = x;
			this.y = y;
		}
		
		@Override
		public boolean equals(Object obj) {
			Point ob = (Point) obj;
			if(this.x == ob.x && this.y == ob.y){
				return true;
			}
			return false;
		}
		@Override
		public String toString() {
			return this.x + " " + this.y;
		}
	}

	private static long pow(int base, int pow) {
		long val = 1L;
		for(int i = 1; i <= pow; i++) {
			val *= base;
		}
		return val;
	}
	
	private static int log(int x, int base) {
		return (int) (Math.log(x) / Math.log(base));
	}
	private static int log(long x, int base) {
		return (int) (Math.log(x) / Math.log(base));
	}
	private static long max(long a, long b) {
		if (a >= b) {
			return a;
		}
		return b;
	}

	private static long abs(long a) {
		if (a < 0) {
			return -a;
		}
		return a;
	}

	private static int abs(int a) {
		if (a < 0) {
			return -a;
		}
		return a;
	}

	private static int max(int a, int b) {
		if (a >= b) {
			return a;
		}
		return b;
	}

	private static int min(int a, int b) {
		if (a <= b) {
			return a;
		}
		return b;
	}
	
	private static long min(long a, long b) {
		if (a <= b) {
			return a;
		}
		return b;
	}

	private static long gcd(long a, long b) {
		if (b == 0) {
			return a;
		}
		return gcd(b, a % b);
	}

	private static int gcd(int a, int b) {
		if (b == 0) {
			return a;
		}
		return gcd(b, a % b);
	}

	private static long bigMod(long n, long k, long m) {

		long ans = 1;
		while (k > 0) {
			if ((k & 1) == 1) {
				ans = (ans * n) % m;
			}
			n = (n * n) % m;
			k >>= 1;
		}
		return ans;
	}

	/*
	 * Returns an iterator pointing to the first element in the range [first,
	 * last] which does not compare less than val.
	 * 
	 */
	private static int lowerBoundNew(long[] arr, long num) {
		int start = 0;
		int end = arr.length - 1;
		int index = 0;
		int len = arr.length;
		int mid = 0;
		while (true) {
			if (start > end) {
				break;
			}
			mid = (start + end) / 2;
			if (arr[mid] > num) {
				end = mid - 1;
			} else if (arr[mid] < num) {
				start = mid + 1;
			} else {
				while (mid >= 0 && arr[mid] == num) {
					mid--;
				}
				return mid + 1;
			}
		}
		if (arr[mid] < num) {
			return mid + 1;
		}
		return mid;
	}

	/*
	 * upper_bound() is a standard library function in C++ defined in the header
	 * . It returns an iterator pointing to the first element in the range
	 * [first, last) that is greater than value, or last if no such element is
	 * found
	 * 
	 */
	private static int upperBoundNew(long[] arr, long num) {

		int start = 0;
		int end = arr.length - 1;
		int index = 0;
		int len = arr.length;
		int mid = 0;
		while (true) {
			if (start > end) {
				break;
			}
			mid = (start + end) / 2;
			if (arr[mid] > num) {
				end = mid - 1;
			} else if (arr[mid] < num) {
				start = mid + 1;
			} else {
				while (mid < len && arr[mid] == num) {
					mid++;
				}
				if (mid == len - 1 && arr[mid] == num) {
					return mid + 1;
				} else {
					return mid;
				}
			}
		}
		if (arr[mid] < num) {
			return mid + 1;
		}
		return mid;
	}

	private static class InputReader {
		public BufferedReader reader;
		public StringTokenizer tokenizer;

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

		public String next() {
			try {
				while (tokenizer == null || !tokenizer.hasMoreTokens()) {
					tokenizer = new StringTokenizer(reader.readLine());

				}
			} catch (IOException e) {
				return null;
			}
			return tokenizer.nextToken();
		}

		public String nextLine() {
			String line = null;
			try {
				tokenizer = null;
				line = reader.readLine();
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
			return line;
		}

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

		public double nextDouble() {
			return Double.parseDouble(next());
		}

		public long nextLong() {
			return Long.parseLong(next());
		}

		public boolean hasNext() {
			try {
				while (tokenizer == null || !tokenizer.hasMoreTokens()) {
					tokenizer = new StringTokenizer(reader.readLine());
				}
			} catch (Exception e) {
				return false;
			}
			return true;
		}
	}
}