import java.util.*;

public class Permutations {

	public static boolean nextPermutation(int[] p) {
		for (int a = p.length - 2; a >= 0; --a)
			if (p[a] < p[a + 1])
				for (int b = p.length - 1; ; --b)
					if (p[b] > p[a]) {
						int t = p[a];
						p[a] = p[b];
						p[b] = t;
						for (++a, b = p.length - 1; a < b; ++a, --b) {
							t = p[a];
							p[a] = p[b];
							p[b] = t;
						}
						return true;
					}
		return false;
	}

	public static int[] permutationByNumber(int n, long number) {
		long[] fact = new long[n];
		fact[0] = 1;
		for (int i = 1; i < n; i++) {
			fact[i] = i * fact[i - 1];
		}
		int[] p = new int[n];
		int[] free = new int[n];
		for (int i = 0; i < n; i++) {
			free[i] = i;
		}
		for (int i = 0; i < n; i++) {
			int pos = (int) (number / fact[n - 1 - i]);
			p[i] = free[pos];
			System.arraycopy(free, pos + 1, free, pos, n - 1 - pos);
			number %= fact[n - 1 - i];
		}
		return p;
	}

	public static long numberByPermutation(int[] p) {
		int n = p.length;
		long[] fact = new long[n];
		fact[0] = 1;
		for (int i = 1; i < n; i++) {
			fact[i] = i * fact[i - 1];
		}
		long res = 0;
		for (int i = 0; i < n; i++) {
			int a = p[i];
			for (int j = 0; j < i; j++) {
				if (p[j] < p[i]) {
					--a;
				}
			}
			res += a * fact[n - 1 - i];
		}
		return res;
	}

	public static void generatePermutations(int[] p, int depth) {
		int n = p.length;
		if (depth == n) {
			System.out.println(Arrays.toString(p));
			return;
		}
		for (int i = 0; i < n; i++) {
			if (p[i] == 0) {
				p[i] = depth;
				generatePermutations(p, depth + 1);
				p[i] = 0;
			}
		}
	}

	public static long nextPermutation(long x) {
		long s = x & -x;
		long r = x + s;
		long ones = x ^ r;
		ones = (ones >> 2) / s;
		return r | ones;
	}

	public static List<List<Integer>> decomposeIntoCycles(int[] p) {
		int n = p.length;
		boolean[] vis = new boolean[n];
		List<List<Integer>> res = new ArrayList<>();
		for (int i = 0; i < n; i++) {
			if (vis[i])
				continue;
			int j = i;
			List<Integer> cur = new ArrayList<>();
			do {
				cur.add(j);
				vis[j] = true;
				j = p[j];
			} while (j != i);
			res.add(cur);
		}
		return res;
	}

	// Usage example
	public static void main(String[] args) {
		// print all permutations method 1
		generatePermutations(new int[2], 1);

		// print all permutations method 2
		int[] p = {0, 1, 2};
		int cnt = 0;
		do {
			System.out.println(Arrays.toString(p));
			if (!Arrays.equals(p, permutationByNumber(p.length, numberByPermutation(p))) ||
					cnt != numberByPermutation(permutationByNumber(p.length, cnt)))
				throw new RuntimeException();
			++cnt;
		} while (nextPermutation(p));

		System.out.println(5 == numberByPermutation(p));
		System.out.println(Arrays.equals(new int[]{1, 0, 2}, permutationByNumber(3, 2)));

		System.out.println(0b1101 == nextPermutation(0b1011));
		System.out.println(decomposeIntoCycles(new int[]{0, 2, 1, 3}));
	}
}
