結果
問題 | No.1995 CHIKA Road |
ユーザー | terry_u16 |
提出日時 | 2022-07-01 21:51:10 |
言語 | C# (.NET 8.0.203) |
結果 |
AC
|
実行時間 | 427 ms / 2,000 ms |
コード長 | 28,268 bytes |
コンパイル時間 | 10,421 ms |
コンパイル使用メモリ | 166,832 KB |
実行使用メモリ | 198,696 KB |
最終ジャッジ日時 | 2024-05-04 16:14:57 |
合計ジャッジ時間 | 19,894 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 62 ms
31,360 KB |
testcase_01 | AC | 59 ms
31,488 KB |
testcase_02 | AC | 60 ms
30,976 KB |
testcase_03 | AC | 63 ms
31,232 KB |
testcase_04 | AC | 66 ms
31,488 KB |
testcase_05 | AC | 66 ms
31,744 KB |
testcase_06 | AC | 95 ms
35,584 KB |
testcase_07 | AC | 131 ms
43,392 KB |
testcase_08 | AC | 62 ms
31,616 KB |
testcase_09 | AC | 62 ms
31,360 KB |
testcase_10 | AC | 115 ms
47,360 KB |
testcase_11 | AC | 400 ms
86,008 KB |
testcase_12 | AC | 210 ms
62,848 KB |
testcase_13 | AC | 163 ms
49,920 KB |
testcase_14 | AC | 172 ms
50,688 KB |
testcase_15 | AC | 427 ms
79,872 KB |
testcase_16 | AC | 126 ms
37,760 KB |
testcase_17 | AC | 321 ms
56,960 KB |
testcase_18 | AC | 404 ms
70,912 KB |
testcase_19 | AC | 401 ms
71,040 KB |
testcase_20 | AC | 245 ms
54,912 KB |
testcase_21 | AC | 233 ms
52,736 KB |
testcase_22 | AC | 380 ms
66,304 KB |
testcase_23 | AC | 132 ms
43,520 KB |
testcase_24 | AC | 342 ms
64,896 KB |
testcase_25 | AC | 110 ms
39,040 KB |
testcase_26 | AC | 137 ms
45,952 KB |
testcase_27 | AC | 327 ms
64,256 KB |
testcase_28 | AC | 229 ms
52,864 KB |
testcase_29 | AC | 403 ms
67,832 KB |
testcase_30 | AC | 105 ms
38,272 KB |
testcase_31 | AC | 88 ms
35,572 KB |
testcase_32 | AC | 115 ms
40,576 KB |
testcase_33 | AC | 326 ms
65,792 KB |
testcase_34 | AC | 91 ms
35,960 KB |
testcase_35 | AC | 132 ms
44,928 KB |
testcase_36 | AC | 145 ms
47,104 KB |
testcase_37 | AC | 374 ms
65,408 KB |
testcase_38 | AC | 286 ms
61,440 KB |
testcase_39 | AC | 91 ms
198,696 KB |
コンパイルメッセージ
復元対象のプロジェクトを決定しています... /home/judge/data/code/main.csproj を復元しました (83 ms)。 MSBuild のバージョン 17.9.6+a4ecab324 (.NET) main -> /home/judge/data/code/bin/Release/net8.0/main.dll main -> /home/judge/data/code/bin/Release/net8.0/publish/
ソースコード
using System; using System.Buffers; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics.X86; using System.Text; using YukicoderContest350.Problems; namespace YukicoderContest350.Problems { public class ProblemD : ProblemBase { public ProblemD() : base(false) { } [MethodImpl(MethodImplOptions.AggressiveOptimization)] protected override void SolveEach(IOManager io) { var n = io.ReadLong(); var m = io.ReadInt(); var edges = new long[2 * (m + 1)]; for (int i = 0; i < m; i++) { edges[2 * i] = io.ReadInt(); edges[2 * i + 1] = io.ReadInt(); } edges[^2] = 1; edges[^1] = n; var compressed = new CompressedCoordinate<long>(edges); var graph = new WeightedGraph(compressed.UniqueCount); for (int i = 0; i < m; i++) { var cost = 2 * edges[2 * i + 1] - 2 * edges[2 * i] - 1; graph.AddEdge(compressed.Compressed[2 * i], compressed.Compressed[2 * i + 1], cost); } var values = edges.Distinct().OrderBy(i => i).ToArray(); for (int i = 0; i + 1 < values.Length; i++) { graph.AddEdge(i, i + 1, 2 * (values[i + 1] - values[i])); } var dijkstra = new Dijkstra(graph); var distances = dijkstra.GetDistancesFrom(0); var d = long.MaxValue; for (int i = 0; i < m + 1; i++) { var v = compressed.Compressed[2 * i + 1]; d.ChangeMin(distances[v] + 2 * (n - edges[2 * i + 1])); } io.WriteLine(d); } public interface IEdge { int To { get; } } public interface IWeightedEdge : IEdge { long Weight { get; } } public interface IGraph<TEdge> where TEdge : IEdge { ReadOnlySpan<TEdge> this[int node] { get; } int NodeCount { get; } } public interface IWeightedGraph<TEdge> : IGraph<TEdge> where TEdge : IWeightedEdge { } public readonly struct BasicEdge : IEdge { public int To { get; } public BasicEdge(int to) { To = to; } public override string ToString() => To.ToString(); public static implicit operator BasicEdge(int edge) => new BasicEdge(edge); public static implicit operator int(BasicEdge edge) => edge.To; } [StructLayout(LayoutKind.Auto)] public readonly struct WeightedEdge : IWeightedEdge { public int To { get; } public long Weight { get; } public WeightedEdge(int to) : this(to, 1) { } public WeightedEdge(int to, long weight) { To = to; Weight = weight; } public override string ToString() => $"[{Weight}]-->{To}"; public void Deconstruct(out int to, out long weight) => (to, weight) = (To, Weight); } public class BasicGraph : IGraph<BasicEdge> { private readonly List<List<BasicEdge>> _edges; public ReadOnlySpan<BasicEdge> this[int node] => _edges[node].AsSpan(); public int NodeCount => _edges.Count; public BasicGraph(int nodeCount) { _edges = new List<List<BasicEdge>>(nodeCount); for (int i = 0; i < nodeCount; i++) { _edges.Add(new List<BasicEdge>()); } } public void AddEdge(int from, int to) => _edges[from].Add(to); public void AddNode() => _edges.Add(new List<BasicEdge>()); } public class WeightedGraph : IGraph<WeightedEdge> { private readonly List<List<WeightedEdge>> _edges; public ReadOnlySpan<WeightedEdge> this[int node] => _edges[node].AsSpan(); public int NodeCount => _edges.Count; public WeightedGraph(int nodeCount) { _edges = new List<List<WeightedEdge>>(nodeCount); for (int i = 0; i < nodeCount; i++) { _edges.Add(new List<WeightedEdge>()); } } public void AddEdge(int from, int to, long weight) => _edges[from].Add(new WeightedEdge(to, weight)); public void AddNode() => _edges.Add(new List<WeightedEdge>()); } public class Dijkstra { private readonly WeightedGraph _graph; public Dijkstra(WeightedGraph graph) { _graph = graph; } public long[] GetDistancesFrom(int startNode) { const long Inf = 1L << 60; var distances = Enumerable.Repeat(Inf, _graph.NodeCount).ToArray(); distances[startNode] = 0; var todo = new PriorityQueue<State>(PriorityQueue<State>.Order.Ascending); todo.Enqueue(new State(startNode, 0)); while (todo.Count > 0) { var current = todo.Dequeue(); if (current.Distance > distances[current.Node]) { continue; } foreach (var edge in _graph[current.Node]) { var nextDistance = current.Distance + edge.Weight; if (distances[edge.To] > nextDistance) { distances[edge.To] = nextDistance; todo.Enqueue(new State(edge.To, nextDistance)); } } } return distances; } private readonly struct State : IComparable<State> { public int Node { get; } public long Distance { get; } public State(int node, long distance) { Node = node; Distance = distance; } public int CompareTo(State other) => Distance.CompareTo(other.Distance); public void Deconstruct(out int node, out long distance) => (node, distance) = (Node, Distance); } } public class PriorityQueue<T> : IEnumerable<T> where T : IComparable<T> { const int InitialSize = 4; private readonly int _reverseFactor; private T[] _heap; public int Count { get; private set; } public bool IsDescending => _reverseFactor == 1; public PriorityQueue(Order order) { _reverseFactor = order == Order.Ascending ? -1 : 1; _heap = new T[InitialSize]; Count = 0; } public PriorityQueue(Order order, IEnumerable<T> collection) : this(order) { foreach (var item in collection) { Enqueue(item); } } public void Enqueue(T item) { if (Count >= _heap.Length) { var temp = new T[_heap.Length << 1]; _heap.AsSpan().CopyTo(temp); _heap = temp; } var index = Count++; ref var child = ref _heap[index]; child = item; while (index > 0) { index = (index - 1) >> 1; ref var parent = ref _heap[index]; if (Compare(child, parent) <= 0) { break; } Swap(ref child, ref parent); child = ref parent; } } public T Dequeue() { var index = 0; ref var parent = ref _heap[index]; var item = parent; parent = _heap[--Count]; var span = _heap.AsSpan(0, Count); while (true) { index = (index << 1) + 1; if (unchecked((uint)index < (uint)span.Length)) { ref var child = ref span[index]; var r = index + 1; if (unchecked((uint)r < (uint)span.Length)) { ref var brother = ref span[r]; if (Compare(child, brother) < 0) { child = ref brother; index = r; } } if (Compare(parent, child) < 0) { Swap(ref parent, ref child); parent = ref child; } else { break; } } else { break; } } return item; } public T Peek() => _heap[0]; public void Clear() => Count = 0; private int Compare(T a, T b) => _reverseFactor * a.CompareTo(b); private void Swap(ref T a, ref T b) { var temp = a; a = b; b = temp; } public IEnumerator<T> GetEnumerator() { var copy = new T[_heap.Length]; var cnt = Count; _heap.AsSpan().CopyTo(copy); try { while (Count > 0) { yield return Dequeue(); } } finally { _heap = copy; Count = cnt; } } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(); public enum Order { Ascending, Descending } } public class CompressedCoordinate<T> where T : IComparable<T>, IEquatable<T> { readonly int[] _compressed; readonly T[] _raw; readonly Dictionary<T, int> _converter; readonly T[] _inverter; public int UniqueCount => _inverter.Length; /// <summary> /// 座圧前のデータ列を返します。 /// </summary> public ReadOnlySpan<T> Raw => _raw; /// <summary> /// 座圧後のデータ列を返します。 /// </summary> public ReadOnlySpan<int> Compressed => _compressed; /// <summary> /// 座圧前のデータを座圧後のインデックスに変換します。 /// </summary> public int Convert(T value) => _converter[value]; /// <summary> /// 座圧後のインデックスを座圧前のデータに変換します。 /// </summary> public T Invert(Index index) => _inverter[index]; public CompressedCoordinate(IEnumerable<T> data) { _raw = data.ToArray(); _converter = new Dictionary<T, int>(); _inverter = _raw.Distinct().ToArray(); Array.Sort(_inverter); _compressed = new int[_raw.Length]; var span = _inverter.AsSpan(); for (int i = 0; i < _compressed.Length; i++) { _compressed[i] = span.BinarySearch(_raw[i]); } for (var i = 0; i < _inverter.Length; i++) { _converter[_inverter[i]] = i; } } } } } namespace YukicoderContest350 { internal class Program { static void Main(string[] args) { IProblem question = new ProblemD(); using var io = new IOManager(Console.OpenStandardInput(), Console.OpenStandardOutput()); question.Solve(io); } } } #region Base Class namespace YukicoderContest350.Problems { public interface IProblem { string Solve(string input); void Solve(IOManager io); } public abstract class ProblemBase : IProblem { protected bool HasMultiTestCases { get; } protected ProblemBase(bool hasMultiTestCases) => HasMultiTestCases = hasMultiTestCases; public string Solve(string input) { var inputStream = new MemoryStream(Encoding.UTF8.GetBytes(input)); var outputStream = new MemoryStream(); using var manager = new IOManager(inputStream, outputStream); Solve(manager); manager.Flush(); outputStream.Seek(0, SeekOrigin.Begin); var reader = new StreamReader(outputStream); return reader.ReadToEnd(); } public void Solve(IOManager io) { var tests = HasMultiTestCases ? io.ReadInt() : 1; for (var t = 0; t < tests; t++) { SolveEach(io); } } protected abstract void SolveEach(IOManager io); } } #endregion #region Utils namespace YukicoderContest350 { public class IOManager : IDisposable { private readonly BinaryReader _reader; private readonly StreamWriter _writer; private bool _disposedValue; private byte[] _buffer = new byte[1024]; private int _length; private int _cursor; private bool _eof; const char ValidFirstChar = '!'; const char ValidLastChar = '~'; public IOManager(Stream input, Stream output) { _reader = new BinaryReader(input); _writer = new StreamWriter(output) { AutoFlush = false }; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private char ReadAscii() { if (_cursor == _length) { _cursor = 0; _length = _reader.Read(_buffer); if (_length == 0) { if (!_eof) { _eof = true; return char.MinValue; } else { ThrowEndOfStreamException(); } } } return (char)_buffer[_cursor++]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public char ReadChar() { char c; while (!IsValidChar(c = ReadAscii())) { } return c; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadString() { var builder = new StringBuilder(); char c; while (!IsValidChar(c = ReadAscii())) { } do { builder.Append(c); } while (IsValidChar(c = ReadAscii())); return builder.ToString(); } public int ReadInt() => (int)ReadLong(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public long ReadLong() { long result = 0; bool isPositive = true; char c; while (!IsNumericChar(c = ReadAscii())) { } if (c == '-') { isPositive = false; c = ReadAscii(); } do { result *= 10; result += c - '0'; } while (IsNumericChar(c = ReadAscii())); return isPositive ? result : -result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private Span<char> ReadChunk(Span<char> span) { var i = 0; char c; while (!IsValidChar(c = ReadAscii())) { } do { span[i++] = c; } while (IsValidChar(c = ReadAscii())); return span.Slice(0, i); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public double ReadDouble() => double.Parse(ReadChunk(stackalloc char[32])); [MethodImpl(MethodImplOptions.AggressiveInlining)] public decimal ReadDecimal() => decimal.Parse(ReadChunk(stackalloc char[32])); public int[] ReadIntArray(int n) { var a = new int[n]; for (int i = 0; i < a.Length; i++) { a[i] = ReadInt(); } return a; } public long[] ReadLongArray(int n) { var a = new long[n]; for (int i = 0; i < a.Length; i++) { a[i] = ReadLong(); } return a; } public double[] ReadDoubleArray(int n) { var a = new double[n]; for (int i = 0; i < a.Length; i++) { a[i] = ReadDouble(); } return a; } public decimal[] ReadDecimalArray(int n) { var a = new decimal[n]; for (int i = 0; i < a.Length; i++) { a[i] = ReadDecimal(); } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Write<T>(T value) => _writer.Write(value.ToString()); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteLine<T>(T value) => _writer.WriteLine(value.ToString()); public void WriteLine<T>(IEnumerable<T> values, char separator) { var e = values.GetEnumerator(); if (e.MoveNext()) { _writer.Write(e.Current.ToString()); while (e.MoveNext()) { _writer.Write(separator); _writer.Write(e.Current.ToString()); } } _writer.WriteLine(); } public void WriteLine<T>(T[] values, char separator) => WriteLine((ReadOnlySpan<T>)values, separator); public void WriteLine<T>(Span<T> values, char separator) => WriteLine((ReadOnlySpan<T>)values, separator); public void WriteLine<T>(ReadOnlySpan<T> values, char separator) { for (int i = 0; i < values.Length - 1; i++) { _writer.Write(values[i]); _writer.Write(separator); } if (values.Length > 0) { _writer.Write(values[^1]); } _writer.WriteLine(); } public void Flush() => _writer.Flush(); [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsValidChar(char c) => ValidFirstChar <= c && c <= ValidLastChar; [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsNumericChar(char c) => ('0' <= c && c <= '9') || c == '-'; private void ThrowEndOfStreamException() => throw new EndOfStreamException(); protected virtual void Dispose(bool disposing) { if (!_disposedValue) { if (disposing) { _reader.Dispose(); _writer.Flush(); _writer.Dispose(); } _disposedValue = true; } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } public static class UtilExtensions { public static bool ChangeMax<T>(ref this T value, T other) where T : struct, IComparable<T> { if (value.CompareTo(other) < 0) { value = other; return true; } return false; } public static bool ChangeMin<T>(ref this T value, T other) where T : struct, IComparable<T> { if (value.CompareTo(other) > 0) { value = other; return true; } return false; } public static void SwapIfLargerThan<T>(ref this T a, ref T b) where T : struct, IComparable<T> { if (a.CompareTo(b) > 0) { (a, b) = (b, a); } } public static void SwapIfSmallerThan<T>(ref this T a, ref T b) where T : struct, IComparable<T> { if (a.CompareTo(b) < 0) { (a, b) = (b, a); } } public static void Sort<T>(this T[] array) where T : IComparable<T> => Array.Sort(array); public static void Sort<T>(this T[] array, Comparison<T> comparison) => Array.Sort(array, comparison); } public static class CollectionExtensions { private class ArrayWrapper<T> { #pragma warning disable CS0649 public T[] Array; #pragma warning restore CS0649 } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span<T> AsSpan<T>(this List<T> list) { return Unsafe.As<ArrayWrapper<T>>(list).Array.AsSpan(0, list.Count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span<T> GetRowSpan<T>(this T[,] array, int i) { var width = array.GetLength(1); return MemoryMarshal.CreateSpan(ref array[i, 0], width); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span<T> GetRowSpan<T>(this T[,,] array, int i, int j) { var width = array.GetLength(2); return MemoryMarshal.CreateSpan(ref array[i, j, 0], width); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span<T> GetRowSpan<T>(this T[,,,] array, int i, int j, int k) { var width = array.GetLength(3); return MemoryMarshal.CreateSpan(ref array[i, j, k, 0], width); } public static void Fill<T>(this T[] array, T value) => array.AsSpan().Fill(value); public static void Fill<T>(this T[,] array, T value) => MemoryMarshal.CreateSpan(ref array[0, 0], array.Length).Fill(value); public static void Fill<T>(this T[,,] array, T value) => MemoryMarshal.CreateSpan(ref array[0, 0, 0], array.Length).Fill(value); public static void Fill<T>(this T[,,,] array, T value) => MemoryMarshal.CreateSpan(ref array[0, 0, 0, 0], array.Length).Fill(value); } public static class SearchExtensions { private struct LowerBoundComparer<T> : IComparer<T> where T : IComparable<T> { public int Compare(T x, T y) => 0 <= x.CompareTo(y) ? 1 : -1; } private struct UpperBoundComparer<T> : IComparer<T> where T : IComparable<T> { public int Compare(T x, T y) => 0 < x.CompareTo(y) ? 1 : -1; } // https://trsing.hatenablog.com/entry/2019/08/27/211038 public static int GetGreaterEqualIndex<T>(this ReadOnlySpan<T> span, T inclusiveMin) where T : IComparable<T> => ~span.BinarySearch(inclusiveMin, new UpperBoundComparer<T>()); public static int GetGreaterThanIndex<T>(this ReadOnlySpan<T> span, T exclusiveMin) where T : IComparable<T> => ~span.BinarySearch(exclusiveMin, new LowerBoundComparer<T>()); public static int GetLessEqualIndex<T>(this ReadOnlySpan<T> span, T inclusiveMax) where T : IComparable<T> => ~span.BinarySearch(inclusiveMax, new LowerBoundComparer<T>()) - 1; public static int GetLessThanIndex<T>(this ReadOnlySpan<T> span, T exclusiveMax) where T : IComparable<T> => ~span.BinarySearch(exclusiveMax, new UpperBoundComparer<T>()) - 1; public static int GetGreaterEqualIndex<T>(this Span<T> span, T inclusiveMin) where T : IComparable<T> => ((ReadOnlySpan<T>)span).GetGreaterEqualIndex(inclusiveMin); public static int GetGreaterThanIndex<T>(this Span<T> span, T exclusiveMin) where T : IComparable<T> => ((ReadOnlySpan<T>)span).GetGreaterThanIndex(exclusiveMin); public static int GetLessEqualIndex<T>(this Span<T> span, T inclusiveMax) where T : IComparable<T> => ((ReadOnlySpan<T>)span).GetLessEqualIndex(inclusiveMax); public static int GetLessThanIndex<T>(this Span<T> span, T exclusiveMax) where T : IComparable<T> => ((ReadOnlySpan<T>)span).GetLessThanIndex(exclusiveMax); public static int BoundaryBinarySearch(Predicate<int> predicate, int ok, int ng) { while (Math.Abs(ok - ng) > 1) { var mid = (ok + ng) / 2; if (predicate(mid)) { ok = mid; } else { ng = mid; } } return ok; } public static long BoundaryBinarySearch(Predicate<long> predicate, long ok, long ng) { while (Math.Abs(ok - ng) > 1) { var mid = (ok + ng) / 2; if (predicate(mid)) { ok = mid; } else { ng = mid; } } return ok; } public static BigInteger BoundaryBinarySearch(Predicate<BigInteger> predicate, BigInteger ok, BigInteger ng) { while (BigInteger.Abs(ok - ng) > 1) { var mid = (ok + ng) / 2; if (predicate(mid)) { ok = mid; } else { ng = mid; } } return ok; } public static double BoundaryBinarySearch(Predicate<double> predicate, double ok, double ng, double eps = 1e-9, int loopLimit = 1000) { var count = 0; while (Math.Abs(ok - ng) > eps && count++ < loopLimit) { var mid = (ok + ng) * 0.5; if (predicate(mid)) { ok = mid; } else { ng = mid; } } return (ok + ng) * 0.5; } public static double Bisection(Func<double, double> f, double a, double b, double eps = 1e-9, int loopLimit = 100) { double mid = (a + b) / 2; var fa = f(a); if (fa * f(b) >= 0) { throw new ArgumentException("f(a)とf(b)は異符号である必要があります。"); } for (int i = 0; i < loopLimit; i++) { var fmid = f(mid); var sign = fa * fmid; if (sign < 0) { b = mid; } else if (sign > 0) { a = mid; fa = fmid; } else { return mid; } mid = (a + b) / 2; if (Math.Abs(b - a) < eps) { break; } } return mid; } } } #endregion