using System.ComponentModel; using System.Reflection.Metadata.Ecma335; using System.Runtime.CompilerServices; using System.Security.Cryptography; namespace test { internal class Program { static void Main(string[] args) { cin = new input(); mod = new mod(998244353); toolbox = new toolbox(); Priority_Queue = new Priority_Queue(true); var sw = new System.IO.StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false }; Console.SetOut(sw); toolbox.StartTimer(); int n=cin.intreed(); int p=cin.intreed(); int q=cin.intreed(); var arr=cin.arrayint(n); int ans=0; for(int i=0; i where T2 : struct, IComparable { //1indexだよ!!!! 例[1,5,8,9,5,5]=>[1,2,3,4,2,2] public Dictionary key2raw; public Dictionary raw2key; //やりたいこと 構築 生=>圧縮後 圧縮後=>生 public Compress(IEnumerable vector = null) { key2raw = new Dictionary(); raw2key = new Dictionary(); if (vector is { }) Build(vector); } public (List, IOrderedEnumerable) Build(IEnumerable vector) { int cnt = 0; var back = new List(); var sorted = vector.OrderBy(i => i); foreach (var i in sorted) { if (!raw2key.ContainsKey(i)) { cnt++; raw2key.Add(i, cnt); key2raw.Add(cnt, i); } } foreach (var i in vector) back.Add(raw2key[i]); return (back, sorted); } //インデクサは圧縮後=>生 public T2 this[int k] => key2raw[k]; public int Count => key2raw.Count; } //treeのnodesizeは要素数に応じて決定 1e5なら3*1e6,2*1e5なら5*1e6 5*1e5なら2*1e7 public class SegmentTree { //たまには1indexで書いてみたくないですか? 書きたい //とりあえずrange sum internal struct node { //index=0のnodeはnullを表す public int cnt;//この値の数 public long sum;//cnt*(圧縮前のこの値) public int left; public int right; public node(int a) => cnt = a; public node() { cnt = 0; left = 0; right = 0; sum = 0; } } public List roots;//roots[i]=>バージョンiのrootのインデックス root[0]は0が入っている internal node[] nodes; internal int size; public int now_index; //5*1e5回のsetをすると、nodesizeは2*1e7でギリギリ(400MB程度) 5*1e7でも速度的には大丈夫だけど、メモリがやばい(900MBギリ下回るぐらい)  public SegmentTree(int n, int nodesize = 2 * (int)1e7) { size = 1; while (size < n) size <<= 1; nodes = Enumerable.Repeat(new node(), nodesize).ToArray(); now_index = 2; roots = [0, 1]; } /// /// /// /// 加算する値 /// 加算する位置(1index) /// そのノードが担当する圧縮間の、真の値 /// /// public int add(int cnt, int index, long real_val, int version = 1) { int root = add(cnt, index, roots[version], real_val, 1, size + 1); if (root == -1) return -1; roots.Add(root); return roots.Count - 1; } /// /// /// /// 加算する値 /// 加算する位置(1index) /// 現在のノード /// そのノードが担当する圧縮間の、真の値 /// 現在のノードが担当する範囲の左側(閉区間) /// 右側(開区間) /// 更新後の木のversion private int add(int cnt, int index, int node_index, long real_val, int l, int r) { if (index < l || r <= index) return -1; int now = newnode(); nodes[now] = nodes[node_index]; if (l + 1 == r) { nodes[now].cnt += cnt; nodes[now].sum = real_val * nodes[now].cnt; return now; } int mid = (l + r) >> 1; if (index < mid) { int left = add(cnt, index, nodes[node_index].left, real_val, l, mid); if (left == -1) return -1; nodes[now].left = left; } else { int right = add(cnt, index, nodes[node_index].right, real_val, mid, r); if (right == -1) return -1; nodes[now].right = right; } nodes[now].cnt = nodes[nodes[now].left].cnt + nodes[nodes[now].right].cnt; nodes[now].sum = nodes[nodes[now].left].sum + nodes[nodes[now].right].sum; return now; } /// /// [a,b)のsumのsum /// /// /// /// /// public long sum(int l, int r, int version = 1) => sum(l, r, roots[version], 1, size + 1); private long sum(int a, int b, int node_index, int l, int r) { if (node_index == 0) return 0;//nullノード if (b <= l || r <= a) return 0;//範囲外 if (a <= l && r <= b) return nodes[node_index].sum;//完全被覆 int mid = (l + r) >> 1; long left = sum(a, b, nodes[node_index].left, l, mid); long right = sum(a, b, nodes[node_index].right, mid, r); return left + right; } /// /// [l,r) 個数について /// /// /// /// /// public int query(int l, int r, int version = 1) => query(l, r, roots[version], 1, size + 1); private int query(int a, int b, int node_index, int l, int r) { if (node_index == 0) return 0;//nullノード if (b <= l || r <= a) return 0;//範囲外 if (a <= l && r <= b) return nodes[node_index].cnt;//完全被覆 int mid = (l + r) >> 1; int left = query(a, b, nodes[node_index].left, l, mid); int right = query(a, b, nodes[node_index].right, mid, r); return left + right; } /// /// 1index 単独の個数について /// /// /// /// public int get(int index, int version = 1) { int l = 1; int r = size + 1; int now = roots[version]; while (true) { if (now == 0) return 0;//nullノード if (index < l || r <= index) return 0; if (l + 1 == r) return nodes[now].cnt; int mid = (l + r) >> 1; if (index < mid) { now = nodes[now].left; r = mid; } else { now = nodes[now].right; l = mid; } } } private int newnode() => now_index++; } public SegmentTree tree; public Compress comp; public List rows;//重複を排除した座標圧縮前の配列の要素全て(ソート済み) private const int NodePoolMargin = 100; public ThisIsNotAWavelet_Matrix(IEnumerable arr) { //座標圧縮してから構築する comp = new Compress(); var comped = comp.Build(arr); var arr_list = arr.ToList(); int nodesize = GetNodePoolSize(); tree = new SegmentTree(comp.Count + 1, nodesize); int version = 1; for (int i = 0; i < arr_list.Count; i++) { version = tree.add(1, comped.Item1[i], arr_list[i], version); } rows = comped.Item2.Distinct().ToList(); int GetNodePoolSize() { int n = comped.Item1.Count; int k = comp.Count+1; int size = 1; int height = 0; while (size < k) { size <<= 1; height++; } height++; return 2 + n * height + NodePoolMargin;//2(nullと初期ノード)+n*(add1回で作らないといけないノード数<=>木の高さ)+マージン } } //区間[a,b)でk番目に大きい値を取得する public long GetKthLargest(int a, int b, int k) { //root[b]とroot[a]を見比べればいい varsion=1は全て0の状態 version=2がarrの最初の要素を入れた状態であることに注意せよ つまり、versionは1ずれている if (a < 1 || b < 1 || a >= b) return -1;//区間が不正 if (b > tree.roots.Count - 1) return -1;//範囲外 long total = tree.nodes[tree.roots[b]].cnt - tree.nodes[tree.roots[a]].cnt; if (k <= 0 || total < k) return -1;//そんな要素ないです //今見てるノード int node_a = tree.roots[a]; int node_b = tree.roots[b]; //今見てる区間 int l = 1; int r = tree.size + 1; while (l + 1 != r) { int left_a = tree.nodes[node_a].left; int left_b = tree.nodes[node_b].left; int right_a = tree.nodes[node_a].right; int right_b = tree.nodes[node_b].right; int cnt_right = tree.nodes[right_b].cnt - tree.nodes[right_a].cnt;//この区間の右側にある要素数 int mid = (l + r) >> 1; if (cnt_right >= k) { node_a = right_a; node_b = right_b; l = mid; } else { k -= cnt_right; node_a = left_a; node_b = left_b; r = mid; } } return comp[l]; } //区間[a,b)でk番目に小さい値を返す public long GetKthSmallest(int a, int b, int k) { if (a < 1 || b < 1 || a >= b) return -1;//区間が不正 if (b > tree.roots.Count - 1) return -1;//範囲外 int total = tree.nodes[tree.roots[b]].cnt - tree.nodes[tree.roots[a]].cnt; if (k <= 0 || total < k) return -1;//そんな要素ないです return GetKthLargest(a, b, total - k + 1);//k番目に大きい値に変更して投げる } //区間[a,b)の要素で[x,y)を満たすものの要素を数える a,b,x,yのどれかが不正だと壊れるよ public int RangeFreq(int a, int b, long x, long y) => CountLower(a, b, y) - CountLower(a, b, x); //区間[a,b)の要素でx未満の要素の数を数える public int CountLower(int a, int b, long x) { if (a < 1 || b < 1 || a >= b) return -1;//区間が不正 if (b > tree.roots.Count - 1) return -1;//範囲外 int x_comped = rows.BinarySearch(x); if (x_comped < 0) x_comped = ~x_comped; x_comped++; int l = tree.query(1, x_comped, a);//[1,a)でのクエリ結果 var r = tree.query(1, x_comped, b);//[1,b)でのクエリ結果 //xを圧縮後の世界に飛ばす x未満を数えるから、xを超える最小値を探してきて、それでいい return r - l;//[1,b)-[1,a)=[a,b) } //区間[a,b)でx未満の最大値を返す public long PrevValue(int a, int b, long x) { //サボり実装 int cnt = CountLower(a, b, x);//区間[a,b)でx未満の個数を数える if (cnt <= 0) return -1; return GetKthSmallest(a, b, cnt);//求める値はcnt番目に小さいもの } //区間[a,b)でx以上の最小値を返す public long NextValue(int a, int b, long x) { int cnt = CountLower(a, b, x);//区間[a,b)でx未満の個数を数える if (cnt < 0) return -1; return GetKthSmallest(a, b, cnt + 1);//cnt+1はx以上になる最初の値の順位 } //区間[1,b)でxが登場する回数を返す public int Count(int b, long x) { var index = rows.BinarySearch(x); if (index < 0) return 0;//xは1度も登場しない index++; return tree.get(index, b); } //区間[a,b)でxが登場する回数を返す public int Count(int a, int b, long x) => Count(b, x) - Count(a, x); //区間[a,b)で要素xがi回目に登場するインデックスを返す 計算量O(logN*log(種類数)) public int Select(int a, int b, long x, int cnt) { //xは座標圧縮後であることに注意せよ int Count(int a, int b, int x) => tree.get(x, b) - tree.get(x, a); if (a < 1 || b < 1 || a >= b) return -1;//区間が不正 if (b > tree.roots.Count - 1) return -1;//範囲外 if (cnt <= 0) return -1; var index = rows.BinarySearch(x); if (index < 0) return -1;//そんな要素存在しない index++; int total = Count(a, b, index); if (total < cnt) return -1; int l = a; int r = b; while (l + 1 < r) { int mid = (l + r) >> 1; int left = Count(l, mid, index); if (left >= cnt) { r = mid; } else { l = mid; cnt -= left; } } return l; } //区間[a,b)でx未満の要素のsumを返す public long SumLower(int a, int b, long x) { //負の値が入っていても壊れないように、クエリ失敗は-INFとする if (a < 1 || b < 1 || a >= b) return long.MinValue;//区間が不正 if (b > tree.roots.Count - 1) return long.MinValue;//範囲外 int x_comped = rows.BinarySearch(x); if (x_comped < 0) x_comped = ~x_comped; x_comped++; long l = tree.sum(1, x_comped, a);//[1,a) long r = tree.sum(1, x_comped, b);//[1,b) return r - l;//[1,b)-[1,a)=[a,b) } //区間[a,b)の要素で[x,y)を満たすもののsumを返す public long RangeSum(int a, int b, long x, long y) { long r = SumLower(a, b, y); long l = SumLower(a, b, x); if (r is long.MinValue || l is long.MinValue) return -1; return r - l; } } public class imos { long[,] arr; int x_len;//値域は[0,x_len] int y_len;//値域は[0,y_len] public imos(int n) { x_len = n + 1; y_len = n + 1; arr = new long[x_len + 1, y_len + 1]; } public imos(int x_len, int y_len) { this.x_len = x_len; this.y_len = y_len; arr = new long[x_len + 1, y_len + 1]; } //[x1,x2),[y1,y2)にvalを加算 座標は0~x_len,0~y_lenの範囲で public void set(int x1, int x2, int y1, int y2, long val) { arr[x1, y1] += val; arr[x2, y1] -= val; arr[x1, y2] -= val; arr[x2, y2] += val; } //imos法を実行して結果を返す public long[,] build() { for (int x = 0; x <= x_len; x++) { for (int y = 1; y <= y_len; y++) { arr[x, y] += arr[x, y - 1]; } } for (int x = 1; x <= x_len; x++) { for (int y = 0; y <= y_len; y++) { arr[x, y] += arr[x - 1, y]; } } return arr; } } public class FastTreap { //1-indexです!!!!!! private class node { public long val; public node left;//小さい public node right;//大きい public long cnt;//部分木の大きさ public long same;//このvalが何個入っているのか public int priority;//優先度 public node(long val, int priority, long same, node left = null, node right = null) { this.val = val; this.priority = priority; this.left = left; this.right = right; this.same = same; } public long update() { cnt = same; if (left != null) cnt += left.cnt; if (right != null) cnt += right.cnt; return cnt; } } private node root; private Random rand; public FastTreap(int seed = 998244353) { root = null; rand = new Random(seed); } //内部向け //key未満のノードとkey以上のノードに分割する private void Split(node t, long key, out node left, out node right) { if (t == null) { left = null; right = null; return; } else if (key <= t.val) { //key以上なので、今回のノードと右側部分木は右に行く Split(t.left, key, out left, out t.left); right = t; } else { //key未満なので、今回のノードと右側部分木は右に行く Split(t.right, key, out t.right, out right); left = t; } t.update(); } //左と右を合体した新たな木(t)を作る private void Marge(ref node t, node left, node right) { if (left == null || right == null) { t = left ?? right; } else if (left.priority > right.priority) { //leftの方が優先度高い Marge(ref left.right, left.right, right); t = left; } else { //rightの方が優先度高い Marge(ref right.left, left, right.left); t = right; } if (t != null) t.update(); } private void Insert(ref node t, node item) { if (t == null) { t = item; } else if (t.val == item.val) { t.same += item.same; } else if (item.priority > t.priority) { //itemの方が優先度高い このノードをitemに置き換える 今のノードtはledtかrightに入る Split(t, item.val, out item.left, out item.right); t = item; } else { //こいつは優先度がヒープになることに反するので、下に潜る Insert(ref item.val < t.val ? ref t.left : ref t.right, item); } t.update(); } private void Erase(ref node t, long key, long same) { if (t == null) return; if (t.val == key) { t.same -= same; if (t.same == 0) { //今いるノードを消す このノードを子供をマージしてできた木に置き換える Marge(ref t, t.left, t.right); } } else { //このノードは消したいノードじゃない Erase(ref key < t.val ? ref t.left : ref t.right, key, same); } if (t != null) t.update(); } private bool Find(node t, long key) { if (t == null) return false; if (t.val == key) return true; return Find(key < t.val ? t.left : t.right, key); } private long GetKth(node t, long k) { if (t == null || k < 1 || k > t.cnt) throw new ArgumentOutOfRangeException(nameof(k)); long leftCount = t.left != null ? t.left.cnt : 0; if (k <= leftCount) { return GetKth(t.left, k); } else if (k <= leftCount + t.same) { return t.val; } else { return GetKth(t.right, k - leftCount - t.same); } } //left以上 right未満の世界でk番目に小さい要素を取得する private long GetKth(long l, long r, int k) { // Split は「< key / >= key」 Split(root, l, out node LessThanLeft, out node LeftOrMore); // (=l) Split(LeftOrMore, r, out node inLR, out node MoreThanR); // ([l,r)) と (>=r) if (inLR == null || k < 1 || k > inLR.cnt) throw new ArgumentOutOfRangeException(nameof(k)); var nd = GetKth(inLR, k); // 必ず元に戻す(例外時も含めて復元) node back = null; Marge(ref back, inLR, MoreThanR); // back = (>=l) を復元 Marge(ref root, LessThanLeft, back); // root を復元 return nd; } private long FastGetKth(long l, long r, int k) => GetKth(root, CountLower(l) + k); // 要素 < val の個数を数える(非再帰・O(log N)) private long CountLower(long val) { long cnt = 0; var t = root; while (t != null) { if (t.val < val) { cnt += (t.left?.cnt ?? 0) + t.same; t = t.right; } else { t = t.left; } } return cnt; } // k(1-indexed) 番目のノードを返すワーカー。見つからなければ null private node GetNode(node t, long k) { while (t != null) { long lc = t.left?.cnt ?? 0; if (k <= lc) { t = t.left; } else if (k <= lc + t.same) { return t; } else { k -= lc + t.same; t = t.right; } } return null; } // val 以上の最初の要素のインデックス(1-indexed)。なければ Count()+1 public long LowerBoundIndex(long val) => CountLower(val) + 1; // val より大きい最初の要素のインデックス(1-indexed)。なければ Count()+1 private long UpperBoundIndex(long val) => CountLower(checked(val + 1)) + 1; // ノード版:見つからなければ null private node LowerBoundNode(long val) { long idx = LowerBoundIndex(val); return (idx <= Count()) ? GetNode(root, idx) : null; } private node UpperBoundNode(long val) { long idx = UpperBoundIndex(val); return (idx <= Count()) ? GetNode(root, idx) : null; } //外部向け public void Insert(long key) => Insert(ref root, new node(key, rand.Next(), 1)); public void Insert(long key, long same) => Insert(ref root, new node(key, rand.Next(), same)); public void Erase(long key) => Erase(ref root, key, 1); public void Erase(long key, long same) => Erase(ref root, key, same); public bool Find(long key) => Find(root, key); public long Count() => root?.cnt ?? 0; public long this[int index] => GetKth(root, index); //public long GetKth(long l, long r, int k) => this.GetKth(l, r, k); 名前ぶつかっちゃった 悲しいね public long this[long l, long r, int k] => FastGetKth(l, r, k); public void test() { for (int i = 1; i <= 10; i++) { Insert(i); } Split(root, 5, out var left, out var right); for (int i = 1; i <= 5; i++) { System.Console.WriteLine($"{i},==>{Find(left, i)}"); } System.Console.WriteLine("---"); for (int i = 5; i <= 10; i++) { System.Console.WriteLine($"{i},==>{Find(right, i)}"); } System.Console.WriteLine("==="); Marge(ref root, left, right); for (int i = 1; i <= 10; i++) { System.Console.WriteLine($"{i},==>{Find(root, i)}"); } } } public static class Extensions { public static Dictionary safe_addtion_for_dictionary_int(this Dictionary dic, T key) { if (dic.ContainsKey(key)) dic[key]++; else dic.Add(key, 1); return dic; } public static Dictionary safe_addtion_for_dictionary_long(this Dictionary dic, T key) { if (dic.ContainsKey(key)) dic[key]++; else dic.Add(key, 1); return dic; } public static Dictionary> safe_addtion_for_list_in_dictionary(this Dictionary> dic, T key, T2 value) { if (dic.ContainsKey(key)) dic[key].Add(value); else dic.Add(key, new List() { value }); return dic; } public static T list_pop_back(this List a) { var k = a[a.Count - 1]; a.RemoveAt(a.Count - 1); return k; } public static T chmin(ref this T a, T b) where T : struct, IComparable { if (a.CompareTo(b) > 0) return a = b; else return a; } public static T chmax(ref this T a, T b) where T : struct, IComparable { if (a.CompareTo(b) < 0) return a = b; else return a; } } internal class input { string[] soloinput; int t; public input() { soloinput = new string[0]; t = 0; } public string soloreed() { if (t < soloinput.Length) { return soloinput[t++]; } string input = Console.ReadLine(); while (input == "") { input = Console.ReadLine(); } soloinput = input.Split(" "); t = 0; return soloinput[t++]; } public int intreed() { return int.Parse(soloreed()); } public int[] arrayint(int N) { int[] A = new int[N]; for (int i = 0; i < N; i++) { A[i] = intreed(); } return A; } public long longreed() { return long.Parse(soloreed()); } public long[] arraylong(long N) { long[] A = new long[N]; for (long i = 0; i < N; i++) { A[i] = longreed(); } return A; } public decimal decimalreed() { return decimal.Parse(soloreed()); } public decimal[] arraydecimal(long N) { decimal[] A = new decimal[N]; for (decimal i = 0; i < N; i++) { A[(long)i] = decimalreed(); } return A; } } internal class mod { public long T { get; set; } public mod(long mod = 1000000007) { T = mod; } public long addition(long A, long B) { long C = A + B; return (long)C % T; } public long subtraction(long A, long B) { return ((A % T) - (B % T) + T) % T; } public long multiplication(long A, long B) { return ((A % T) * (B % T)) % T; } } internal class toolbox { string Y = "Yes"; string N = "No"; static input cin; public DateTime? startTime; public toolbox() { cin = new input(); } public long[] CumulativeSum(long[] A, bool mode = true) { if (mode == false) Array.Reverse(A); long[] back = new long[A.Length + 1]; back[0] = 0; for (int i = 1; i <= A.Length; i++) { back[i] = back[i - 1] + A[i - 1]; } if (mode == false) Array.Reverse(A); return back; } public long[] Eratosthenes(long A) { A++; var back = new List(); bool[] ch = new bool[A]; for (int i = 2; i < A; i++) ch[i] = true; for (long i = 2; i < Math.Sqrt(A); i++) { if (ch[i] == true) { back.Add(i); for (long t = 1; i * t < A; t++) { ch[i * t] = false; } } } for (long i = 0; i < A; i++) { if (ch[i] == true) back.Add(i); } return back.Distinct().ToArray(); } public void Swap(ref T a, ref T b) { var i = a; a = b; b = i; } public void LSwap(ref List A, int a, int b) { var i = A[a]; A[a] = A[b]; A[b] = i; } public long Gcd(long A, long B) { while (A != 0) { B %= A; Swap(ref A, ref B); } return B; } public long[] AllDivisors(long N) { var back = new List(); for (int i = 1; Math.Pow(i, 2) <= N; i++) { if (N % i == 0) { back.Add(i); back.Add(N / i); } } return back.Distinct().ToArray(); } public static IEnumerable ExhaustiveEnumeration(IEnumerable indata) { if (indata.Count() == 1) yield return new T[] { indata.First() }; foreach (var i in indata) { var used = new T[] { i }; var unused = indata.Except(used); foreach (var t in ExhaustiveEnumeration(unused)) yield return used.Concat(t).ToArray(); } //How to use //var allpattern = toolbox.ExhaustiveEnumeration(Enumerable.Range(1, N)); } public bool[,] bitallsearch(int N) { bool[,] back = new bool[(int)Math.Pow(2, N), N]; for (int i = 0; i < Math.Pow(2, N); i++) { for (int t = 0; t < N; t++) { var k = (i >> t) & 1; if (k == 1) { back[i, t] = true; } } } return back; } public static int BS(T[] A, T key) where T : IComparable { //このコード、定数倍が大変な事になってるので標準ライブラリを使いましょう(BinarySearch) int left = 0; int right = A.Length; int mid = 0; while (left < right) { mid = (left + right) / 2; if (A[mid].CompareTo(key) == 0) return mid; else if (A[mid].CompareTo(key) > 0) right = mid; else if (A[mid].CompareTo(key) < 0) left = mid + 1; } return -1; } public static int lower_bound(T[] a, T v) { return lower_bound(a, v, Comparer.Default); } public static int lower_bound(T[] A, T key, Comparer v) { int left = 0; int right = A.Length - 1; int mid = 0; var W = 0; while (left <= right) { mid = (left + right) / 2; W = v.Compare(A[mid], key); if (W == -1) left = mid + 1; else right = mid - 1; } return left; } public long[] prime_factorize(long N) { long T = N; var back = new List(); for (long i = 2; i * i <= T; i++) { if (T % i != 0) continue; while (T % i == 0) { back.Add(i); T /= i; } } if (T != 1) back.Add(T); return back.ToArray(); } public long[] One_dimensional_Coordinate_Compression(long[] A) { long[] back = new long[A.Length]; var T = A.Distinct().ToList(); T.Sort(); for (int i = 0; i < A.Length; i++) back[i] = T.BinarySearch(A[i]); return back; } public void setYN(string A = "Yes", string B = "No") { Y = A; N = B; } public void YN(bool ans) { if (ans) Console.WriteLine(Y); else Console.WriteLine(N); } public string[] x_dekakou(int H, int W) { var s = new string[H + 2]; for (int i = 0; i < W + 2; i++) { s[0] += "x"; s[H + 1] += "x"; } for (int i = 1; i < H + 1; i++) { //x場外 .白 #黒 s[i] = "x" + Console.ReadLine().Replace(" ", "") + "x"; } return s; } public List> x_dekakou_string(int H, int W) { var back = new List>(); for (int i = 0; i < H + 2; i++) back.Add(Enumerable.Repeat(-1, W + 2).ToList()); for (int i = 0; i < W + 2; i++) { back[0][i] = -1; back[H + 1][i] = -1; } for (int i = 1; i <= H; i++) { back[i][0] = -1; back[i][W + 1] = -1; for (int t = 1; t <= W; t++) back[i][t] = cin.intreed(); } return back; } /// /// 配列の指定位置以降を反転する /// /// 反転対象の配列 /// 反転開始位置(この位置以降が反転される) private void Reverse(T[] array, int begin) where T : IComparable { // 反転する要素が2個未満の場合は何もしない if (array.Length - begin < 2) return; // 両端から中央に向かって要素を交換 int left = begin; int right = array.Length - 1; while (left < right) { Swap(ref array[left], ref array[right]); left++; right--; } } /// /// 配列を辞書順で次の順列に変更する /// 全ての順列を列挙するには、事前に Array.Sort() でソートした配列を渡すこと /// /// 順列を生成する配列(事前ソート必須) /// 次の順列が存在する場合true、最大順列の場合false public bool NextPermutation(T[] array) where T : IComparable { // 辞書順で次に大きい順列を生成 // 1. 右端から降順でない位置を探す int pivotIndex = -1; for (int i = array.Length - 2; i >= 0; i--) { if (array[i].CompareTo(array[i + 1]) < 0) // 昇順ペア発見 { pivotIndex = i; break; } } // 最大順列に到達している場合 if (pivotIndex == -1) return false; // 2. pivotより大きい最右の要素と交換 for (int j = array.Length - 1; j > pivotIndex; j--) { if (array[pivotIndex].CompareTo(array[j]) < 0) { Swap(ref array[pivotIndex], ref array[j]); break; } } // 3. pivot以降を昇順に並べ直し Reverse(array, pivotIndex + 1); return true; // how to use // do{}while(NextPermutation) } /// /// 回文判定のコア処理(配列版) /// private bool IsPalindromeCore(T[] array, int left, int right) where T : IComparable { while (left < right) { if (array[left].CompareTo(array[right]) != 0) return false; left++; right--; } return true; } /// /// 回文判定のコア処理(文字列版) /// private bool IsPalindromeCore(string str, int left, int right) { while (left < right) { if (str[left] != str[right]) return false; left++; right--; } return true; } /// /// 配列全体が回文かどうかを判定 /// public bool IsPalindrome(T[] array) where T : IComparable { return IsPalindromeCore(array, 0, array.Length - 1); } /// /// 文字列全体が回文かどうかを判定 /// public bool IsPalindrome(string str) { return IsPalindromeCore(str, 0, str.Length - 1); } /// /// 指定範囲が回文かどうかを判定(配列版) /// public bool IsPalindrome(T[] array, int start, int end) where T : IComparable { return IsPalindromeCore(array, start, end); } /// /// 指定範囲が回文かどうかを判定(文字列版) /// public bool IsPalindrome(string str, int start, int end) { return IsPalindromeCore(str, start, end); } /// /// 指定長さの部分配列に回文が含まれるかを判定 /// public bool HasPalindrome(T[] array, int length) where T : IComparable { for (int i = 0; i <= array.Length - length; i++) { if (IsPalindromeCore(array, i, i + length - 1)) return true; } return false; } /// /// 指定長さの部分文字列に回文が含まれるかを判定 /// public bool HasPalindrome(string str, int length) { for (int i = 0; i <= str.Length - length; i++) { if (IsPalindromeCore(str, i, i + length - 1)) return true; } return false; } public long modpow(long x, long p, long mod = 1000000007) { long result = 1; x %= mod; while (p > 0) { if (p % 2 == 1) // pが奇数の場合 { result = (result * x) % mod; } x = (x * x) % mod; // xを二乗(これが繰り返し二乗) p /= 2; // pを半分にする } return result; } public void StartTimer() { startTime = DateTime.Now; } public void PrintElapsedTime(bool error_output = true) { //標準出力ではなくて標準エラー出力を使ってるのでatcoderのジャッジはこの出力を無視する つまり消さなくてok 便利だね if (startTime.HasValue) { var elapsed = DateTime.Now - startTime.Value; if (error_output) Console.Error.WriteLine($"Elapsed time: {elapsed.TotalMilliseconds} ms"); else Console.WriteLine($"Elapsed time: {elapsed.TotalMilliseconds} ms"); } else { Console.Error.WriteLine("Timer was not started."); } } } internal class Priority_Queue { toolbox toolbox = new toolbox(); public List<(long, long)> Queue { get; private set; } /// /// true==>大きいやつから出るよ false==>小さいやつからでるよ /// public bool revase { get; set; } public Priority_Queue(bool cnt = true) { Queue = new List<(long, long)>(); revase = cnt; } public void Enqueue(long a, long b) { if (revase == false) a *= -1; int i = Queue.Count, t; Queue.Add((a, b)); while (i != 0) { t = (i - 1) / 2; if (Queue[i].Item1 > Queue[t].Item1) { var k = Queue[i]; Queue[i] = Queue[t]; Queue[t] = k; i = t; } else { break; } } } public (long, long) Dequeue() { int a = Queue.Count - 1; var back = Queue[0]; Queue[0] = Queue[a]; Queue.RemoveAt(a); for (int i = 0, j; (j = 2 * i + 1) < a;) { if (j != a - 1 && Queue[j].Item1 < Queue[j + 1].Item1) j++; if (Queue[i].Item1 < Queue[j].Item1) { var k = Queue[i]; Queue[i] = Queue[j]; Queue[j] = k; i = j; } else { break; } } if (revase == false) back.Item1 *= -1; return back; } public (long, long) GetPeek() => (revase ? Queue[0].Item1 : Queue[0].Item1 * -1, Queue[0].Item2); } internal class Generic_Priority_Queue { toolbox toolbox = new toolbox(); public List<(long, T)> Queue { get; private set; } /// /// true==>大きいやつから出るよ false==>小さいやつからでるよ /// public bool revase { get; set; } public Generic_Priority_Queue(bool cnt = true) { Queue = new List<(long, T)>(); revase = cnt; } public void Enqueue(long a, T b) { if (revase == false) a *= -1; int i = Queue.Count, t; Queue.Add((a, b)); while (i != 0) { t = (i - 1) / 2; if (Queue[i].Item1 > Queue[t].Item1) { var k = Queue[i]; Queue[i] = Queue[t]; Queue[t] = k; i = t; } else { break; } } } public (long, T) Dequeue() { int a = Queue.Count - 1; var back = Queue[0]; Queue[0] = Queue[a]; Queue.RemoveAt(a); for (int i = 0, j; (j = 2 * i + 1) < a;) { if (j != a - 1 && Queue[j].Item1 < Queue[j + 1].Item1) j++; if (Queue[i].Item1 < Queue[j].Item1) { var k = Queue[i]; Queue[i] = Queue[j]; Queue[j] = k; i = j; } else { break; } } if (revase == false) back.Item1 *= -1; return back; } public (long, T) get_first() { if (Queue.Count == 0) return (default(long), default(T)); else return Queue[0]; } } }