Problem:
I: 偶奇ソート

問題文

$0$ から $N-1$ までの整数を並び替えた長さ $N$ の順列 $P$ が与えられます。

以下の操作を最大 $30$ 回まで行って、 $P$ を昇順に並べ替えてください。

操作

$1$ 回の操作では、次の 1 から 4 を順に行う。

0 と 1 からなる長さ $N$ の文字列 $S$ と、整数 $t$ ( $t = 0$ または $t = 1$ ) を宣言する。

空の数列 $A, B$ を用意し、整数 $i$ を $1$ から $N$ まで動かしながら以下を行う。

$S_i$ が 0 のとき、何もしない。

$S_i$ が 1 のとき、

$P_i$ が偶数ならば $A$ の末尾に $P_i$ を追加する。

$P_i$ が奇数ならば $B$ の末尾に $P_i$ を追加する。

数列 $C$ を以下のように定義する。

$t = 0$ のとき、 $C$ は $A$ と $B$ をこの順に連結したものとする。

$t = 1$ のとき、 $C$ は $B$ と $A$ をこの順に連結したものとする。

整数 $i$ を $1$ から $N$ まで動かしながら以下を行う。

$S_i$ が 0 のとき、何もしない。

$S_i$ が 1 のとき、 $P_i$ を $C$ の先頭の要素に置き換え、 $C$ の先頭の要素を消す。

例えば、$N = 7, P = {0, 4, 2, 3, 6, 5, 1}$ とします。

$S$ を "1101101" とし、$t = 1$ とした操作を $1$ 回行うと、以下の図のように $P = {3, 1, 2, 0, 4, 5, 6}$ となります。

制約

$1 \leq N \leq 15000$

$P$ は $0$ から $N-1$ までの整数を並び替えた順列

入力

入力は以下の形式で標準入力から与えられる。

$N$
$P_1$ $P_2$ $\ldots$ $P_N$

出力

$30$ 回以内の操作で $P$ を昇順に並べ替えるような操作列の $1$ つを以下の形式で出力せよ。このような操作列は複数存在するかもしれないが、どれを出力しても正答となる。

$1$ 行目には、操作を行う回数 $K$ を出力せよ。ただし、 $0 \le K \le 30$ でなければならない。

$i + 1$ 行目 $(1 \le i \le K)$ には、 $i$ 回目の操作で宣言する整数 $t_i (t_i = 0,1)$ および長さ $N$ の文字列 $S_i$ をこの順に出力せよ。

$K$
$t_1$ $S_1$
$t_2$ $S_2$
$\vdots$
$t_K$ $S_K$

入力例1

7
0 4 2 3 6 5 1

出力例1

1
1 0100101

操作を行うと、$A = { 4, 6 }, B = { 1 }$ となり、 $t = 1$ より $C = { 1, 4, 6 }$ となります。

$P$ の要素を $C$ によって置き換えると、 $P = { 0, 1, 2, 3, 4, 5, 6 }$ となるので、この操作で $P$ を昇順に並べ替えることができます。

入力例2

4
1 0 3 2

出力例2

2
0 1100
0 0011

例えば以下のような出力も正答となります。

2
0 1111
1 0110

入力例3

1
0

出力例3

0

操作を行わなくても構いません。

Solution in C# (judge verdict: Accepted)

#undef DEBUG
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static System.Math;
using MethodImplAttribute = System.Runtime.CompilerServices.MethodImplAttribute;
using MethodImplOptions = System.Runtime.CompilerServices.MethodImplOptions;

public static class P
{
    static int n;
    static int[] p;
    static List<Operation> Operations = new List<Operation>();
    public static void Main()
    {
        n = int.Parse(Console.ReadLine());
        p = Console.ReadLine().Split().Select(int.Parse).ToArray();
        if (n % 2 == 1)
        {
            var ind = Array.IndexOf(p, n - 1);
            if (ind == n - 1) goto end;
            if (p.Last() % 2 == 0)
            {
                var op = new bool[n];
                op[n - 1] = true;
                op[Array.FindIndex(p, x => x % 2 == 1)] = true;
                //op 1
                ExecuteOperation(new Operation() { Kind = Kind.EvenOdd, tf = op });
            }
            { 
                var op = new bool[n];
                op[n - 1] = true;
                op[ind] = true;
                //op 2
                ExecuteOperation(new Operation() { Kind = Kind.OddEven, tf = op });
            }
        }end:;
        var half = n / 2;
        int[] final = new int[half * 2];
        //even init
        var normalEven = 0;
        var overEven = half % 2 == 0 ? half : half + 1;
        var normalOdd = 1;
        var overOdd = half % 2 == 1 ? half : half + 1;
        for (int i = 0; i < half; i++)
        {
            if (i % 2 == 0) final[i] = (normalEven += 2) - 2;
            else final[i] = (overEven += 2) - 2;
        }
        //odd init
        for (int i = half; i < half * 2; i++)
        {
            if (i % 2 == 0) final[i] = (normalOdd += 2) - 2;
            else final[i] = (overOdd += 2) - 2;
        }

        var numberToFinalIndex = new int[half * 2];
        for (int i = 0; i < final.Length; i++)
        {
            numberToFinalIndex[final[i]] = i;
        }

        //op 3
        var allOp = new Operation();
        {
            var op = new bool[n];
            for (int i = 0; i < half * 2; i++)
                op[i] = true;
            allOp = new Operation() { Kind = Kind.EvenOdd, tf = op };
            ExecuteOperation(allOp);
        }
        //op 4-29
        for (int i = 0; i < 13; i++)
        {
            var op = new bool[n];

            //even
            for (int j = 0; j < half; j++)
            {
                var relativeInd = numberToFinalIndex[p[j]];
                if ((relativeInd >> i & 1) == 1) op[j] = true;
            }
            //odd
            for (int j = half; j < half * 2; j++)
            {
                var relativeInd = 2 * half - 1 - numberToFinalIndex[p[j]];
                if ((relativeInd >> i & 1) == 1) op[j] = true; 
            }
            ExecuteOperation(new Operation()
            {
                Kind = Kind.OddEven,
                tf = op
            });
            ExecuteOperation(allOp);
        }
        //op 30
        {
            var op = new bool[n];
            for (int j = 0; j < half; j++)
            {
                if (j % 2 == 1) op[j] = true;
            }
            //odd
            for (int j = half; j < half * 2; j++)
            {
                if (j % 2 == 0) op[j] = true;
            }
            ExecuteOperation(new Operation()
            {
                Kind = Kind.OddEven,
                tf = op
            });
        }
        Console.WriteLine(Operations.Count);
        foreach (var item in Operations)
        {
            Console.WriteLine($"{(int)item.Kind} {string.Join("", item.tf.Select(x => x ? '1' : '0'))}");
        }
    }
    static void ExecuteOperation(Operation operation)
    {
#if DEBUG
        Console.WriteLine($"{(int)operation.Kind} {string.Join("", operation.tf.Select(x => x ? '1' : '0'))}");
#endif
        List<int> odd = new List<int>();
        List<int> even = new List<int>();
        Operations.Add(operation);
        for (int i = 0; i < n; i++)
        {
            if (!operation.tf[i]) continue;
            (p[i] % 2 == 0 ? even : odd).Add(p[i]);
        }
        var c = operation.Kind == Kind.OddEven ? odd.Concat(even) : even.Concat(odd);
        int ptr = 0;
        foreach (var item in c)
        {
            while (!operation.tf[ptr]) ptr++;
            p[ptr++] = item;
        }
#if DEBUG
        Console.WriteLine(string.Join(" ", p));
#endif  
    }
}

class Operation
{
    public Kind Kind;
    public bool[] tf;
}

enum Kind
{
    EvenOdd = 0,
    OddEven = 1
}