Today is birthday of a Little Dasha — she is now 8 years old! On this occasion, each of her n friends and relatives gave her a ribbon with a greeting written on it, and, as it turned out, all the greetings are different. Dasha gathered all the ribbons and decided to throw away some of them in order to make the remaining set stylish. The birthday girl considers a set of ribbons stylish if no greeting written on some ribbon is a substring of another greeting written on some other ribbon. Let us recall that the substring of the string s is a continuous segment of s.

Help Dasha to keep as many ribbons as possible, so that she could brag about them to all of her friends. Dasha cannot rotate or flip ribbons, that is, each greeting can be read in a single way given in the input.

Input

The first line of the input contains integer n (1 ≤ n ≤ 750) — the number of Dasha's relatives and friends.

Each of the next n lines contains exactly one greeting. Each greeting consists of characters 'a' and 'b' only.

The total length of all greetings won't exceed 10 000 000 characters.

Output

In the first line print the maximum size of the stylish set. In the second line print the numbers of ribbons involved in it, assuming that they are numbered from 1 to n in the order they appear in the input. If there are several stylish sets of the maximum size, print any of them.

Examples

Input

5
abab
aba
aabab
ababb
bab


Output

2
2 5

Note

In the sample, the answer that keeps ribbons 3 and 4 is also considered correct.
import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.stream.IntStream;
import java.util.Arrays;
import java.util.Random;
import java.util.ArrayList;
import java.io.OutputStreamWriter;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.IOException;
import java.io.Serializable;
import java.io.UncheckedIOException;
import java.util.List;
import java.util.stream.Stream;
import java.io.Closeable;
import java.io.Writer;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(null, new TaskAdapter(), "", 1 << 29);
        thread.start();
        thread.join();
    }

    static class TaskAdapter implements Runnable {
        @Override
        public void run() {
            InputStream inputStream = System.in;
            OutputStream outputStream = System.out;
            FastInput in = new FastInput(inputStream);
            FastOutput out = new FastOutput(outputStream);
            EBirthday solver = new EBirthday();
            solver.solve(1, in, out);
            out.close();
        }
    }

    static class EBirthday {
        Debug debug = new Debug(true);

        public void solve(int testNumber, FastInput in, FastOutput out) {
            int n = in.ri();
            int threshold = (int) 1e7;
            ACAutomaton2 ac = new ACAutomaton2('a', 'b', (int) 1e7);
            byte[] buf = new byte[threshold];
            byte[][] s = new byte[n][];
            boolean[] skip = new boolean[n];
            int[] terminals = new int[n];
            for (int i = 0; i < n; i++) {
                int len = in.rs(buf, 0);
                s[i] = Arrays.copyOf(buf, len);
            }
            debug.elapse("read");
            for (int i = 0; i < n; i++) {
                ac.prepareBuild();
                for (byte x : s[i]) {
                    ac.build((char) x);
                }
                terminals[i] = ac.buildLast;
                if (ac.input[terminals[i]] == null) {
                    ac.input[terminals[i]] = new BitSet(n);
                } else {
                    skip[i] = true;
                    continue;
                }
            }
            debug.elapse("build");
            ac.endBuild();

            debug.elapse("build fail");
            for (int i = 0; i < n; i++) {
                if (skip[i]) {
                    continue;
                }
                ac.prepareMatch();
                for (byte x : s[i]) {
                    ac.match(x);
                    int last = ac.matchLast;
                    if (ac.input[last] != null) {
                        ac.input[last].set(i);
                    }
                }
            }

            debug.elapse("match");
            int[] order = IntStream.range(0, n).toArray();
            CompareUtils.quickSort(order, (i, j) -> -(s[i].length - s[j].length), 0, order.length);
            for (int i : order) {
                if (ac.terminals[terminals[i]] != 0) {
                    ac.input[ac.terminals[terminals[i]]].or(ac.input[terminals[i]]);
                }
            }
            DinicBipartiteMatch bm = new DinicBipartiteMatch(n, n);
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (i != j && ac.input[terminals[i]].get(j)) {
                        bm.addEdge(j, i);
                    }
                }
            }
            List<Integer> ans = new ArrayList<>();
            bm.solve();
            boolean[][] mis = bm.maxIndependentSet();
            for (int i = 0; i < n; i++) {
                if (skip[i]) {
                    continue;
                }
                if (mis[0][i] && mis[1][i]) {
                    ans.add(i);
                }
            }

            debug.elapse("bm");
            out.println(ans.size());
            for (int x : ans) {
                out.append(x + 1).append(' ');
            }

            debug.summary();
        }

    }

    static class DinicBipartiteMatch {
        private List<IntegerFlowEdge>[] g;
        private IntegerDinic dinic;
        private int[] lMates;
        private int[] rMates;
        int l;
        int r;

        private int idOfL(int i) {
            return i;
        }

        private int idOfR(int i) {
            return i + l;
        }

        private int idOfSrc() {
            return l + r;
        }

        private int idOfDst() {
            return idOfSrc() + 1;
        }

        public DinicBipartiteMatch(int l, int r) {
            this.l = l;
            this.r = r;
            lMates = new int[l];
            rMates = new int[r];
            g = Graph.createGraph(idOfDst() + 1);
            dinic = new IntegerDinic();
            for (int i = 0; i < l; i++) {
                IntegerFlow.addFlowEdge(g, idOfSrc(), idOfL(i), 1);
            }
            for (int i = 0; i < r; i++) {
                IntegerFlow.addFlowEdge(g, idOfR(i), idOfDst(), 1);
            }
        }

        public void addEdge(int u, int v) {
            IntegerFlow.addFlowEdge(g, idOfL(u), idOfR(v), 1);
        }

        public int solve() {
            Arrays.fill(lMates, -1);
            Arrays.fill(rMates, -1);
            dinic.apply(g, idOfSrc(), idOfDst(), l);
            int ans = 0;
            for (int i = 0; i < l; i++) {
                for (IntegerFlowEdge e : g[idOfL(i)]) {
                    if (e.real && e.flow == 1) {
                        ans++;
                        int to = e.to - idOfR(0);
                        lMates[i] = to;
                        rMates[to] = i;
                        break;
                    }
                }
            }
            return ans;
        }

        public boolean[][] minVertexCover() {
            boolean[] lVis = new boolean[l];
            boolean[] rVis = new boolean[r];
            for (int i = 0; i < r; i++) {
                if (rMates[i] == -1) {
                    dfsRight(i, lVis, rVis);
                }
            }

            boolean[] left = new boolean[l];
            boolean[] right = new boolean[r];
            for (int i = 0; i < l; i++) {
                left[i] = lVis[i];
            }
            for (int i = 0; i < r; i++) {
                right[i] = !rVis[i];
            }

            return new boolean[][]{left, right};
        }

        public boolean[][] maxIndependentSet() {
            boolean[][] cover = minVertexCover();
            for (boolean[] arr : cover) {
                for (int i = 0; i < arr.length; i++) {
                    arr[i] = !arr[i];
                }
            }
            return cover;
        }

        private void dfsRight(int i, boolean[] lVis, boolean[] rVis) {
            if (rVis[i]) {
                return;
            }
            rVis[i] = true;
            for (IntegerFlowEdge e : g[idOfR(i)]) {
                if (e.real) {
                    continue;
                }
                dfsLeft(e.to - idOfL(0), lVis, rVis);
            }
        }

        private void dfsLeft(int i, boolean[] lVis, boolean[] rVis) {
            if (lMates[i] == -1) {
                return;
            }
            if (lVis[i]) {
                return;
            }
            lVis[i] = true;
            dfsRight(lMates[i], lVis, rVis);
        }

    }

    static class Debug {
        private boolean offline;
        private PrintStream out = System.err;
        private long time = System.currentTimeMillis();
        private long begin = System.currentTimeMillis();

        public Debug(boolean enable) {
            offline = enable && System.getSecurityManager() == null;
        }

        public Debug elapse(String name) {
            if (offline) {
                debug(name, System.currentTimeMillis() - time);
                time = System.currentTimeMillis();
            }
            return this;
        }

        public Debug summary() {
            if (offline) {
                debug("used time", (System.currentTimeMillis() - begin) + "ms");
                debug("used memory", (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) >> 20);
            }
            return this;
        }

        public Debug debug(String name, long x) {
            if (offline) {
                debug(name, "" + x);
            }
            return this;
        }

        public Debug debug(String name, String x) {
            if (offline) {
                out.printf("%s=%s", name, x);
                out.println();
            }
            return this;
        }

    }

    static class CompareUtils {
        private static final int THRESHOLD = 8;

        private CompareUtils() {
        }

        public static void insertSort(int[] data, IntegerComparator cmp, int l, int r) {
            for (int i = l + 1; i <= r; i++) {
                int j = i;
                int val = data[i];
                while (j > l && cmp.compare(data[j - 1], val) > 0) {
                    data[j] = data[j - 1];
                    j--;
                }
                data[j] = val;
            }
        }

        public static void quickSort(int[] data, IntegerComparator cmp, int f, int t) {
            if (t - f <= THRESHOLD) {
                insertSort(data, cmp, f, t - 1);
                return;
            }
            SequenceUtils.swap(data, f, RandomWrapper.INSTANCE.nextInt(f, t - 1));
            int l = f;
            int r = t;
            int m = l + 1;
            while (m < r) {
                int c = cmp.compare(data[m], data[l]);
                if (c == 0) {
                    m++;
                } else if (c < 0) {
                    SequenceUtils.swap(data, l, m);
                    l++;
                    m++;
                } else {
                    SequenceUtils.swap(data, m, --r);
                }
            }
            quickSort(data, cmp, f, l);
            quickSort(data, cmp, m, t);
        }

    }

    static interface IntegerDeque extends IntegerStack {
        int removeFirst();

    }

    static class RandomWrapper {
        private Random random;
        public static final RandomWrapper INSTANCE = new RandomWrapper(new Random());

        public RandomWrapper() {
            this(new Random());
        }

        public RandomWrapper(Random random) {
            this.random = random;
        }

        public int nextInt(int l, int r) {
            return random.nextInt(r - l + 1) + l;
        }

    }

    static interface IntegerMaximumFlow {
    }

    static interface IntegerIterator {
        boolean hasNext();

        int next();

    }

    static interface IntegerStack {
        void addLast(int x);

        boolean isEmpty();

        void clear();

    }

    static class IntegerDinic implements IntegerMaximumFlow {
        List<IntegerFlowEdge>[] g;
        int s;
        int t;
        IntegerDeque deque;
        int[] dists;
        int[] iterators;

        public IntegerDinic() {
        }

        public void ensure(int vertexNum) {
            if (dists != null && dists.length >= vertexNum) {
                return;
            }
            deque = new IntegerDequeImpl(vertexNum);
            dists = new int[vertexNum];
            iterators = new int[vertexNum];
        }

        public int send(int root, int flow) {
            if (root == t) {
                return flow;
            }
            int snapshot = flow;
            while (iterators[root] >= 0 && flow > 0) {
                IntegerFlowEdge e = g[root].get(iterators[root]);
                if (dists[e.to] + 1 == dists[root] && e.rev.flow != 0) {
                    int sent = send(e.to, Math.min(flow, e.rev.flow));
                    if (sent > 0) {
                        flow -= sent;
                        IntegerFlow.send(e, sent);
                        continue;
                    }
                }
                iterators[root]--;
            }
            return snapshot - flow;
        }

        public int apply(List<IntegerFlowEdge>[] g, int s, int t, int send) {
            ensure(g.length);
            this.s = s;
            this.t = t;
            this.g = g;
            int flow = 0;
            while (flow < send) {
                IntegerFlow.bfsForFlow(g, t, dists, Integer.MAX_VALUE, deque);
                if (dists[s] == Integer.MAX_VALUE) {
                    break;
                }
                for (int i = 0; i < g.length; i++) {
                    iterators[i] = g[i].size() - 1;
                }
                flow += send(s, send - flow);
            }
            return flow;
        }

    }

    static class FastInput {
        private final InputStream is;
        private byte[] buf = new byte[1 << 13];
        private int bufLen;
        private int bufOffset;
        private int next;

        public FastInput(InputStream is) {
            this.is = is;
        }

        private int read() {
            while (bufLen == bufOffset) {
                bufOffset = 0;
                try {
                    bufLen = is.read(buf);
                } catch (IOException e) {
                    bufLen = -1;
                }
                if (bufLen == -1) {
                    return -1;
                }
            }
            return buf[bufOffset++];
        }

        public void skipBlank() {
            while (next >= 0 && next <= 32) {
                next = read();
            }
        }

        public int ri() {
            return readInt();
        }

        public int readInt() {
            int sign = 1;

            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+' ? 1 : -1;
                next = read();
            }

            int val = 0;
            if (sign == 1) {
                while (next >= '0' && next <= '9') {
                    val = val * 10 + next - '0';
                    next = read();
                }
            } else {
                while (next >= '0' && next <= '9') {
                    val = val * 10 - next + '0';
                    next = read();
                }
            }

            return val;
        }

        public int rs(byte[] data, int offset) {
            return readString(data, offset);
        }

        public int readString(byte[] data, int offset) {
            skipBlank();

            int originalOffset = offset;
            while (next > 32) {
                data[offset++] = (byte) next;
                next = read();
            }

            return offset - originalOffset;
        }

    }

    static class IntegerDequeImpl implements IntegerDeque {
        private int[] data;
        private int bpos;
        private int epos;
        private static final int[] EMPTY = new int[0];
        private int n;

        public IntegerDequeImpl(int cap) {
            if (cap == 0) {
                data = EMPTY;
            } else {
                data = new int[cap];
            }
            bpos = 0;
            epos = 0;
            n = cap;
        }

        private void expandSpace(int len) {
            while (n < len) {
                n = Math.max(n + 10, n * 2);
            }
            int[] newData = new int[n];
            if (bpos <= epos) {
                if (bpos < epos) {
                    System.arraycopy(data, bpos, newData, 0, epos - bpos);
                }
            } else {
                System.arraycopy(data, bpos, newData, 0, data.length - bpos);
                System.arraycopy(data, 0, newData, data.length - bpos, epos);
            }
            epos = size();
            bpos = 0;
            data = newData;
        }

        public IntegerIterator iterator() {
            return new IntegerIterator() {
                int index = bpos;


                public boolean hasNext() {
                    return index != epos;
                }


                public int next() {
                    int ans = data[index];
                    index = IntegerDequeImpl.this.next(index);
                    return ans;
                }
            };
        }

        public int removeFirst() {
            int ans = data[bpos];
            bpos = next(bpos);
            return ans;
        }

        public void addLast(int x) {
            ensureMore();
            data[epos] = x;
            epos = next(epos);
        }

        public void clear() {
            bpos = epos = 0;
        }

        private int next(int x) {
            return x + 1 >= n ? 0 : x + 1;
        }

        private void ensureMore() {
            if (next(epos) == bpos) {
                expandSpace(n + 1);
            }
        }

        public int size() {
            int ans = epos - bpos;
            if (ans < 0) {
                ans += data.length;
            }
            return ans;
        }

        public boolean isEmpty() {
            return bpos == epos;
        }

        public String toString() {
            StringBuilder builder = new StringBuilder();
            for (IntegerIterator iterator = iterator(); iterator.hasNext(); ) {
                builder.append(iterator.next()).append(' ');
            }
            return builder.toString();
        }

    }

    static class FastOutput implements AutoCloseable, Closeable, Appendable {
        private static final int THRESHOLD = 1 << 13;
        private final Writer os;
        private StringBuilder cache = new StringBuilder(THRESHOLD * 2);

        public FastOutput append(CharSequence csq) {
            cache.append(csq);
            return this;
        }

        public FastOutput append(CharSequence csq, int start, int end) {
            cache.append(csq, start, end);
            return this;
        }

        private void afterWrite() {
            if (cache.length() < THRESHOLD) {
                return;
            }
            flush();
        }

        public FastOutput(Writer os) {
            this.os = os;
        }

        public FastOutput(OutputStream os) {
            this(new OutputStreamWriter(os));
        }

        public FastOutput append(char c) {
            cache.append(c);
            afterWrite();
            return this;
        }

        public FastOutput append(int c) {
            cache.append(c);
            afterWrite();
            return this;
        }

        public FastOutput append(String c) {
            cache.append(c);
            afterWrite();
            return this;
        }

        public FastOutput println(int c) {
            return append(c).println();
        }

        public FastOutput println() {
            return append(System.lineSeparator());
        }

        public FastOutput flush() {
            try {
                os.append(cache);
                os.flush();
                cache.setLength(0);
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
            return this;
        }

        public void close() {
            flush();
            try {
                os.close();
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }

        public String toString() {
            return cache.toString();
        }

    }

    static class SequenceUtils {
        public static void swap(int[] data, int i, int j) {
            int tmp = data[i];
            data[i] = data[j];
            data[j] = tmp;
        }

    }

    static class IntegerFlow {
        public static <T extends IntegerFlowEdge> void send(T edge, int flow) {
            edge.flow += flow;
            edge.rev.flow -= flow;
        }

        public static IntegerFlowEdge addFlowEdge(List[] g, int s, int t, int cap) {
            IntegerFlowEdge real = new IntegerFlowEdge(t, 0, true);
            IntegerFlowEdge virtual = new IntegerFlowEdge(s, cap, false);
            real.rev = virtual;
            virtual.rev = real;
            g[s].add(real);
            g[t].add(virtual);
            return real;
        }

        public static <T extends IntegerFlowEdge> void bfsForFlow(List<T>[] g, int s, int[] dist, int inf, IntegerDeque deque) {
            Arrays.fill(dist, 0, g.length, inf);
            dist[s] = 0;
            deque.clear();
            deque.addLast(s);
            while (!deque.isEmpty()) {
                int head = deque.removeFirst();
                for (T e : g[head]) {
                    if (!DigitUtils.equal(e.flow, 0) && dist[e.to] == inf) {
                        dist[e.to] = dist[head] + 1;
                        deque.addLast(e.to);
                    }
                }
            }
        }

    }

    static interface IntegerComparator {
        public int compare(int a, int b);

    }

    static class ACAutomaton2 {
        public int[][] next;
        public int[] fails;
        private int minChar;
        private int maxChar;
        private int allocIndicator;
        private int range;
        public int[] terminals;
        public BitSet[] input;
        public int buildLast;
        public int matchLast;

        public void init() {
            allocIndicator = 1;
        }

        private int alloc() {
            return allocIndicator++;
        }

        public ACAutomaton2(int minChar, int maxChar, int cap) {
            this.minChar = minChar;
            this.maxChar = maxChar;
            range = maxChar - minChar + 1;
            next = new int[range][cap + 1];
            fails = new int[cap + 1];
            input = new BitSet[cap + 1];
            terminals = new int[cap + 1];
            init();
        }

        public void prepareBuild() {
            buildLast = 0;
        }

        public void prepareMatch() {
            matchLast = 0;
        }

        public void build(int c) {
            c -= minChar;
            if (next[c][buildLast] == 0) {
                next[c][buildLast] = alloc();
            }
            buildLast = next[c][buildLast];
        }

        public void match(int c) {
            c -= minChar;
            matchLast = next[c][matchLast];
        }

        public int[] endBuild() {
            int[] dq = new int[allocIndicator];
            int dqTail = 1;
            int dqHead = 1;
            fails[0] = -1;
            for (int i = 0; i < range; i++) {
                if (next[i][0] != 0) {
                    dq[dqTail++] = next[i][0];
                    fails[next[i][0]] = 0;
                }
            }

            while (dqHead < dqTail) {
                int head = dq[dqHead++];
                terminals[head] = input[fails[head]] != null ? fails[head] : terminals[fails[head]];
                if (input[head] == null) {
                    input[head] = input[terminals[head]];
                }
                for (int i = 0; i < range; i++) {
                    if (next[i][head] != 0) {
                        dq[dqTail++] = next[i][head];
                        int fail = visit(fails[head], i);
                        if (fail == -1) {
                            fail = 0;
                        } else {
                            fail = next[i][fail];
                        }
                        fails[next[i][head]] = fail;
                    }
                }
            }

            assert dqTail == allocIndicator;
            return dq;
        }

        public int visit(int trace, int index) {
            while (trace != -1 && next[index][trace] == 0) {
                trace = fails[trace];
            }
            return trace;
        }

    }

    static class DirectedEdge {
        public int to;

        public DirectedEdge(int to) {
            this.to = to;
        }

        public String toString() {
            return "->" + to;
        }

    }

    static class Graph {
        public static List[] createGraph(int n) {
            return IntStream.range(0, n).mapToObj(i -> new ArrayList<>()).toArray(i -> new List[i]);
        }

    }

    static final class BitSet implements Serializable, Cloneable {
        private long[] data;
        private long tailAvailable;
        private int capacity;
        private int m;
        private static final int SHIFT = 6;
        private static final int LOW = 63;
        private static final int BITS_FOR_EACH = 64;
        private static final long ALL_ONE = ~0L;
        private static final long ALL_ZERO = 0L;
        private static final int MAX_OFFSET = 63;
        private static long[] EMPTY_ARRAY = new long[0];

        public BitSet(int n) {
            capacity = n;
            this.m = (capacity + 64 - 1) / 64;
            data = new long[m];
            tailAvailable = oneBetween(0, offset(capacity - 1));
        }

        public BitSet(BitSet bs) {
            this.data = bs.data.clone();
            this.tailAvailable = bs.tailAvailable;
            this.capacity = bs.capacity;
            this.m = bs.m;
        }

        private BitSet(BitSet bs, int l, int r) {
            this.data = EMPTY_ARRAY;
            copyInterval(bs, l, r);
        }

        public void copyInterval(BitSet bs, int l, int r) {
            capacity = r - l + 1;
            tailAvailable = oneBetween(0, offset(capacity - 1));
            int reqLength = word(r) - word(l) + 1;
            if (data.length >= word(r) - word(l) + 1) {
                System.arraycopy(bs.data, word(l), data, 0, reqLength);
            } else {
                data = Arrays.copyOfRange(bs.data, word(l), word(r) + 1);
            }
            this.m = reqLength;
            leftShift(offset(l));
            this.m = (capacity + 64 - 1) / 64;
            data[m - 1] &= tailAvailable;
            for (int i = m; i < reqLength; i++) {
                data[i] = 0;
            }
        }

        public boolean get(int i) {
            return (data[word(i)] & (1L << offset(i))) != 0;
        }

        public void set(int i) {
            data[word(i)] |= (1L << offset(i));
        }

        private static int word(int i) {
            return i >>> SHIFT;
        }

        private static int offset(int i) {
            return i & LOW;
        }

        private long oneBetween(int l, int r) {
            if (r < l) {
                return 0;
            }
            long lBegin = 1L << offset(l);
            long rEnd = 1L << offset(r);
            return (ALL_ONE ^ (lBegin - 1)) & ((rEnd << 1) - 1);
        }

        public int capacity() {
            return capacity;
        }

        public void or(BitSet bs) {
            int n = Math.min(this.m, bs.m);
            for (int i = 0; i < n; i++) {
                data[i] |= bs.data[i];
            }
        }

        public int nextSetBit(int start) {
            int offset = offset(start);
            int w = word(start);
            if (offset != 0) {
                long mask = oneBetween(offset, MAX_OFFSET);
                if ((data[w] & mask) != 0) {
                    return Long.numberOfTrailingZeros(data[w] & mask) + w * BITS_FOR_EACH;
                }
                w++;
            }

            while (w < m && data[w] == ALL_ZERO) {
                w++;
            }
            if (w >= m) {
                return capacity();
            }
            return Long.numberOfTrailingZeros(data[w]) + w * BITS_FOR_EACH;
        }

        public void leftShift(int n) {
            int wordMove = word(n);
            int offsetMove = offset(n);
            int rshift = MAX_OFFSET - (offsetMove - 1);

            if (offsetMove != 0) {
                //slightly
                for (int i = 0; i < m; i++) {
                    if (i > 0) {
                        data[i - 1] |= data[i] << rshift;
                    }
                    data[i] >>>= offsetMove;
                }
            }
            if (wordMove > 0) {
                for (int i = 0; i < m; i++) {
                    if (i >= wordMove) {
                        data[i - wordMove] = data[i];
                    }
                    data[i] = 0;
                }
            }
        }

        public BitSet clone() {
            return new BitSet(this);
        }

        public String toString() {
            StringBuilder builder = new StringBuilder("{");
            for (int i = nextSetBit(0); i < capacity(); i = nextSetBit(i + 1)) {
                builder.append(i).append(',');
            }
            if (builder.length() > 1) {
                builder.setLength(builder.length() - 1);
            }
            builder.append("}");
            return builder.toString();
        }

        public int hashCode() {
            int ans = 1;
            for (int i = 0; i < m; i++) {
                ans = ans * 31 + Long.hashCode(data[i]);
            }
            return ans;
        }

        public boolean equals(Object obj) {
            if (!(obj instanceof BitSet)) {
                return false;
            }
            BitSet other = (BitSet) obj;
            if (other.capacity != capacity) {
                return false;
            }
            for (int i = 0; i < m; i++) {
                if (other.data[i] != data[i]) {
                    return false;
                }
            }
            return true;
        }

    }

    static class IntegerFlowEdge<T extends IntegerFlowEdge<T>> extends DirectedEdge {
        public int flow;
        public boolean real;
        public T rev;

        public IntegerFlowEdge(int to, int flow, boolean real) {
            super(to);
            this.flow = flow;
            this.real = real;
        }

        public String toString() {
            return rev.to + "-[" + flow + "/" + (flow + rev.flow) + "]->" + to;
        }

    }

    static class DigitUtils {
        private DigitUtils() {
        }

        public static boolean equal(int a, int b) {
            return a == b;
        }

    }
}

