Problem:
G: 恋のジュンレツRun!Run!Run! - Love Permutation, Run run run! -

物語

おおきなジュンレツ らんらんらんでぶー♪
Hello, 星空蘭にゃ！
好きなデータ構造は Starry Sky Tree にゃ！

蘭は最近物理学科に入学したんだけど、どうやらそこでもプログラミングをやらないといけないらしいんだ。
蘭、アルゴリズムやデータ構造の理論は好きなんだけど、実装はどうも苦手なんだよね……
だいたい蘭達は人間なのに、どうして機械の言葉を勉強しなくちゃいけないの！？

とはいえ、課題をやらないことには単位が出ないしやるしかないにゃ。
今回出た課題は順列の run とかいうのが関係しているらしいんだー。
この問題、明らかに作者がタイトル一発ネタで考えてるのが見え見えにゃ、ちょっと寒くないかにゃー。
とにかく、プログラミングが得意なあなたに手伝ってもらえたら、テンション上がるにゃー！
それじゃあ問題、行っくにゃ〜！

問題

長さKの数列aが1 \leq a_i \leq K (1 \leq i \leq K) かつa_i \neq a_j (1 \leq i < j \leq K) を満たすとき、aは長さKの順列であるという。

ここで順列のパターンマッチングを以下のように定義する。
テキスト順列qがパターン順列pにマッチするとは、pと相対順序が一致するような、pと同じ長さのqの (連続とは限らない) 部分列が存在することをいう。
より厳密には、qの長さをN、pの長さをMとしたとき、qがpにマッチするとは、ある条件を満たす添え字列 1 \leq i_1 < ... < i_M \leq Nが存在することである。その条件とは、p_x < p_y (1 \leq x<y \leq M) ならば、かつそのときに限りq_{i_x} < q_{i_y}となることである。
例えば、順列(3, 4, 2, 1, 5)は順列(2, 1, 3)にマッチする。なぜならば、添え字列(1, 4, 5)が上記の条件を満たすからである。

さらに、順列の run を定義する。
順列のrunとは、単調増加、あるいは単調減少な極大連続部分列である。すなわち、run は連続部分列 a_l, ..., , a_r (l<r) のうち、a_i < a_{i+1} (l \leq i < r) (a_i > a_{i+1} (l \leq i < r)) を満たし、かつこの区間を真に包含する連続区間からなる run が存在しないものを言う。
例えば、順列(3, 4, 2, 1, 5)は(3, 4), (4, 2, 1), (1, 5)という3つのrunを持つ。

長さNのテキスト順列qと長さMのパターン順列pが与えられる。
ここで、qは必ずちょうど3つだけの run を持つことが保証される。
qがpにマッチするかどうかを判定せよ。

入力形式

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

N
q_1 ... q_N
M
p_1 ... p_M

入力は全て整数からなる。
1行目にはテキストとなる順列qの長さNが与えられる。
続く2行目はN個の整数が空白区切りで与えられ、i (1 \leq i \leq N) 番目の整数はqのi番目の要素q_iを表す。
3行目にはパターンとなる順列pの長さMが与えられる。
続く4行目はM個の整数が空白区切りで与えられ、j (1 \leq j \leq M) 番目の整数はpのj番目の要素p_jを表す。

制約

4 \leq N \leq 10^5

1 \leq M \leq N

q, pはそれぞれ長さN, Mの順列である。

qが持つ run の数はちょうど3。

出力形式

順列qが順列pにマッチするとき"Yes"、そうでなければ"No"と1行に出力せよ。

入力例1

5
3 4 2 1 5
3
1 2 3

出力例1

Yes

入力例2

5
3 5 4 1 2
3
1 2 3

出力例2

No

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;

class Program
{
    static void Main()
    {
        n = int.Parse(Console.ReadLine());
        var q = Console.ReadLine().Split().Select(int.Parse).ToArray();
        m = int.Parse(Console.ReadLine());
        var p = Console.ReadLine().Split().Select(int.Parse).ToArray();
        if (m == 1)
        {
            Console.WriteLine("Yes");
            return;
        }
        chgp = new List<int>();
        chgq = new List<int>();
        int c = chkrun(p, out chgp);
        chkrun(q, out chgq);
        if (c > 2 || c == 2 && (q[0] < q[1]) != (p[0] < p[1]))
        {
            Console.WriteLine("No");
            return;
        }
        if (c == 0)
        {
            Console.WriteLine(sol1(q, p) ? "Yes" : "No");
        }
        if (c == 1)
        {
            Console.WriteLine(sol2(q, p) ? "Yes" : "No");
        }
        if (c == 2)
        {
            Console.WriteLine(sol3(q, p) ? "Yes" : "No");
        }
    }
    static int n, m;
    static int[] revlr(int[] a)
    {
        var ret = new int[a.Length];
        for (int i = 0; i < a.Length; i++)
        {
            ret[i] = a[a.Length - 1 - i];
        }
        return ret;
    }
    static int[] revud(int[] a)
    {
        var ret = new int[a.Length];
        for (int i = 0; i < a.Length; i++)
        {
            ret[i] = a.Length - a[i] + 1;
        }
        return ret;
    }
    static bool sol1(int[] q, int[] p)
    {
        int c = 0;
        if (p[0] > p[1])
        {
            q = revlr(q);
            p = revlr(p);
        }
        var dp = new int[n];
        for (int i = 0; i < n; i++)
        {
            dp[i] = (int)1e9;
        }
        for (int i = 0; i < n; i++)
        {
            int j = lowerbound(dp, q[i]);
            dp[j] = q[i];
        }
        c = lowerbound(dp, (int)1e9 - 10);
        if (c >= m)
        {
            return true;

        }
        return false;
    }
    static bool sol2(int[] q, int[] p)
    {
        if (p[0] > p[1])
        {
            p = revud(p);
            q = revud(q);
        }
        if (q[0] > q[1])
        {
            p = revlr(p);
            q = revlr(q);
        }
        var sp1 = new Stack<int>();
        var sp2 = new Stack<int>();
        var sq1 = new Stack<int>();
        var sq2 = new Stack<int>();
        for (int i = 0; i <= chgp[0]; i++)
        {
            sp1.Push(p[i]);
        }
        for (int i = m - 1; i > chgp[0] ; i--)
        {
            sp2.Push(p[i]);
        }
        for (int i = 0; i <= chgq[0]; i++)
        {
            sq1.Push(q[i]);
        }
        for (int i = chgq[1]; i > chgq[0] ; i--)
        {
            sq2.Push(q[i]);
        }
        while (sp1.Count + sp2.Count > 0)
        {
            int p1 = 0, p2 = 0;
            if (sp2.Count == 0)
            {
                p1 = sp1.Pop();
                p2 = -1;
            }
            if (sp1.Count == 0)
            {
                p2 = sp2.Pop();
                p1 = -1;
            }
            if (p1 > p2)
            {
                if (sq1.Count == 0)
                {
                    return false;
                }
                int use = sq1.Pop();
                while (sq2.Count > 0)
                {
                    int aa = sq2.Pop();
                    if (aa < use)
                    {
                        sq2.Push(aa);
                        break;
                    }
                }
            }
            else
            {
                if (sq2.Count == 0)
                {
                    return false;
                }
                int use = sq2.Pop();
                while (sq1.Count > 0)
                {
                    int aa = sq1.Pop();
                    if (aa < use)
                    {
                        sq1.Push(aa);
                        break;
                    }
                }
            }
        }
        return true;
    }
    static bool sol3(int[] q, int[] p)
    {
        if (q[0] > q[1])
        {
            p = revlr(p);
            q = revlr(q);
        }
        var sp1 = new Stack<int>();
        var sp2 = new Stack<int>();
        var sp3 = new Stack<int>();
        var sq1 = new Stack<int>();
        var sq2 = new Stack<int>();
        var sq3 = new Stack<int>();
        for (int i = 0; i <= chgp[0]; i++)
        {
            sp1.Push(p[i]);
        }
        for (int i = chgp[1] - 1; i > chgp[0] ; i--)
        {
            sp2.Push(p[i]);
        }
        for (int i = chgp[1]; i < m; i++)
        {
            sp3.Push(p[i]);
        }
        for (int i = 0; i <= chgq[0]; i++)
        {
            sq1.Push(q[i]);
        }
        for (int i = chgq[1] - 1; i > chgq[0] ; i--)
        {
            sq2.Push(q[i]);
        }
        for (int i = chgq[1]; i < n; i++)
        {
            sq3.Push(q[i]);
        }
        while (sp1.Count + sp2.Count + sp3.Count > 0)
        {
            int p1 = -1, p2 = -1, p3 = -1;
            if (sp1.Count > 0)
            {
                p1 = sp1.Pop();
            }
            if (sp2.Count > 0)
            {
                p2 = sp2.Pop();
            }
            if (sp3.Count > 0)
            {
                p3 = sp3.Pop();
            }
            if (p1 > p2 && p1 > p3)
            {
                if (sq1.Count == 0)
                {
                    return false;
                }
                int use = sq1.Pop();
                while (sq2.Count > 0)
                {
                    int aa = sq2.Pop();
                    if (aa < use)
                    {
                        sq2.Push(aa);
                        break;
                    }
                }
                while (sq3.Count > 0)
                {
                    int aa = sq3.Pop();
                    if (aa < use)
                    {
                        sq3.Push(aa);
                        break;
                    }
                }
            }
            else if (p2 > p1 && p2 > p3)
            {
                if (sq2.Count == 0)
                {
                    return false;
                }
                int use = sq2.Pop();
                while (sq1.Count > 0)
                {
                    int aa = sq1.Pop();
                    if (aa < use)
                    {
                        sq1.Push(aa);
                        break;
                    }
                }
                while (sq3.Count > 0)
                {
                    int aa = sq3.Pop();
                    if (aa < use)
                    {
                        sq3.Push(aa);
                        break;
                    }
                }
            }
            else
            {
                if (sq3.Count == 0)
                {
                    return false;
                }
                int use = sq3.Pop();
                while (sq1.Count > 0)
                {
                    int aa = sq1.Pop();
                    if (aa < use)
                    {
                        sq1.Push(aa);
                        break;
                    }
                }
                while (sq2.Count > 0)
                {
                    int aa = sq2.Pop();
                    if (aa < use)
                    {
                        sq2.Push(aa);
                        break;
                    }
                }
            }
        }
        return true;
    }
    static int lowerbound(int[] a, int n)
    {
        int l = 0, r = a.Length - 1;
        while (l < r)
        {
            int m = (l + r) / 2;
            if (a[m] < n)
            {
                if (a[m + 1] >= n) return m + 1;
                l = m + 1;
            }
            else
                r = m - 1;
        }
        if (a[l] < n) return l + 1;
        return l;
    }
    static List<int> chgp, chgq;
    static int chkrun(int[] p, out List<int> l)
    {
        int c = 0;
        l = new List<int>();
        for (int i = 1; i < p.Length - 1; i++)
        {
            if (p[i - 1] < p[i] && p[i] > p[i + 1])
            {
                l.Add(i);
                ++c;
            }
            if (p[i - 1] > p[i] && p[i] < p[i + 1])
            {
                l.Add(i);
                ++c;
            }
        }
        return c;
    }
}