diff --git a/.github/workflows/build-release-publish.yml b/.github/workflows/build-release-publish.yml index 80c883b9..36e848e9 100644 --- a/.github/workflows/build-release-publish.yml +++ b/.github/workflows/build-release-publish.yml @@ -17,12 +17,12 @@ env: jobs: get-version: - uses: kzrnm/dotnet-actions/.github/workflows/get-version.yml@v1 + uses: kzrnm/dotnet-actions/.github/workflows/get-version.yml@v2 with: project-path: Directory.Build.props format: - uses: kzrnm/dotnet-actions/.github/workflows/format.yml@v1 + uses: kzrnm/dotnet-actions/.github/workflows/format.yml@v2 with: target: ac-library-csharp.sln dotnet-version: | @@ -30,7 +30,7 @@ jobs: 3.1.x 7.0.x test: - uses: kzrnm/dotnet-actions/.github/workflows/unittest.yml@v1 + uses: kzrnm/dotnet-actions/.github/workflows/unittest.yml@v2 with: target: ac-library-csharp.sln test-logger: GitHubActions @@ -48,7 +48,7 @@ jobs: publish: needs: [get-version, test, format, build-verify] if: ${{ needs.get-version.outputs.is-new == 'true' }} - uses: kzrnm/dotnet-actions/.github/workflows/publish.yml@v1 + uses: kzrnm/dotnet-actions/.github/workflows/publish.yml@v2 with: artifact-name: dist version: ${{ needs.get-version.outputs.version }} diff --git a/.github/workflows/reusable_verify.yml b/.github/workflows/reusable_verify.yml index 6e925a98..ca2aa8c3 100644 --- a/.github/workflows/reusable_verify.yml +++ b/.github/workflows/reusable_verify.yml @@ -19,14 +19,14 @@ jobs: build-resolve: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-dotnet@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-dotnet@v4 with: dotnet-version: | 3.0.x 3.1.x 7.0.x - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ~/.nuget/packages key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/Directory.Build.props') }} @@ -60,7 +60,7 @@ jobs: solution: ${{ env.WORKFLOW_BUILD_SLN }} output-path: verify_files.json include: Source/ac-library-csharp/** Test/ac-library-csharp.LibraryChecker/** Test/ac-library-csharp.Test - exclude: Test/ac-library-csharp.LibraryChecker/BaseSover.cs **/obj/** + exclude: Test/ac-library-csharp.LibraryChecker/BaseSolver.cs **/obj/** unittest-result: ${{runner.temp}}/VerifierCsUnitTestResult/*.csv problems: ${{runner.temp}}/problems-*.json msbuild-properties: Configuration=Release @@ -69,13 +69,13 @@ jobs: with: file: verify_files.json - name: Upload binaries - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: binary-${{github.sha}} path: Test/ac-library-csharp.LibraryChecker/bin/Release - name: Upload packages - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: inputs.upload-artifact with: name: dist @@ -92,7 +92,7 @@ jobs: index: ["0", "1", "2", "3", "4", "5"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up competitive-verifier uses: competitive-verifier/actions/setup@v1 @@ -103,20 +103,20 @@ jobs: - name: Download verify_files.json uses: competitive-verifier/actions/download-verify-artifact@v1 - - uses: actions/setup-dotnet@v3 + - uses: actions/setup-dotnet@v4 with: dotnet-version: | 3.0.x 3.1.x 7.0.x - name: Download binaries - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: binary-${{github.sha}} path: Test/ac-library-csharp.LibraryChecker/bin/Release - name: Verify - uses: competitive-verifier/actions/verify@v1 + uses: competitive-verifier/actions/verify@v2 with: destination: ${{runner.temp}}/result.json split-size: ${{ env.SPLIT_SIZE }} diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml index 393b1746..086c51ac 100644 --- a/.github/workflows/unittest.yml +++ b/.github/workflows/unittest.yml @@ -14,12 +14,12 @@ env: jobs: format: - uses: kzrnm/dotnet-actions/.github/workflows/format.yml@v1 + uses: kzrnm/dotnet-actions/.github/workflows/format.yml@v2 with: target: ac-library-csharp.sln dotnet-version: 7.0.x test: - uses: kzrnm/dotnet-actions/.github/workflows/unittest.yml@v1 + uses: kzrnm/dotnet-actions/.github/workflows/unittest.yml@v2 with: target: ac-library-csharp.sln test-logger: GitHubActions diff --git a/CHANGELOG.md b/CHANGELOG.md index 654d5308..755eb659 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,74 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.9.0] +### Changed +- `ILazySegtreeOperator` implements `ISegtreeOperator` + +## [3.8.0] - 2023-12-03 +### Added +- Create `Segtree` from Span + +## [3.7.0] - 2023-11-29 +### Added +- Add PriorityQueue.TryPeek(out T) +- Add PriorityQueue.DequeueEnqueue(T) + +## [3.6.2] - 2023-11-26 +### Changed +- Fix EnqueueDequeue + +## [3.6.1] - 2023-11-25 +### Changed +- Fix doc of FloorSum + +## [3.6.0] - 2023-11-23 +### Added +- Add `Parse`/`TryParse` to `ModInt` + +## [3.5.0] - 2023-10-29 +### Added +- Add MfGraph.Count +### Changed +- Rename generic parameter TValue to T + +## [3.4.1] - 2023-10-26 +### Changed +- Rename `AtCoder.Internal.BigMul` into `AtCoder.Internal.Mul128` + +## [3.4.0] - 2023-10-26 +### Changed +- Separate `MathLib` and `InternalMath` implementations in separate classes + +## [3.3.0] - 2023-10-25 +### Added +- Add `IModInt.Value` and `IModInt.Mod` +### Changed +- Move `IStaticMod` to IModInterface.cs +### Removed +- Remove DebugView from expanded code + +## [3.2.0] - 2023-09-25 +### Added +- Add `Deque.Grow(int capacity)` + +### Changed +- `AtCoder.Internal.Barrett` for `2^31` < m < `2^32` +- Fix empty `Deque.GetEnumerator()` + +## [3.1.0] - 2023-09-24 +### Added +- Add IModInt interface + +## [3.0.2] - 2023-09-21 +### Changed +- AtCoderAnalyzer: Create operator as readonly struct + +## [3.0.1] - 2023-09-12 +### Change +- Update DebugView +- Rename IMinMaxValue to IMinMaxValueOperator + ## [3.0.0-pre8] - 2023-01-27 ### Added - Add SimpleList.RemoveLastSize @@ -19,7 +87,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [3.0.0-pre5] - 2023-01-26 ### Changed -- Fix LCPArray ¨ LcpArray +- Fix LCPArray → LcpArray ## [3.0.0-pre4] - 2023-01-26 ### Added diff --git a/Directory.Build.props b/Directory.Build.props index a95613c6..7717acf8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,8 +7,8 @@ https://github.com/kzrnm/ac-library-csharp https://github.com/kzrnm/ac-library-csharp/blob/main/CHANGELOG.md - 3.0.0-atcoder8 - 3.0.0.8 + 3.9.0-atcoder1 + 3.9.0.1 $(GIT_COMMIT) True @@ -19,6 +19,8 @@ false $(DefineConstants);EMBEDDING + 5.5.1 + true true snupkg @@ -30,7 +32,7 @@ all - runtime; build; native; contentfiles; analyzers; buildtransitive + runtime;build;native;contentfiles;analyzers;buildtransitive diff --git a/Source/ac-library-csharp/DataStructure/FenwickTree.GenericMath.cs b/Source/ac-library-csharp/DataStructure/FenwickTree.GenericMath.cs index 4de90dbf..aea78a7e 100644 --- a/Source/ac-library-csharp/DataStructure/FenwickTree.GenericMath.cs +++ b/Source/ac-library-csharp/DataStructure/FenwickTree.GenericMath.cs @@ -18,13 +18,13 @@ namespace AtCoder /// /// ã‚’ O(logâ¡N) ã§æ±‚ã‚ã‚‹ã“ã¨ãŒå‡ºæ¥ã‚‹ãƒ‡ãƒ¼ã‚¿æ§‹é€ ã§ã™ã€‚ /// - /// é…列è¦ç´ ã®åž‹ + /// é…列è¦ç´ ã®åž‹ [DebuggerTypeProxy(typeof(FenwickTree<>.DebugView))] - public class FenwickTree - where TValue : IAdditionOperators, ISubtractionOperators, IAdditiveIdentity + public class FenwickTree + where T : IAdditionOperators, ISubtractionOperators, IAdditiveIdentity { [EditorBrowsable(EditorBrowsableState.Never)] - public readonly TValue[] data; + public readonly T[] data; public int Length { get; } @@ -39,7 +39,7 @@ public class FenwickTree public FenwickTree(int n) { Length = n; - data = new TValue[n + 1]; + data = new T[n + 1]; } /// @@ -50,7 +50,7 @@ public FenwickTree(int n) /// 計算é‡: O(log n) /// [MethodImpl(256)] - public void Add(int p, TValue x) + public void Add(int p, T x) { Contract.Assert((uint)p < (uint)Length, reason: $"IndexOutOfRange: 0 <= {nameof(p)} && {nameof(p)} < Length"); for (++p; p < data.Length; p += (int)InternalBit.ExtractLowestSetBit(p)) @@ -68,7 +68,7 @@ public void Add(int p, TValue x) /// /// a[] + a[ - 1] + ... + a[ - 1] [MethodImpl(256)] - public TValue Sum(int l, int r) + public T Sum(int l, int r) { Contract.Assert((uint)l <= (uint)r && (uint)r <= (uint)Length, reason: $"IndexOutOfRange: 0 <= {nameof(l)} && {nameof(l)} <= {nameof(r)} && {nameof(r)} <= Length"); return Sum(r) - Sum(l); @@ -76,9 +76,9 @@ public TValue Sum(int l, int r) [MethodImpl(256)] [EditorBrowsable(EditorBrowsableState.Never)] - public TValue Sum(int r) + public T Sum(int r) { - TValue s = TValue.AdditiveIdentity; + T s = T.AdditiveIdentity; for (; r > 0; r &= r - 1) { s += data[r]; @@ -87,40 +87,48 @@ public TValue Sum(int r) } [MethodImpl(256)] - public TValue Slice(int l, int len) => Sum(l, l + len); + public T Slice(int l, int len) => Sum(l, l + len); - [DebuggerDisplay("Value = {" + nameof(value) + "}, Sum = {" + nameof(sum) + "}")] - internal struct DebugItem +#if EMBEDDING + [SourceExpander.NotEmbeddingSource] +#endif + [DebuggerDisplay("Value = {" + nameof(Value) + "}, Sum = {" + nameof(Sum) + "}")] + internal readonly struct DebugItem { - public DebugItem(TValue value, TValue sum) + public DebugItem(T value, T sum) { - this.sum = sum; - this.value = value; + Value = value; + Sum = sum; } - public readonly TValue value; - public readonly TValue sum; + public T Value { get; } + public T Sum { get; } } - internal class DebugView +#if EMBEDDING + [SourceExpander.NotEmbeddingSource] +#endif + private class DebugView { - private readonly FenwickTree fenwickTree; - public DebugView(FenwickTree fenwickTree) + private readonly FenwickTree fw; + public DebugView(FenwickTree fenwickTree) { - this.fenwickTree = fenwickTree; + fw = fenwickTree; } [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public DebugItem[] Items { get { - var data = fenwickTree.data; + var data = fw.data; var items = new DebugItem[data.Length - 1]; + if (items.Length == 0) return System.Array.Empty(); + items[0] = new DebugItem(data[1], data[1]); for (int i = 2; i < data.Length; i++) { int length = (int)InternalBit.ExtractLowestSetBit(i); var pr = i - length - 1; - var sum = data[i] + (0 <= pr ? items[pr].sum : TValue.AdditiveIdentity); - var val = sum - items[i - 2].sum; + var sum = data[i] + (0 <= pr ? items[pr].Sum : T.AdditiveIdentity); + var val = sum - items[i - 2].Sum; items[i - 1] = new DebugItem(val, sum); } return items; diff --git a/Source/ac-library-csharp/DataStructure/FenwickTree.cs b/Source/ac-library-csharp/DataStructure/FenwickTree.cs index d9372d25..e5a31000 100644 --- a/Source/ac-library-csharp/DataStructure/FenwickTree.cs +++ b/Source/ac-library-csharp/DataStructure/FenwickTree.cs @@ -18,19 +18,19 @@ namespace AtCoder /// /// ã‚’ O(logâ¡N) ã§æ±‚ã‚ã‚‹ã“ã¨ãŒå‡ºæ¥ã‚‹ãƒ‡ãƒ¼ã‚¿æ§‹é€ ã§ã™ã€‚ /// - /// é…列è¦ç´ ã®åž‹ + /// é…列è¦ç´ ã®åž‹ /// é…列è¦ç´ ã®æ“作を表ã™åž‹ [DebuggerTypeProxy(typeof(FenwickTree<,>.DebugView))] #if GENERIC_MATH [System.Obsolete("Use generic math")] #endif - public class FenwickTree - where TOp : struct, IAdditionOperator, ISubtractOperator + public class FenwickTree + where TOp : struct, IAdditionOperator, ISubtractOperator { private static readonly TOp op = default; [EditorBrowsable(EditorBrowsableState.Never)] - public readonly TValue[] data; + public readonly T[] data; public int Length { get; } @@ -45,7 +45,7 @@ public class FenwickTree public FenwickTree(int n) { Length = n; - data = new TValue[n + 1]; + data = new T[n + 1]; } /// @@ -56,7 +56,7 @@ public FenwickTree(int n) /// 計算é‡: O(log n) /// [MethodImpl(256)] - public void Add(int p, TValue x) + public void Add(int p, T x) { Contract.Assert((uint)p < (uint)Length, reason: $"IndexOutOfRange: 0 <= {nameof(p)} && {nameof(p)} < Length"); for (++p; p < data.Length; p += (int)InternalBit.ExtractLowestSetBit(p)) @@ -74,7 +74,7 @@ public void Add(int p, TValue x) /// /// a[] + a[ - 1] + ... + a[ - 1] [MethodImpl(256)] - public TValue Sum(int l, int r) + public T Sum(int l, int r) { Contract.Assert((uint)l <= (uint)r && (uint)r <= (uint)Length, reason: $"IndexOutOfRange: 0 <= {nameof(l)} && {nameof(l)} <= {nameof(r)} && {nameof(r)} <= Length"); return op.Subtract(Sum(r), Sum(l)); @@ -82,9 +82,9 @@ public TValue Sum(int l, int r) [MethodImpl(256)] [EditorBrowsable(EditorBrowsableState.Never)] - public TValue Sum(int r) + public T Sum(int r) { - TValue s = default; + T s = default; for (; r > 0; r &= r - 1) { s = op.Add(s, data[r]); @@ -93,40 +93,48 @@ public TValue Sum(int r) } [MethodImpl(256)] - public TValue Slice(int l, int len) => Sum(l, l + len); + public T Slice(int l, int len) => Sum(l, l + len); - [DebuggerDisplay("Value = {" + nameof(value) + "}, Sum = {" + nameof(sum) + "}")] - internal struct DebugItem +#if EMBEDDING + [SourceExpander.NotEmbeddingSource] +#endif + [DebuggerDisplay("Value = {" + nameof(Value) + "}, Sum = {" + nameof(Sum) + "}")] + internal readonly struct DebugItem { - public DebugItem(TValue value, TValue sum) + public DebugItem(T value, T sum) { - this.sum = sum; - this.value = value; + Value = value; + Sum = sum; } - public readonly TValue value; - public readonly TValue sum; + public T Value { get; } + public T Sum { get; } } - internal class DebugView +#if EMBEDDING + [SourceExpander.NotEmbeddingSource] +#endif + private class DebugView { - private readonly FenwickTree fenwickTree; - public DebugView(FenwickTree fenwickTree) + private readonly FenwickTree fw; + public DebugView(FenwickTree fenwickTree) { - this.fenwickTree = fenwickTree; + fw = fenwickTree; } [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public DebugItem[] Items { get { - var data = fenwickTree.data; + var data = fw.data; var items = new DebugItem[data.Length - 1]; + if (items.Length == 0) return System.Array.Empty(); + items[0] = new DebugItem(data[1], data[1]); for (int i = 2; i < data.Length; i++) { int length = (int)InternalBit.ExtractLowestSetBit(i); var pr = i - length - 1; - var sum = op.Add(data[i], 0 <= pr ? items[pr].sum : default); - var val = op.Subtract(sum, items[i - 2].sum); + var sum = op.Add(data[i], 0 <= pr ? items[pr].Sum : default); + var val = op.Subtract(sum, items[i - 2].Sum); items[i - 1] = new DebugItem(val, sum); } return items; diff --git a/Source/ac-library-csharp/DataStructure/LazySegtree.cs b/Source/ac-library-csharp/DataStructure/LazySegtree.cs index 5252c5a2..763f440b 100644 --- a/Source/ac-library-csharp/DataStructure/LazySegtree.cs +++ b/Source/ac-library-csharp/DataStructure/LazySegtree.cs @@ -64,9 +64,29 @@ public LazySegtree(int n) /// 計算é‡: O() /// /// åˆæœŸé…列 - public LazySegtree(TValue[] v) : this(v.Length) + public LazySegtree(TValue[] v) : this((ReadOnlySpan)v) { } + + /// + /// é•·ã• n=.Length ã®æ•°åˆ— a をæŒã¤ クラスã®æ–°ã—ã„インスタンスを作りã¾ã™ã€‚åˆæœŸå€¤ã¯ ã§ã™ã€‚ + /// + /// + /// 制約: 0≤≤10^8 + /// 計算é‡: O() + /// + /// åˆæœŸé…列 + public LazySegtree(Span v) : this((ReadOnlySpan)v) { } + + /// + /// é•·ã• n=.Length ã®æ•°åˆ— a をæŒã¤ クラスã®æ–°ã—ã„インスタンスを作りã¾ã™ã€‚åˆæœŸå€¤ã¯ ã§ã™ã€‚ + /// + /// + /// 制約: 0≤≤10^8 + /// 計算é‡: O() + /// + /// åˆæœŸé…列 + public LazySegtree(ReadOnlySpan v) : this(v.Length) { - for (int i = 0; i < v.Length; i++) d[size + i] = v[i]; + v.CopyTo(d.AsSpan(size)); for (int i = size - 1; i >= 1; i--) { Update(i); @@ -349,51 +369,58 @@ public int MinLeft(int r, Predicate g) return 0; } - - [DebuggerDisplay("Value = {" + nameof(value) + "}, Lazy = {" + nameof(lazy) + "}", Name = "{" + nameof(key) + ",nq}")] - private struct DebugItem +#if EMBEDDING + [SourceExpander.NotEmbeddingSource] +#endif + [DebuggerDisplay("Value = {" + nameof(Value) + "}, Lazy = {" + nameof(Lazy) + "}", Name = "{" + nameof(Key) + ",nq}")] + internal readonly struct DebugItem { public DebugItem(int l, int r, TValue value, F lazy) { - if (r - l == 1) - key = $"[{l}]"; - else - key = $"[{l}-{r})"; - this.value = value; - this.lazy = lazy; + L = l; + R = r; + Value = value; + Lazy = lazy; } [DebuggerBrowsable(0)] - private readonly string key; - private readonly TValue value; - private readonly F lazy; + public int L { get; } + [DebuggerBrowsable(0)] + public int R { get; } + [DebuggerBrowsable(0)] + public string Key => R - L == 1 ? $"[{L}]" : $"[{L}-{R})"; + public TValue Value { get; } + public F Lazy { get; } } +#if EMBEDDING + [SourceExpander.NotEmbeddingSource] +#endif private class DebugView { - private readonly LazySegtree segtree; + private readonly LazySegtree s; public DebugView(LazySegtree segtree) { - this.segtree = segtree; + s = segtree; } [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public DebugItem[] Items { get { - var items = new List(segtree.Length); - for (int len = segtree.size; len > 0; len >>= 1) + var items = new List(s.Length); + for (int len = s.size; len > 0; len >>= 1) { - int unit = segtree.size / len; + int unit = s.size / len; for (int i = 0; i < len; i++) { int l = i * unit; - int r = Math.Min(l + unit, segtree.Length); - if (l < segtree.Length) + int r = l + unit; + if (l < s.Length) { int dataIndex = i + len; - if ((uint)dataIndex < segtree.lz.Length) - items.Add(new DebugItem(l, r, segtree.d[dataIndex], segtree.lz[dataIndex])); + if ((uint)dataIndex < s.lz.Length) + items.Add(new DebugItem(l, r, s.d[dataIndex], s.lz[dataIndex])); else - items.Add(new DebugItem(l, r, segtree.d[dataIndex], op.FIdentity)); + items.Add(new DebugItem(l, r, s.d[dataIndex], op.FIdentity)); } } } diff --git a/Source/ac-library-csharp/DataStructure/Operators/ILazySegtreeOperator.cs b/Source/ac-library-csharp/DataStructure/Operators/ILazySegtreeOperator.cs index 4262a40d..6f326c77 100644 --- a/Source/ac-library-csharp/DataStructure/Operators/ILazySegtreeOperator.cs +++ b/Source/ac-library-csharp/DataStructure/Operators/ILazySegtreeOperator.cs @@ -1,26 +1,18 @@ namespace AtCoder { /// - /// モノイドを定義ã™ã‚‹ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ã‚¤ã‚¹ã§ã™ã€‚ + /// モノイドã¨å†™åƒã‚’定義ã™ã‚‹ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ã‚¤ã‚¹ã§ã™ã€‚ /// /// æ“作を行ã†åž‹ã€‚ /// 写åƒã®åž‹ã€‚ [IsOperator] - public interface ILazySegtreeOperator + public interface ILazySegtreeOperator : ISegtreeOperator { - /// - /// Operate(x, ) = x を満ãŸã™å˜ä½å…ƒã€‚ - /// - T Identity { get; } /// /// Mapping(, x) = x を満ãŸã™æ’等写åƒã€‚ /// F FIdentity { get; } /// - /// çµåˆå¾‹ Operate(Operate(a, b), c) = Operate(a, Operate(b, c)) を満ãŸã™å†™åƒã€‚ - /// - T Operate(T x, T y); - /// /// 写åƒã€€ ã‚’ ã«ä½œç”¨ã•ã›ã‚‹é–¢æ•°ã€‚ /// T Mapping(F f, T x); diff --git a/Source/ac-library-csharp/DataStructure/Segtree.cs b/Source/ac-library-csharp/DataStructure/Segtree.cs index e9749bac..bac6710e 100644 --- a/Source/ac-library-csharp/DataStructure/Segtree.cs +++ b/Source/ac-library-csharp/DataStructure/Segtree.cs @@ -61,9 +61,27 @@ public Segtree(int n) /// 計算é‡: O() /// /// åˆæœŸé…列 - public Segtree(TValue[] v) : this(v.Length) + public Segtree(TValue[] v) : this((ReadOnlySpan)v) { } + /// + /// é•·ã• n=.Length ã®æ•°åˆ— a をæŒã¤ クラスã®æ–°ã—ã„インスタンスを作りã¾ã™ã€‚åˆæœŸå€¤ã¯ ã§ã™ã€‚ + /// + /// + /// 制約: 0≤≤10^8 + /// 計算é‡: O() + /// + /// åˆæœŸé…列 + public Segtree(Span v) : this((ReadOnlySpan)v) { } + /// + /// é•·ã• n=.Length ã®æ•°åˆ— a をæŒã¤ クラスã®æ–°ã—ã„インスタンスを作りã¾ã™ã€‚åˆæœŸå€¤ã¯ ã§ã™ã€‚ + /// + /// + /// 制約: 0≤≤10^8 + /// 計算é‡: O() + /// + /// åˆæœŸé…列 + public Segtree(ReadOnlySpan v) : this(v.Length) { - for (int i = 0; i < v.Length; i++) d[size + i] = v[i]; + v.CopyTo(d.AsSpan(size)); for (int i = size - 1; i >= 1; i--) { Update(i); @@ -252,44 +270,51 @@ public int MinLeft(int r, Predicate f) return 0; } - - [DebuggerDisplay("{" + nameof(value) + "}", Name = "{" + nameof(key) + ",nq}")] - private struct DebugItem +#if EMBEDDING + [SourceExpander.NotEmbeddingSource] +#endif + [DebuggerDisplay("{" + nameof(Value) + "}", Name = "{" + nameof(Key) + ",nq}")] + internal readonly struct DebugItem { public DebugItem(int l, int r, TValue value) { - if (r - l == 1) - key = $"[{l}]"; - else - key = $"[{l}-{r})"; - this.value = value; + L = l; + R = r; + Value = value; } [DebuggerBrowsable(0)] - private readonly string key; - private readonly TValue value; + public int L { get; } + [DebuggerBrowsable(0)] + public int R { get; } + [DebuggerBrowsable(0)] + public string Key => R - L == 1 ? $"[{L}]" : $"[{L}-{R})"; + public TValue Value { get; } } +#if EMBEDDING + [SourceExpander.NotEmbeddingSource] +#endif private class DebugView { - private readonly Segtree segtree; + private readonly Segtree s; public DebugView(Segtree segtree) { - this.segtree = segtree; + s = segtree; } [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public DebugItem[] Items { get { - var items = new List(segtree.Length); - for (int len = segtree.size; len > 0; len >>= 1) + var items = new List(s.d.Length); + for (int len = s.size; len > 0; len >>= 1) { - int unit = segtree.size / len; + int unit = s.size / len; for (int i = 0; i < len; i++) { int l = i * unit; - int r = Math.Min(l + unit, segtree.Length); - if (l < segtree.Length) - items.Add(new DebugItem(l, r, segtree.d[i + len])); + int r = l + unit; + if (l < s.Length) + items.Add(new DebugItem(l, r, s.d[i + len])); } } return items.ToArray(); diff --git a/Source/ac-library-csharp/Graph/MaxFlow.GenericMath.cs b/Source/ac-library-csharp/Graph/MaxFlow.GenericMath.cs index 3d3e1bf1..3c6e3b92 100644 --- a/Source/ac-library-csharp/Graph/MaxFlow.GenericMath.cs +++ b/Source/ac-library-csharp/Graph/MaxFlow.GenericMath.cs @@ -11,21 +11,21 @@ namespace AtCoder /// /// 最大フローå•é¡Œ を解ãライブラリã§ã™ã€‚ /// - /// 容é‡ã®åž‹ + /// 容é‡ã®åž‹ /// - /// 制約: 㯠int, long。 + /// 制約: 㯠int, long。 /// /// 内部ã§ã¯å„辺 e ã«ã¤ã„㦠2 ã¤ã®å¤‰æ•°ã€æµé‡ f_e ã¨å®¹é‡ c_e を管ç†ã—ã¦ã„ã¾ã™ã€‚ /// 頂点 v ã‹ã‚‰å‡ºã‚‹è¾ºã®é›†åˆã‚’ out(v)ã€å…¥ã‚‹è¾ºã®é›†åˆã‚’ in(v)〠/// ã¾ãŸé ‚点 v ã«ã¤ã„㦠g(v, f) = (Σ_in(v) f_e) - (Σ_out(v) f_e) ã¨ã—ã¾ã™ã€‚ /// /// - public class MfGraph - where TValue - : INumber - , IMinMaxValue + public class MfGraph + where T + : INumber + , IMinMaxValue { - internal readonly int _n; + public int Count => _g.Length; [EditorBrowsable(EditorBrowsableState.Never)] public readonly SimpleList<(int first, int second)> _pos; [EditorBrowsable(EditorBrowsableState.Never)] @@ -40,7 +40,6 @@ where TValue /// public MfGraph(int n) { - _n = n; _g = new SimpleList[n]; for (int i = 0; i < _g.Length; i++) { @@ -66,12 +65,12 @@ public MfGraph(int n) /// 計算é‡: ãªã‚‰ã—O(1) /// [MethodImpl(256)] - public int AddEdge(int from, int to, TValue cap) + public int AddEdge(int from, int to, T cap) { int m = _pos.Count; - Contract.Assert((uint)from < (uint)_n, reason: $"IndexOutOfRange: 0 <= {nameof(from)} && {nameof(from)} < _n"); - Contract.Assert((uint)to < (uint)_n, reason: $"IndexOutOfRange: 0 <= {nameof(to)} && {nameof(to)} < _n"); - Contract.Assert(TValue.IsPositive(cap), reason: $"IndexOutOfRange: 0 <= {nameof(cap)}"); + Contract.Assert((uint)from < (uint)Count, reason: $"IndexOutOfRange: 0 <= {nameof(from)} && {nameof(from)} < Count"); + Contract.Assert((uint)to < (uint)Count, reason: $"IndexOutOfRange: 0 <= {nameof(to)} && {nameof(to)} < Count"); + Contract.Assert(T.IsPositive(cap), reason: $"IndexOutOfRange: 0 <= {nameof(cap)}"); _pos.Add((from, _g[from].Count)); int fromId = _g[from].Count; int toId = _g[to].Count; @@ -131,10 +130,10 @@ public Edge[] Edges() /// /// [MethodImpl(256)] - public void ChangeEdge(int i, TValue newCap, TValue newFlow) + public void ChangeEdge(int i, T newCap, T newFlow) { Contract.Assert((uint)i < (uint)_pos.Count, reason: $"IndexOutOfRange: 0 <= {nameof(i)} && {nameof(i)} < edgeCount"); - Contract.Assert(TValue.IsPositive(newFlow) && newFlow <= newCap, reason: $"IndexOutOfRange: 0 <= {nameof(newFlow)} && {nameof(newFlow)} <= {nameof(newCap)}"); + Contract.Assert(T.IsPositive(newFlow) && newFlow <= newCap, reason: $"IndexOutOfRange: 0 <= {nameof(newFlow)} && {nameof(newFlow)} <= {nameof(newCap)}"); var (first, second) = _pos[i]; var (to, rev, _) = _g[first][second]; //var _re = _g[_e.To][_e.Rev]; @@ -172,7 +171,7 @@ public void ChangeEdge(int i, TValue newCap, TValue newFlow) /// /// /// - /// 制約: 返値㌠ã«åŽã¾ã‚‹ã€‚ + /// 制約: 返値㌠ã«åŽã¾ã‚‹ã€‚ /// 計算é‡: m を追加ã•ã‚ŒãŸè¾ºæ•°ã¨ã—ã¦ã€ /// /// @@ -184,9 +183,9 @@ public void ChangeEdge(int i, TValue newCap, TValue newFlow) /// /// [MethodImpl(256)] - public TValue Flow(int s, int t) + public T Flow(int s, int t) { - return Flow(s, t, TValue.MaxValue); + return Flow(s, t, T.MaxValue); } /// @@ -220,7 +219,7 @@ public TValue Flow(int s, int t) /// /// /// - /// 制約: 返値㌠ã«åŽã¾ã‚‹ã€‚ + /// 制約: 返値㌠ã«åŽã¾ã‚‹ã€‚ /// 計算é‡: m を追加ã•ã‚ŒãŸè¾ºæ•°ã¨ã—ã¦ã€ /// /// @@ -232,13 +231,13 @@ public TValue Flow(int s, int t) /// /// [MethodImpl(256)] - public TValue Flow(int s, int t, TValue flowLimit) + public T Flow(int s, int t, T flowLimit) { - Contract.Assert((uint)s < (uint)_n, reason: $"IndexOutOfRange: 0 <= {nameof(s)} && {nameof(s)} < _n"); - Contract.Assert((uint)t < (uint)_n, reason: $"IndexOutOfRange: 0 <= {nameof(t)} && {nameof(t)} < _n"); + Contract.Assert((uint)s < (uint)Count, reason: $"IndexOutOfRange: 0 <= {nameof(s)} && {nameof(s)} < Count"); + Contract.Assert((uint)t < (uint)Count, reason: $"IndexOutOfRange: 0 <= {nameof(t)} && {nameof(t)} < Count"); Contract.Assert(s != t, reason: $"{nameof(s)} and {nameof(t)} must be different."); - var level = new int[_n]; + var level = new int[Count]; int[] iter; var que = new Queue(); @@ -253,7 +252,7 @@ void Bfs() int v = que.Dequeue(); foreach (var (to, _, cap) in _g[v].AsSpan()) { - if (EqualityComparer.Default.Equals(cap, default) || level[to] >= 0) continue; + if (EqualityComparer.Default.Equals(cap, default) || level[to] >= 0) continue; level[to] = level[v] + 1; if (to == t) return; que.Enqueue(to); @@ -278,19 +277,19 @@ void Bfs() // res = op.Add(res, d); // if (EqualityComparer.Default.Equals(res, up)) return res; // } - // level[v] = _n; + // level[v] = Count; // return res; //} - TValue Dfs(int v, TValue up) + T Dfs(int v, T up) { - var lastRes = default(TValue); - var stack = new Stack<(int v, TValue up, TValue res, bool childOk)>(); + var lastRes = default(T); + var stack = new Stack<(int v, T up, T res, bool childOk)>(); stack.Push((v, up, default, true)); DFS: while (stack.Count > 0) { - TValue res; + T res; bool childOk; (v, up, res, childOk) = stack.Pop(); if (v == s) @@ -303,23 +302,23 @@ TValue Dfs(int v, TValue up) var (to, rev, cap) = _g[v][itrv]; if (childOk) { - if (level[v] <= level[to] || EqualityComparer.Default.Equals(_g[to][rev].Cap, default)) + if (level[v] <= level[to] || EqualityComparer.Default.Equals(_g[to][rev].Cap, default)) continue; stack.Push((v, up, res, false)); - stack.Push((to, TValue.Min(up - res, _g[to][rev].Cap), default, true)); + stack.Push((to, T.Min(up - res, _g[to][rev].Cap), default, true)); goto DFS; } else { var d = lastRes; - if (TValue.AdditiveIdentity < d) + if (T.AdditiveIdentity < d) { _g[v][itrv].Cap = cap + d; _g[to][rev].Cap -= d; res += d; - if (EqualityComparer.Default.Equals(res, up)) + if (EqualityComparer.Default.Equals(res, up)) { lastRes = res; goto DFS; @@ -328,20 +327,20 @@ TValue Dfs(int v, TValue up) childOk = true; } } - level[v] = _n; + level[v] = Count; lastRes = res; } return lastRes; } - TValue flow = default; + T flow = default; while (flow < flowLimit) { Bfs(); if (level[t] == -1) break; - iter = new int[_n]; + iter = new int[Count]; var f = Dfs(t, flowLimit - flow); - if (EqualityComparer.Default.Equals(f, default)) break; + if (EqualityComparer.Default.Equals(f, default)) break; flow += f; } return flow; @@ -370,7 +369,7 @@ TValue Dfs(int v, TValue up) [MethodImpl(256)] public bool[] MinCut(int s) { - var visited = new bool[_n]; + var visited = new bool[Count]; var que = new Queue(); que.Enqueue(s); while (que.Count > 0) @@ -379,7 +378,7 @@ public bool[] MinCut(int s) visited[p] = true; foreach (var (to, _, cap) in _g[p]) { - if (!EqualityComparer.Default.Equals(cap, default) && !visited[to]) + if (!EqualityComparer.Default.Equals(cap, default) && !visited[to]) { visited[to] = true; que.Enqueue(to); @@ -401,10 +400,10 @@ public struct Edge : IEquatable /// フローãŒæµå…¥ã™ã‚‹é ‚点。 public int To { get; set; } /// 辺ã®å®¹é‡ã€‚ - public TValue Cap { get; set; } + public T Cap { get; set; } /// 辺ã®æµé‡ã€‚ - public TValue Flow { get; set; } - public Edge(int from, int to, TValue cap, TValue flow) + public T Flow { get; set; } + public Edge(int from, int to, T cap, T flow) { From = from; To = to; @@ -420,8 +419,8 @@ public override bool Equals(object obj) public bool Equals(Edge other) => From == other.From && To == other.To && - EqualityComparer.Default.Equals(Cap, other.Cap) && - EqualityComparer.Default.Equals(Flow, other.Flow); + EqualityComparer.Default.Equals(Cap, other.Cap) && + EqualityComparer.Default.Equals(Flow, other.Flow); public override int GetHashCode() => HashCode.Combine(From, To, Cap, Flow); [MethodImpl(256)] public static bool operator ==(Edge left, Edge right) => left.Equals(right); @@ -434,15 +433,15 @@ public struct EdgeInternal { public int To { get; } public int Rev { get; } - public TValue Cap { get; set; } - public EdgeInternal(int to, int rev, TValue cap) + public T Cap { get; set; } + public EdgeInternal(int to, int rev, T cap) { To = to; Rev = rev; Cap = cap; } [MethodImpl(256)] - public void Deconstruct(out int to, out int rev, out TValue cap) + public void Deconstruct(out int to, out int rev, out T cap) { to = To; rev = Rev; diff --git a/Source/ac-library-csharp/Graph/MaxFlow.cs b/Source/ac-library-csharp/Graph/MaxFlow.cs index 96b38215..d861fa73 100644 --- a/Source/ac-library-csharp/Graph/MaxFlow.cs +++ b/Source/ac-library-csharp/Graph/MaxFlow.cs @@ -11,10 +11,10 @@ namespace AtCoder /// /// 最大フローå•é¡Œ を解ãライブラリã§ã™ã€‚ /// - /// 容é‡ã®åž‹ - /// ã«å¯¾å¿œã™ã‚‹æ¼”ç®—ã‚’æè¦ã™ã‚‹åž‹ + /// 容é‡ã®åž‹ + /// ã«å¯¾å¿œã™ã‚‹æ¼”ç®—ã‚’æè¦ã™ã‚‹åž‹ /// - /// 制約: 㯠int, long。 + /// 制約: 㯠int, long。 /// /// 内部ã§ã¯å„辺 e ã«ã¤ã„㦠2 ã¤ã®å¤‰æ•°ã€æµé‡ f_e ã¨å®¹é‡ c_e を管ç†ã—ã¦ã„ã¾ã™ã€‚ /// 頂点 v ã‹ã‚‰å‡ºã‚‹è¾ºã®é›†åˆã‚’ out(v)ã€å…¥ã‚‹è¾ºã®é›†åˆã‚’ in(v)〠@@ -24,13 +24,13 @@ namespace AtCoder #if GENERIC_MATH [Obsolete("Use generic math")] #endif - public class MfGraph - where TValue : struct - where TOp : struct, INumOperator + public class MfGraph + where T : struct + where TOp : struct, INumOperator { static readonly TOp op = default; - internal readonly int _n; + public int Count => _g.Length; [EditorBrowsable(EditorBrowsableState.Never)] public readonly SimpleList<(int first, int second)> _pos; [EditorBrowsable(EditorBrowsableState.Never)] @@ -45,7 +45,6 @@ public class MfGraph /// public MfGraph(int n) { - _n = n; _g = new SimpleList[n]; for (int i = 0; i < _g.Length; i++) { @@ -71,11 +70,11 @@ public MfGraph(int n) /// 計算é‡: ãªã‚‰ã—O(1) /// [MethodImpl(256)] - public int AddEdge(int from, int to, TValue cap) + public int AddEdge(int from, int to, T cap) { int m = _pos.Count; - Contract.Assert((uint)from < (uint)_n, reason: $"IndexOutOfRange: 0 <= {nameof(from)} && {nameof(from)} < _n"); - Contract.Assert((uint)to < (uint)_n, reason: $"IndexOutOfRange: 0 <= {nameof(to)} && {nameof(to)} < _n"); + Contract.Assert((uint)from < (uint)Count, reason: $"IndexOutOfRange: 0 <= {nameof(from)} && {nameof(from)} < Count"); + Contract.Assert((uint)to < (uint)Count, reason: $"IndexOutOfRange: 0 <= {nameof(to)} && {nameof(to)} < Count"); Contract.Assert(op.LessThanOrEqual(default, cap), reason: $"IndexOutOfRange: 0 <= {nameof(cap)}"); _pos.Add((from, _g[from].Count)); int fromId = _g[from].Count; @@ -136,7 +135,7 @@ public Edge[] Edges() /// /// [MethodImpl(256)] - public void ChangeEdge(int i, TValue newCap, TValue newFlow) + public void ChangeEdge(int i, T newCap, T newFlow) { Contract.Assert((uint)i < (uint)_pos.Count, reason: $"IndexOutOfRange: 0 <= {nameof(i)} && {nameof(i)} < edgeCount"); Contract.Assert(op.LessThanOrEqual(default, newFlow) && op.LessThanOrEqual(newFlow, newCap), reason: $"IndexOutOfRange: 0 <= {nameof(newFlow)} && {nameof(newFlow)} <= {nameof(newCap)}"); @@ -177,7 +176,7 @@ public void ChangeEdge(int i, TValue newCap, TValue newFlow) /// /// /// - /// 制約: 返値㌠ã«åŽã¾ã‚‹ã€‚ + /// 制約: 返値㌠ã«åŽã¾ã‚‹ã€‚ /// 計算é‡: m を追加ã•ã‚ŒãŸè¾ºæ•°ã¨ã—ã¦ã€ /// /// @@ -189,7 +188,7 @@ public void ChangeEdge(int i, TValue newCap, TValue newFlow) /// /// [MethodImpl(256)] - public TValue Flow(int s, int t) + public T Flow(int s, int t) { return Flow(s, t, op.MaxValue); } @@ -225,7 +224,7 @@ public TValue Flow(int s, int t) /// /// /// - /// 制約: 返値㌠ã«åŽã¾ã‚‹ã€‚ + /// 制約: 返値㌠ã«åŽã¾ã‚‹ã€‚ /// 計算é‡: m を追加ã•ã‚ŒãŸè¾ºæ•°ã¨ã—ã¦ã€ /// /// @@ -237,13 +236,13 @@ public TValue Flow(int s, int t) /// /// [MethodImpl(256)] - public TValue Flow(int s, int t, TValue flowLimit) + public T Flow(int s, int t, T flowLimit) { - Contract.Assert((uint)s < (uint)_n, reason: $"IndexOutOfRange: 0 <= {nameof(s)} && {nameof(s)} < _n"); - Contract.Assert((uint)t < (uint)_n, reason: $"IndexOutOfRange: 0 <= {nameof(t)} && {nameof(t)} < _n"); + Contract.Assert((uint)s < (uint)Count, reason: $"IndexOutOfRange: 0 <= {nameof(s)} && {nameof(s)} < Count"); + Contract.Assert((uint)t < (uint)Count, reason: $"IndexOutOfRange: 0 <= {nameof(t)} && {nameof(t)} < Count"); Contract.Assert(s != t, reason: $"{nameof(s)} and {nameof(t)} must be different."); - var level = new int[_n]; + var level = new int[Count]; int[] iter; var que = new Queue(); @@ -258,7 +257,7 @@ void Bfs() int v = que.Dequeue(); foreach (var (to, _, cap) in _g[v].AsSpan()) { - if (EqualityComparer.Default.Equals(cap, default) || level[to] >= 0) continue; + if (EqualityComparer.Default.Equals(cap, default) || level[to] >= 0) continue; level[to] = level[v] + 1; if (to == t) return; que.Enqueue(to); @@ -283,19 +282,19 @@ void Bfs() // res = op.Add(res, d); // if (EqualityComparer.Default.Equals(res, up)) return res; // } - // level[v] = _n; + // level[v] = Count; // return res; //} - TValue Dfs(int v, TValue up) + T Dfs(int v, T up) { - var lastRes = default(TValue); - var stack = new Stack<(int v, TValue up, TValue res, bool childOk)>(); + var lastRes = default(T); + var stack = new Stack<(int v, T up, T res, bool childOk)>(); stack.Push((v, up, default, true)); DFS: while (stack.Count > 0) { - TValue res; + T res; bool childOk; (v, up, res, childOk) = stack.Pop(); if (v == s) @@ -308,7 +307,7 @@ TValue Dfs(int v, TValue up) var (to, rev, cap) = _g[v][itrv]; if (childOk) { - if (level[v] <= level[to] || EqualityComparer.Default.Equals(_g[to][rev].Cap, default)) + if (level[v] <= level[to] || EqualityComparer.Default.Equals(_g[to][rev].Cap, default)) continue; var up1 = op.Subtract(up, res); @@ -326,7 +325,7 @@ TValue Dfs(int v, TValue up) _g[to][rev].Cap = op.Subtract(_g[to][rev].Cap, d); res = op.Add(res, d); - if (EqualityComparer.Default.Equals(res, up)) + if (EqualityComparer.Default.Equals(res, up)) { lastRes = res; goto DFS; @@ -335,20 +334,20 @@ TValue Dfs(int v, TValue up) childOk = true; } } - level[v] = _n; + level[v] = Count; lastRes = res; } return lastRes; } - TValue flow = default; + T flow = default; while (op.LessThan(flow, flowLimit)) { Bfs(); if (level[t] == -1) break; - iter = new int[_n]; + iter = new int[Count]; var f = Dfs(t, op.Subtract(flowLimit, flow)); - if (EqualityComparer.Default.Equals(f, default)) break; + if (EqualityComparer.Default.Equals(f, default)) break; flow = op.Add(flow, f); } return flow; @@ -377,7 +376,7 @@ TValue Dfs(int v, TValue up) [MethodImpl(256)] public bool[] MinCut(int s) { - var visited = new bool[_n]; + var visited = new bool[Count]; var que = new Queue(); que.Enqueue(s); while (que.Count > 0) @@ -386,7 +385,7 @@ public bool[] MinCut(int s) visited[p] = true; foreach (var (to, _, cap) in _g[p]) { - if (!EqualityComparer.Default.Equals(cap, default) && !visited[to]) + if (!EqualityComparer.Default.Equals(cap, default) && !visited[to]) { visited[to] = true; que.Enqueue(to); @@ -408,10 +407,10 @@ public struct Edge : IEquatable /// フローãŒæµå…¥ã™ã‚‹é ‚点。 public int To { get; set; } /// 辺ã®å®¹é‡ã€‚ - public TValue Cap { get; set; } + public T Cap { get; set; } /// 辺ã®æµé‡ã€‚ - public TValue Flow { get; set; } - public Edge(int from, int to, TValue cap, TValue flow) + public T Flow { get; set; } + public Edge(int from, int to, T cap, T flow) { From = from; To = to; @@ -427,8 +426,8 @@ public override bool Equals(object obj) public bool Equals(Edge other) => From == other.From && To == other.To && - EqualityComparer.Default.Equals(Cap, other.Cap) && - EqualityComparer.Default.Equals(Flow, other.Flow); + EqualityComparer.Default.Equals(Cap, other.Cap) && + EqualityComparer.Default.Equals(Flow, other.Flow); public override int GetHashCode() => HashCode.Combine(From, To, Cap, Flow); [MethodImpl(256)] public static bool operator ==(Edge left, Edge right) => left.Equals(right); @@ -441,15 +440,15 @@ public struct EdgeInternal { public int To { get; } public int Rev { get; } - public TValue Cap { get; set; } - public EdgeInternal(int to, int rev, TValue cap) + public T Cap { get; set; } + public EdgeInternal(int to, int rev, T cap) { To = to; Rev = rev; Cap = cap; } [MethodImpl(256)] - public void Deconstruct(out int to, out int rev, out TValue cap) + public void Deconstruct(out int to, out int rev, out T cap) { to = To; rev = Rev; diff --git a/Source/ac-library-csharp/Graph/MinCostFlow.GenericMath.cs b/Source/ac-library-csharp/Graph/MinCostFlow.GenericMath.cs index 640243e1..542b7a55 100644 --- a/Source/ac-library-csharp/Graph/MinCostFlow.GenericMath.cs +++ b/Source/ac-library-csharp/Graph/MinCostFlow.GenericMath.cs @@ -11,9 +11,9 @@ namespace AtCoder /// /// Minimum-cost flow problem を扱ã†ãƒ©ã‚¤ãƒ–ラリã§ã™ã€‚ /// - /// 容é‡ã¨ã‚³ã‚¹ãƒˆã®åž‹ - public class McfGraph : McfGraph - where TValue : INumber, ISignedNumber, IMinMaxValue + /// 容é‡ã¨ã‚³ã‚¹ãƒˆã®åž‹ + public class McfGraph : McfGraph + where T : INumber, ISignedNumber, IMinMaxValue { /// /// 頂点 0 辺ã®ã‚°ãƒ©ãƒ•ã‚’作りã¾ã™ã€‚ diff --git a/Source/ac-library-csharp/Math/Internal/Barrett.cs b/Source/ac-library-csharp/Math/Internal/Barrett.cs index ffad1224..170079be 100644 --- a/Source/ac-library-csharp/Math/Internal/Barrett.cs +++ b/Source/ac-library-csharp/Math/Internal/Barrett.cs @@ -25,10 +25,10 @@ public Barrett(uint m) [MethodImpl(256)] public uint Reduce(ulong z) { - var x = InternalMath.Mul128Bit(z, IM); - var v = unchecked((uint)(z - x * Mod)); - if (Mod <= v) v += Mod; - return v; + var x = Mul128.Mul128Bit(z, IM); + var y = x * Mod; + if (z < y) return (uint)(z - y + Mod); + return (uint)(z - y); } /// @@ -42,8 +42,21 @@ public uint Reduce(ulong z) public uint Pow(long x, long n) { Contract.Assert(0 <= n, $"{nameof(n)} must be positive."); + return Pow(x, (ulong)n); + } + + /// + /// ^ mod m ã‚’è¿”ã—ã¾ã™ã€‚ + /// + /// + /// 制約: 0≤|| + /// 計算é‡: O(log()) + /// + [MethodImpl(256)] + public uint Pow(long x, ulong n) + { if (Mod == 1) return 0; - uint r = 1, y = (uint)InternalMath.SafeMod(x, Mod); + uint r = 1, y = (uint)ModCalc.SafeMod(x, Mod); while (n > 0) { if ((n & 1) != 0) r = Mul(r, y); diff --git a/Source/ac-library-csharp/Math/Internal/BigMul.cs b/Source/ac-library-csharp/Math/Internal/BigMul.cs new file mode 100644 index 00000000..53d92d00 --- /dev/null +++ b/Source/ac-library-csharp/Math/Internal/BigMul.cs @@ -0,0 +1,88 @@ +using System.Runtime.CompilerServices; +#if NETCOREAPP3_1_OR_GREATER +using System.Runtime.Intrinsics.X86; +#endif + +namespace AtCoder.Internal +{ + public static class Mul128 + { + /// + /// * ã®ä¸Šä½ 64 ビットを返ã—ã¾ã™ã€‚ + /// + /// + /// + /// + [MethodImpl(256)] + public static ulong Mul128Bit(ulong a, ulong b) + { +#if NETCOREAPP3_1_OR_GREATER + if (Bmi2.X64.IsSupported) + return Bmi2.X64.MultiplyNoFlags(a, b); +#endif + return Mul128BitLogic(a, b); + } + + /// + /// * ã®ä¸Šä½ 64 ビットを返ã—ã¾ã™ã€‚ + /// + /// + /// + /// + [MethodImpl(256)] + internal static ulong Mul128BitLogic(ulong a, ulong b) + { + /* + * ã“ã“ã§ã¯ 64 bit æ•´æ•° X ã®ä¸Šä½, ä¸‹ä½ 32 bit ã‚’ãã‚Œãžã‚Œ Xu ,Xd ã¨è¡¨ã™ + * A * B を計算ã™ã‚‹ã€‚ + * + * 変数を下記ã®ã‚ˆã†ã«å®šç¾©ã™ã‚‹ã€‚ + * s := 1ul << 32 + * R := A * B + * L := Ad * Bd + * M1 := Ad * Bu + * M2 := Au * Bd + * H := Au * Bu + * + * A * B = s * s * H + s * (M1 + M2) + L + * ã§ã‚ã‚‹ã“ã¨ã‚’使ã£ã¦ + * R = s * s * x + y + * ã¨è¡¨ã›ã‚‹ x, y を求ã‚ãŸã„ (x, y < s * s) + * + * A * B + * = s * s * H + s * (s * M1u + M1d + s * M2u + M2d) + L + * = s * s * H + s * (s * (M1u + M2u) + M1d + M2d) + L + * = s * s * (H + M1u + M2u) + s * (M1d + M2d) + L + * + * ã¨è¡¨ã›ã‚‹ã®ã§ã€ç¹°ã‚Šä¸ŠãŒã‚Šã‚’考慮ã—ãªã‘れ㰠+ * x = H + M1u + M2u + * y = s * (M1d + M2d) + L = s * (M1d + M2d + Lu) + Ld + * ã¨ãªã‚‹ + * + * 繰り上ãŒã‚‹ã®ã¯ + * M1d + M2d + Lu ã®ä¸Šä½ 32 bit ãªã®ã§ + * C := M1d + M2d + Lu + * ã¨ã™ã‚‹ã¨ + * + * x = H + M1u + M2u + Cu + * ã¨ãªã‚‹ + */ + var au = a >> 32; + var ad = a & 0xFFFFFFFF; + var bu = b >> 32; + var bd = b & 0xFFFFFFFF; + + var l = ad * bd; + var m1 = au * bd; + var m2 = ad * bu; + var h = au * bu; + + var lu = l >> 32; + var m1d = m1 & 0xFFFFFFFF; + var m2d = m2 & 0xFFFFFFFF; + var c = m1d + m2d + lu; + + return h + (m1 >> 32) + (m2 >> 32) + (c >> 32); + } + } +} diff --git a/Source/ac-library-csharp/Math/Internal/Butterfly.cs b/Source/ac-library-csharp/Math/Internal/Butterfly.cs index 53384266..72da1485 100644 --- a/Source/ac-library-csharp/Math/Internal/Butterfly.cs +++ b/Source/ac-library-csharp/Math/Internal/Butterfly.cs @@ -193,7 +193,7 @@ public static void CalculateInv(Span> a) [EditorBrowsable(EditorBrowsableState.Never)] public static StaticModInt[] CalcurateSumE() { - int g = InternalMath.PrimitiveRoot(); + int g = ModPrimitiveRoot.PrimitiveRoot(); int cnt2 = InternalBit.Bsf(default(T).Mod - 1); var e = new StaticModInt(g).Pow((default(T).Mod - 1) >> cnt2); var ie = e.Inv(); @@ -238,7 +238,7 @@ public static StaticModInt[] CalcurateSumE() [EditorBrowsable(EditorBrowsableState.Never)] public static StaticModInt[] CalcurateSumIE() { - int g = InternalMath.PrimitiveRoot(); + int g = ModPrimitiveRoot.PrimitiveRoot(); int cnt2 = InternalBit.Bsf(default(T).Mod - 1); var e = new StaticModInt(g).Pow((default(T).Mod - 1) >> cnt2); var ie = e.Inv(); diff --git a/Source/ac-library-csharp/Math/Internal/Convolution.cs b/Source/ac-library-csharp/Math/Internal/Convolution.cs new file mode 100644 index 00000000..ab018608 --- /dev/null +++ b/Source/ac-library-csharp/Math/Internal/Convolution.cs @@ -0,0 +1,213 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +#if NETCOREAPP3_1_OR_GREATER +using System.Runtime.InteropServices; +#endif + +namespace AtCoder.Internal +{ + public static class ConvolutionImpl + { + /// + /// 畳ã¿è¾¼ã¿ã‚’ mod ã§è¨ˆç®—ã—ã¾ã™ã€‚ + /// + /// + /// , ã®å°‘ãªãã¨ã‚‚一方ãŒç©ºã®å ´åˆã¯ç©ºé…列を返ã—ã¾ã™ã€‚ + /// 制約: + /// - 2≤≤2×10^9 + /// - ã¯ç´ æ•° + /// - 2^c | ( - 1) ã‹ã¤ || + || - 1 ≤ 2^c ãªã‚‹ c ãŒå­˜åœ¨ã™ã‚‹ + /// 計算é‡: O((||+||)log(||+||) + log) + /// + [MethodImpl(256)] + public static StaticModInt[] Convolution(ReadOnlySpan> a, ReadOnlySpan> b) + where TMod : struct, IStaticMod + { + var n = a.Length; + var m = b.Length; + if (n == 0 || m == 0) + return Array.Empty>(); + if (Math.Min(n, m) <= 60) + return ConvolutionNaive(a, b); + return ConvolutionFFT(a, b); + } + + [MethodImpl(256)] + private static StaticModInt[] ConvolutionFFT(ReadOnlySpan> a, ReadOnlySpan> b) + where TMod : struct, IStaticMod + { + int n = a.Length, m = b.Length; + int z = 1 << InternalBit.CeilPow2(n + m - 1); + var a2 = new StaticModInt[z]; + var b2 = new StaticModInt[z]; + a.CopyTo(a2); + b.CopyTo(b2); + + var result = ConvolutionFFTInner(a2, b2); + Array.Resize(ref result, n + m - 1); + var iz = new StaticModInt(z).Inv(); + for (int i = 0; i < result.Length; i++) + result[i] *= iz; + + return result; + } + + [MethodImpl(256)] + private static StaticModInt[] ConvolutionFFTInner(StaticModInt[] a, StaticModInt[] b) + where TMod : struct, IStaticMod + { + Butterfly.Calculate(a); + Butterfly.Calculate(b); + for (int i = 0; i < a.Length; i++) + a[i] *= b[i]; + Butterfly.CalculateInv(a); + return a; + } + [MethodImpl(256)] + private static StaticModInt[] ConvolutionNaive(ReadOnlySpan> a, ReadOnlySpan> b) + where TMod : struct, IStaticMod + { + if (a.Length < b.Length) + { + var temp = a; + a = b; + b = temp; + } + + var ans = new StaticModInt[a.Length + b.Length - 1]; + for (int i = 0; i < a.Length; i++) + { + for (int j = 0; j < b.Length; j++) + { + ans[i + j] += a[i] * b[j]; + } + } + + return ans; + } + + /// + /// 畳ã¿è¾¼ã¿ã‚’計算ã—ã¾ã™ã€‚ + /// + /// + /// , ã®å°‘ãªãã¨ã‚‚一方ãŒç©ºã®å ´åˆã¯ç©ºé…列を返ã—ã¾ã™ã€‚ + /// 制約: + /// - || + || - 1 ≤ 2^24 = 16,777,216 + /// - 畳ã¿è¾¼ã‚“ã å¾Œã®é…列ã®è¦ç´ ãŒå…¨ã¦ long ã«åŽã¾ã‚‹ + /// 計算é‡: O((||+||)log(||+||)) + /// + [MethodImpl(256)] + public static long[] ConvolutionLong(ReadOnlySpan a, ReadOnlySpan b) + { + unchecked + { + var n = a.Length; + var m = b.Length; + + if (n == 0 || m == 0) + { + return Array.Empty(); + } + + const ulong Mod1 = 754974721; // 2^24 + const ulong Mod2 = 167772161; // 2^25 + const ulong Mod3 = 469762049; // 2^26 + const ulong M2M3 = Mod2 * Mod3; + const ulong M1M3 = Mod1 * Mod3; + const ulong M1M2 = Mod1 * Mod2; + // (m1 * m2 * m3) % 2^64 + const ulong M1M2M3 = Mod1 * Mod2 * Mod3; + + const ulong i1 = 190329765; + const ulong i2 = 58587104; + const ulong i3 = 187290749; + + Debug.Assert(default(FFTMod1).Mod == Mod1); + Debug.Assert(default(FFTMod2).Mod == Mod2); + Debug.Assert(default(FFTMod3).Mod == Mod3); + Debug.Assert(i1 == (ulong)ModCalc.InvGcd((long)M2M3, (long)Mod1).Item2); + Debug.Assert(i2 == (ulong)ModCalc.InvGcd((long)M1M3, (long)Mod2).Item2); + Debug.Assert(i3 == (ulong)ModCalc.InvGcd((long)M1M2, (long)Mod3).Item2); + + var c1 = Convolution(ToModInt(a), ToModInt(b)); + var c2 = Convolution(ToModInt(a), ToModInt(b)); + var c3 = Convolution(ToModInt(a), ToModInt(b)); + + var c = new long[n + m - 1]; + + //ReadOnlySpan offset = stackalloc ulong[] { 0, 0, M1M2M3, 2 * M1M2M3, 3 * M1M2M3 }; + + for (int i = 0; i < c.Length; i++) + { + ulong x = 0; + x += ((ulong)c1[i].Value * i1) % Mod1 * M2M3; + x += ((ulong)c2[i].Value * i2) % Mod2 * M1M3; + x += ((ulong)c3[i].Value * i3) % Mod3 * M1M2; + + long diff = c1[i].Value - ModCalc.SafeMod((long)x, (long)Mod1); + if (diff < 0) + { + diff += (long)Mod1; + } + + // 真値を r, 得られãŸå€¤ã‚’ x, M1M2M3 % 2^64 = M', B = 2^63 ã¨ã—ã¦ã€ + // r = x, + // x - M' + (0 or 2B), + // x - 2M' + (0 or 2B or 4B), + // x - 3M' + (0 or 2B or 4B or 6B) + // ã®ã„ãšã‚Œã‹ãŒæˆã‚Šç«‹ã¤ã€ã‚‰ã—ã„ + // -> see atcoder/convolution.hpp + switch (diff % 5) + { + case 2: + x -= M1M2M3; + break; + case 3: + x -= 2 * M1M2M3; + break; + case 4: + x -= 3 * M1M2M3; + break; + } + c[i] = (long)x; + } + + return c; + } + } + static StaticModInt[] ToModInt(ReadOnlySpan a) where T : struct, IStaticMod + { + if (a.IsEmpty) return Array.Empty>(); + + var c = new StaticModInt[a.Length]; +#if NETCOREAPP3_1_OR_GREATER + ref var ap = ref MemoryMarshal.GetReference(a); + for (int i = 0; i < c.Length; i++) + c[i] = Unsafe.Add(ref ap, i); +#else + for (int i = 0; i < c.Length; i++) + c[i] = a[i]; +#endif + return c; + } + + private readonly struct FFTMod1 : IStaticMod + { + public uint Mod => 754974721; + public bool IsPrime => true; + } + + private readonly struct FFTMod2 : IStaticMod + { + public uint Mod => 167772161; + public bool IsPrime => true; + } + + private readonly struct FFTMod3 : IStaticMod + { + public uint Mod => 469762049; + public bool IsPrime => true; + } + } +} diff --git a/Source/ac-library-csharp/Math/Internal/FloorSum.cs b/Source/ac-library-csharp/Math/Internal/FloorSum.cs new file mode 100644 index 00000000..2fb22cc3 --- /dev/null +++ b/Source/ac-library-csharp/Math/Internal/FloorSum.cs @@ -0,0 +1,67 @@ +using System.Runtime.CompilerServices; + +namespace AtCoder.Internal +{ + public static class FloorSum + { + /// + /// sum_{i=0}^{-1} floor((*i+)/) ã‚’è¿”ã—ã¾ã™ã€‚ç­”ãˆãŒã‚ªãƒ¼ãƒãƒ¼ãƒ•ãƒ­ãƒ¼ã—ãŸãªã‚‰ã°  mod2^64 ã§ç­‰ã—ã„値を返ã—ã¾ã™ã€‚ + /// + /// + /// 制約: + /// 0≤<2^32 + /// 1≤<2^32 + /// 計算é‡: O(log(m)) + /// + /// + [MethodImpl(256)] + public static long FloorSumSigned(long n, long m, long a, long b) + { + Contract.Assert(0 <= n && n < (1L << 32)); + Contract.Assert(1 <= m && m < (1L << 32)); + var nn = (ulong)n; + var mm = (ulong)m; + ulong aa, bb; + ulong ans = 0; + if (a < 0) + { + var a2 = (ulong)ModCalc.SafeMod(a, m); + ans -= nn * (nn - 1) / 2 * ((a2 - (ulong)a) / mm); + aa = a2; + } + else aa = (ulong)a; + if (b < 0) + { + var b2 = (ulong)ModCalc.SafeMod(b, m); + ans -= nn * ((b2 - (ulong)b) / mm); + bb = b2; + } + else bb = (ulong)b; + + return (long)(ans + FloorSumUnsigned(nn, mm, aa, bb)); + } + + [MethodImpl(256)] + public static ulong FloorSumUnsigned(ulong n, ulong m, ulong a, ulong b) + { + ulong ans = 0; + while (true) + { + if (a >= m) + { + ans += (n - 1) * n / 2 * (a / m); + a %= m; + } + if (b >= m) + { + ans += n * (b / m); + b %= m; + } + + ulong yMax = a * n + b; + if (yMax < m) return ans; + (n, m, a, b) = (yMax / m, a, m, yMax % m); + } + } + } +} diff --git a/Source/ac-library-csharp/Math/Internal/InternalMath.cs b/Source/ac-library-csharp/Math/Internal/InternalMath.cs index a3832447..1b681a04 100644 --- a/Source/ac-library-csharp/Math/Internal/InternalMath.cs +++ b/Source/ac-library-csharp/Math/Internal/InternalMath.cs @@ -1,135 +1,33 @@ using System; -using System.Collections.Generic; using System.Runtime.CompilerServices; -#if NETCOREAPP3_1_OR_GREATER -using System.Runtime.Intrinsics.X86; -using System.Numerics; -#endif + namespace AtCoder.Internal { public static class InternalMath { - private static readonly Dictionary primitiveRootsCache = new Dictionary() - { - { 2, 1 }, - { 167772161, 3 }, - { 469762049, 3 }, - { 754974721, 11 }, - { 998244353, 3 } - }; - - /// - /// ã®æœ€å°ã®åŽŸå§‹æ ¹ã‚’求ã‚ã¾ã™ã€‚ - /// - /// - /// 制約: ã¯ç´ æ•° - /// + /// [MethodImpl(256)] - public static int PrimitiveRoot() where TMod : struct, IStaticMod - { - uint m = default(TMod).Mod; - Contract.Assert(m >= 2, reason: $"{nameof(m)} must be greater or equal 2"); - Contract.Assert(default(TMod).IsPrime, reason: $"{nameof(m)} must be prime number"); - -#if NET7_0_OR_GREATER - ref var result = ref System.Runtime.InteropServices.CollectionsMarshal.GetValueRefOrAddDefault(primitiveRootsCache, m, out var exists); - if (!exists) - { - result = PrimitiveRootCalculate(); - } - return result; -#else - if (primitiveRootsCache.TryGetValue(m, out var p)) - { - return p; - } - - return primitiveRootsCache[m] = PrimitiveRootCalculate(); -#endif - } - static int PrimitiveRootCalculate() where TMod : struct, IStaticMod - { - var m = default(TMod).Mod; - Span divs = stackalloc uint[20]; - divs[0] = 2; - int cnt = 1; - var x = m - 1; - x >>= BitOperations.TrailingZeroCount(x); - - for (uint i = 3; (long)i * i <= x; i += 2) - { - if (x % i == 0) - { - divs[cnt++] = i; - do - { - x /= i; - } while (x % i == 0); - } - } + public static int PrimitiveRoot() where TMod : struct, IStaticMod => ModPrimitiveRoot.PrimitiveRoot(); - if (x > 1) - { - divs[cnt++] = x; - } - divs = divs.Slice(0, cnt); - - for (int g = 2; ; g++) - { - foreach (var d in divs) - if (new StaticModInt(g).Pow((m - 1) / d).Value == 1) - goto NEXT; - return g; - NEXT:; - } - } - - /// - /// g=gcd(a,b),xa=g(mod b) ã¨ãªã‚‹ã‚ˆã†ãª 0≤x<b/g ã®(g, x) - /// - /// - /// 制約: 1≤ - /// + /// [MethodImpl(256)] public static (long, long) InvGcd(long a, long b) - { - a = SafeMod(a, b); - if (a == 0) return (b, 0); - - long s = b, t = a; - long m0 = 0, m1 = 1; + => ModCalc.InvGcd(a, b); - long u; - while (true) - { - if (t == 0) - { - if (m0 < 0) m0 += b / s; - return (s, m0); - } - u = s / t; - s -= t * u; - m0 -= m1 * u; + /// + [MethodImpl(256)] + public static long SafeMod(long x, long m) + => ModCalc.SafeMod(x, m); - if (s == 0) - { - if (m1 < 0) m1 += b / t; - return (t, m1); - } - u = t / s; - t -= s * u; - m1 -= m0 * u; - } - } + /// + [MethodImpl(256)] + public static uint PowMod(long x, long n, int m) + => ModCalc.PowMod(x, n, m); + /// [MethodImpl(256)] - public static long SafeMod(long x, long m) - { - x %= m; - if (x < 0) x += m; - return x; - } + public static ulong Mul128Bit(ulong a, ulong b) => Mul128.Mul128Bit(a, b); /// /// ãŒç´ æ•°ã‹ã‚’è¿”ã—ã¾ã™ã€‚ @@ -159,116 +57,10 @@ public static bool IsPrime(int n) } return true; } - /// - /// - /// - [MethodImpl(256)] - public static uint PowMod(long x, long n, int m) - { - Contract.Assert(0 <= n && 1 <= m, reason: $"0 <= {nameof(n)} && 1 <= {nameof(m)}"); - if (m == 1) return 0; - return new Barrett((uint)m).Pow(x, n); - } + /// [MethodImpl(256)] public static ulong FloorSumUnsigned(ulong n, ulong m, ulong a, ulong b) - { - ulong ans = 0; - while (true) - { - if (a >= m) - { - ans += (n - 1) * n / 2 * (a / m); - a %= m; - } - if (b >= m) - { - ans += n * (b / m); - b %= m; - } - - ulong yMax = a * n + b; - if (yMax < m) return ans; - (n, m, a, b) = (yMax / m, a, m, yMax % m); - } - } - - /// - /// * ã®ä¸Šä½ 64 ビットを返ã—ã¾ã™ã€‚ - /// - /// - /// - /// - [MethodImpl(256)] - public static ulong Mul128Bit(ulong a, ulong b) - { -#if NETCOREAPP3_1_OR_GREATER - if (Bmi2.X64.IsSupported) - return Bmi2.X64.MultiplyNoFlags(a, b); -#endif - return Mul128BitLogic(a, b); - } - - /// - /// * ã®ä¸Šä½ 64 ビットを返ã—ã¾ã™ã€‚ - /// - /// - /// - /// - [MethodImpl(256)] - internal static ulong Mul128BitLogic(ulong a, ulong b) - { - /* - * ã“ã“ã§ã¯ 64 bit æ•´æ•° X ã®ä¸Šä½, ä¸‹ä½ 32 bit ã‚’ãã‚Œãžã‚Œ Xu ,Xd ã¨è¡¨ã™ - * A * B を計算ã™ã‚‹ã€‚ - * - * 変数を下記ã®ã‚ˆã†ã«å®šç¾©ã™ã‚‹ã€‚ - * s := 1ul << 32 - * R := A * B - * L := Ad * Bd - * M1 := Ad * Bu - * M2 := Au * Bd - * H := Au * Bu - * - * A * B = s * s * H + s * (M1 + M2) + L - * ã§ã‚ã‚‹ã“ã¨ã‚’使ã£ã¦ - * R = s * s * x + y - * ã¨è¡¨ã›ã‚‹ x, y を求ã‚ãŸã„ (x, y < s * s) - * - * A * B - * = s * s * H + s * (s * M1u + M1d + s * M2u + M2d) + L - * = s * s * H + s * (s * (M1u + M2u) + M1d + M2d) + L - * = s * s * (H + M1u + M2u) + s * (M1d + M2d) + L - * - * ã¨è¡¨ã›ã‚‹ã®ã§ã€ç¹°ã‚Šä¸ŠãŒã‚Šã‚’考慮ã—ãªã‘れ㰠- * x = H + M1u + M2u - * y = s * (M1d + M2d) + L = s * (M1d + M2d + Lu) + Ld - * ã¨ãªã‚‹ - * - * 繰り上ãŒã‚‹ã®ã¯ - * M1d + M2d + Lu ã®ä¸Šä½ 32 bit ãªã®ã§ - * C := M1d + M2d + Lu - * ã¨ã™ã‚‹ã¨ - * - * x = H + M1u + M2u + Cu - * ã¨ãªã‚‹ - */ - var au = a >> 32; - var ad = a & 0xFFFFFFFF; - var bu = b >> 32; - var bd = b & 0xFFFFFFFF; - - var l = ad * bd; - var m1 = au * bd; - var m2 = ad * bu; - var h = au * bu; - - var lu = l >> 32; - var m1d = m1 & 0xFFFFFFFF; - var m2d = m2 & 0xFFFFFFFF; - var c = m1d + m2d + lu; - - return h + (m1 >> 32) + (m2 >> 32) + (c >> 32); - } + => FloorSum.FloorSumUnsigned(n, m, a, b); } } diff --git a/Source/ac-library-csharp/Math/Internal/ModCalc.cs b/Source/ac-library-csharp/Math/Internal/ModCalc.cs new file mode 100644 index 00000000..1be9ff5d --- /dev/null +++ b/Source/ac-library-csharp/Math/Internal/ModCalc.cs @@ -0,0 +1,129 @@ +using System.Runtime.CompilerServices; + +namespace AtCoder.Internal +{ + /// + /// Mod 関連ã®è¨ˆç®— + /// + public static class ModCalc + { + /// + /// y≡1(mod ) ãªã‚‹ y ã®ã†ã¡ã€0≤y< を満ãŸã™ã‚‚ã®ã‚’è¿”ã—ã¾ã™ã€‚ + /// + /// + /// 制約: gcd(,)=1, 1≤ + /// 計算é‡: O(log) + /// + [MethodImpl(256)] + public static long InvMod(long x, long m) + { + Contract.Assert(1 <= m, reason: $"1 <= {nameof(m)}"); + var (g, res) = InvGcd(x, m); + Contract.Assert(g == 1, reason: $"gcd({nameof(x)}, {nameof(m)}) must be 1."); + return res; + } + + /// + /// g=gcd(a,b),xa=g(mod b) ã¨ãªã‚‹ã‚ˆã†ãª 0≤x<b/g ã®(g, x) + /// + /// + /// 制約: 1≤ + /// + [MethodImpl(256)] + public static (long, long) InvGcd(long a, long b) + { + a = SafeMod(a, b); + if (a == 0) return (b, 0); + + long s = b, t = a; + long m0 = 0, m1 = 1; + + long u; + while (true) + { + if (t == 0) + { + if (m0 < 0) m0 += b / s; + return (s, m0); + } + u = s / t; + s -= t * u; + m0 -= m1 * u; + + if (s == 0) + { + if (m1 < 0) m1 += b / t; + return (t, m1); + } + u = t / s; + t -= s * u; + m1 -= m0 * u; + } + } + + [MethodImpl(256)] + public static long SafeMod(long x, long m) + { + x %= m; + if (x < 0) x += m; + return x; + } + + /// + /// ^ mod ã‚’è¿”ã—ã¾ã™ã€‚ + /// + /// + /// 制約: 0≤, 1≤ + /// 計算é‡: O(log) + /// + [MethodImpl(256)] + public static uint PowMod(long x, long n, int m) + { + Contract.Assert(0 <= n && 1 <= m, reason: $"0 <= {nameof(n)} && 1 <= {nameof(m)}"); + if (m == 1) return 0; + return new Barrett((uint)m).Pow(x, n); + } + + /// + /// åŒã˜é•·ã• n ã®é…列 , ã«ã¤ã„ã¦ã€x≡[i] (mod [i]),∀i∈{0,1,⋯,n−1} を解ãã¾ã™ã€‚ + /// + /// + /// 制約: ||=||, 1≤[i], lcm(m[i]) ㌠ll ã«åŽã¾ã‚‹ + /// 計算é‡: O(nloglcm()) + /// + /// ç­”ãˆã¯(存在ã™ã‚‹ãªã‚‰ã°) y,z(0≤y<z=lcm([i])) を用ã„㦠x≡y(mod z) ã®å½¢ã§æ›¸ã‘る。答ãˆãŒãªã„å ´åˆã¯(0,0)ã€n=0 ã®æ™‚ã¯(0,1)ã€ãれ以外ã®å ´åˆã¯(y,z)。 + [MethodImpl(256)] + public static (long y, long z) Crt(long[] r, long[] m) + { + Contract.Assert(r.Length == m.Length, reason: $"Length of {nameof(r)} and {nameof(m)} must be same."); + + long r0 = 0, m0 = 1; + for (int i = 0; i < m.Length; i++) + { + Contract.Assert(1 <= m[i], reason: $"All of {nameof(m)} must be greater or equal 1."); + long r1 = SafeMod(r[i], m[i]); + long m1 = m[i]; + if (m0 < m1) + { + (r0, r1) = (r1, r0); + (m0, m1) = (m1, m0); + } + if (m0 % m1 == 0) + { + if (r0 % m1 != r1) return (0, 0); + continue; + } + var (g, im) = InvGcd(m0, m1); + + long u1 = (m1 / g); + if ((r1 - r0) % g != 0) return (0, 0); + + long x = (r1 - r0) / g % u1 * im % u1; + r0 += x * m0; + m0 *= u1; + if (r0 < 0) r0 += m0; + } + return (r0, m0); + } + } +} diff --git a/Source/ac-library-csharp/Math/Internal/ModPrimitiveRoot.cs b/Source/ac-library-csharp/Math/Internal/ModPrimitiveRoot.cs new file mode 100644 index 00000000..af403eea --- /dev/null +++ b/Source/ac-library-csharp/Math/Internal/ModPrimitiveRoot.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +#if NETCOREAPP3_1_OR_GREATER +using System.Numerics; +#endif +#if NET7_0_OR_GREATER +using System.Runtime.InteropServices; +#endif + +namespace AtCoder.Internal +{ + public static class ModPrimitiveRoot + { + private static readonly Dictionary primitiveRootsCache = new Dictionary() + { + { 2, 1 }, + { 167772161, 3 }, + { 469762049, 3 }, + { 754974721, 11 }, + { 998244353, 3 } + }; + + /// + /// ã®æœ€å°ã®åŽŸå§‹æ ¹ã‚’求ã‚ã¾ã™ã€‚ + /// + /// + /// 制約: ã¯ç´ æ•° + /// + [MethodImpl(256)] + public static int PrimitiveRoot() where TMod : struct, IStaticMod + { + uint m = default(TMod).Mod; + Contract.Assert(m >= 2, reason: $"{nameof(m)} must be greater or equal 2"); + Contract.Assert(default(TMod).IsPrime, reason: $"{nameof(m)} must be prime number"); + +#if NET7_0_OR_GREATER + ref var result = ref CollectionsMarshal.GetValueRefOrAddDefault(primitiveRootsCache, m, out var exists); + if (!exists) + { + result = PrimitiveRootCalculate(); + } + return result; +#else + if (primitiveRootsCache.TryGetValue(m, out var p)) + { + return p; + } + + return primitiveRootsCache[m] = PrimitiveRootCalculate(); +#endif + } + static int PrimitiveRootCalculate() where TMod : struct, IStaticMod + { + var m = default(TMod).Mod; + Span divs = stackalloc uint[20]; + divs[0] = 2; + int cnt = 1; + var x = m - 1; + x >>= BitOperations.TrailingZeroCount(x); + + for (uint i = 3; (long)i * i <= x; i += 2) + { + if (x % i == 0) + { + divs[cnt++] = i; + do + { + x /= i; + } while (x % i == 0); + } + } + + if (x > 1) + { + divs[cnt++] = x; + } + divs = divs.Slice(0, cnt); + + for (int g = 2; ; g++) + { + foreach (var d in divs) + if (new StaticModInt(g).Pow((m - 1) / d).Value == 1) + goto NEXT; + return g; + NEXT:; + } + } + } +} diff --git a/Source/ac-library-csharp/Math/MathLib.Convolution.cs b/Source/ac-library-csharp/Math/MathLib.Convolution.cs index 85a50df7..53fc0ea8 100644 --- a/Source/ac-library-csharp/Math/MathLib.Convolution.cs +++ b/Source/ac-library-csharp/Math/MathLib.Convolution.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.Runtime.CompilerServices; using AtCoder.Internal; @@ -37,71 +36,7 @@ public static StaticModInt[] Convolution(StaticModInt[] a, Sta [MethodImpl(256)] public static StaticModInt[] Convolution(ReadOnlySpan> a, ReadOnlySpan> b) where TMod : struct, IStaticMod - { - var n = a.Length; - var m = b.Length; - if (n == 0 || m == 0) - return Array.Empty>(); - if (Math.Min(n, m) <= 60) - return ConvolutionNaive(a, b); - return ConvolutionFFT(a, b); - } - - [MethodImpl(256)] - private static StaticModInt[] ConvolutionFFT(ReadOnlySpan> a, ReadOnlySpan> b) - where TMod : struct, IStaticMod - { - int n = a.Length, m = b.Length; - int z = 1 << InternalBit.CeilPow2(n + m - 1); - var a2 = new StaticModInt[z]; - var b2 = new StaticModInt[z]; - a.CopyTo(a2); - b.CopyTo(b2); - - var result = ConvolutionFFTInner(a2, b2); - Array.Resize(ref result, n + m - 1); - var iz = new StaticModInt(z).Inv(); - for (int i = 0; i < result.Length; i++) - result[i] *= iz; - - return result; - } - - [MethodImpl(256)] - private static StaticModInt[] ConvolutionFFTInner(StaticModInt[] a, StaticModInt[] b) - where TMod : struct, IStaticMod - { - Butterfly.Calculate(a); - Butterfly.Calculate(b); - for (int i = 0; i < a.Length; i++) - a[i] *= b[i]; - Butterfly.CalculateInv(a); - return a; - } - [MethodImpl(256)] - private static StaticModInt[] ConvolutionNaive(ReadOnlySpan> a, ReadOnlySpan> b) - where TMod : struct, IStaticMod - { - if (a.Length < b.Length) - { -#pragma warning disable IDE0180 // ref 構造体ã®ãŸã‚型引数ã¨ã—ã¦ä½¿ãˆãªã„ - var temp = a; - a = b; - b = temp; -#pragma warning restore IDE0180 - } - - var ans = new StaticModInt[a.Length + b.Length - 1]; - for (int i = 0; i < a.Length; i++) - { - for (int j = 0; j < b.Length; j++) - { - ans[i + j] += a[i] * b[j]; - } - } - - return ans; - } + => ConvolutionImpl.Convolution(a, b); /// /// 畳ã¿è¾¼ã¿ã‚’計算ã—ã¾ã™ã€‚ @@ -115,100 +50,6 @@ private static StaticModInt[] ConvolutionNaive(ReadOnlySpan [MethodImpl(256)] public static long[] ConvolutionLong(ReadOnlySpan a, ReadOnlySpan b) - { - unchecked - { - var n = a.Length; - var m = b.Length; - - if (n == 0 || m == 0) - { - return Array.Empty(); - } - - const ulong Mod1 = 754974721; // 2^24 - const ulong Mod2 = 167772161; // 2^25 - const ulong Mod3 = 469762049; // 2^26 - const ulong M2M3 = Mod2 * Mod3; - const ulong M1M3 = Mod1 * Mod3; - const ulong M1M2 = Mod1 * Mod2; - // (m1 * m2 * m3) % 2^64 - const ulong M1M2M3 = Mod1 * Mod2 * Mod3; - - const ulong i1 = 190329765; - const ulong i2 = 58587104; - const ulong i3 = 187290749; - - Debug.Assert(default(FFTMod1).Mod == Mod1); - Debug.Assert(default(FFTMod2).Mod == Mod2); - Debug.Assert(default(FFTMod3).Mod == Mod3); - Debug.Assert(i1 == (ulong)InternalMath.InvGcd((long)M2M3, (long)Mod1).Item2); - Debug.Assert(i2 == (ulong)InternalMath.InvGcd((long)M1M3, (long)Mod2).Item2); - Debug.Assert(i3 == (ulong)InternalMath.InvGcd((long)M1M2, (long)Mod3).Item2); - - var c1 = Convolution(a, b); - var c2 = Convolution(a, b); - var c3 = Convolution(a, b); - - var c = new long[n + m - 1]; - - //ReadOnlySpan offset = stackalloc ulong[] { 0, 0, M1M2M3, 2 * M1M2M3, 3 * M1M2M3 }; - - for (int i = 0; i < c.Length; i++) - { - ulong x = 0; - x += ((ulong)c1[i] * i1) % Mod1 * M2M3; - x += ((ulong)c2[i] * i2) % Mod2 * M1M3; - x += ((ulong)c3[i] * i3) % Mod3 * M1M2; - - long diff = c1[i] - InternalMath.SafeMod((long)x, (long)Mod1); - if (diff < 0) - { - diff += (long)Mod1; - } - - // 真値を r, 得られãŸå€¤ã‚’ x, M1M2M3 % 2^64 = M', B = 2^63 ã¨ã—ã¦ã€ - // r = x, - // x - M' + (0 or 2B), - // x - 2M' + (0 or 2B or 4B), - // x - 3M' + (0 or 2B or 4B or 6B) - // ã®ã„ãšã‚Œã‹ãŒæˆã‚Šç«‹ã¤ã€ã‚‰ã—ã„ - // -> see atcoder/convolution.hpp - switch (diff % 5) - { - case 2: - x -= M1M2M3; - break; - case 3: - x -= 2 * M1M2M3; - break; - case 4: - x -= 3 * M1M2M3; - break; - } - c[i] = (long)x; - } - - return c; - } - } - - private readonly struct FFTMod1 : IStaticMod - { - public uint Mod => 754974721; - public bool IsPrime => true; - } - - private readonly struct FFTMod2 : IStaticMod - { - public uint Mod => 167772161; - public bool IsPrime => true; - } - - private readonly struct FFTMod3 : IStaticMod - { - public uint Mod => 469762049; - public bool IsPrime => true; - } + => ConvolutionImpl.ConvolutionLong(a, b); } } diff --git a/Source/ac-library-csharp/Math/MathLib.Crt.cs b/Source/ac-library-csharp/Math/MathLib.Crt.cs index 32897c03..9616b067 100644 --- a/Source/ac-library-csharp/Math/MathLib.Crt.cs +++ b/Source/ac-library-csharp/Math/MathLib.Crt.cs @@ -5,46 +5,9 @@ namespace AtCoder { public static partial class MathLib { - /// - /// åŒã˜é•·ã• n ã®é…列 , ã«ã¤ã„ã¦ã€x≡[i] (mod [i]),∀i∈{0,1,⋯,n−1} を解ãã¾ã™ã€‚ - /// - /// - /// 制約: ||=||, 1≤[i], lcm(m[i]) ㌠ll ã«åŽã¾ã‚‹ - /// 計算é‡: O(nloglcm()) - /// - /// ç­”ãˆã¯(存在ã™ã‚‹ãªã‚‰ã°) y,z(0≤y<z=lcm([i])) を用ã„㦠x≡y(mod z) ã®å½¢ã§æ›¸ã‘る。答ãˆãŒãªã„å ´åˆã¯(0,0)ã€n=0 ã®æ™‚ã¯(0,1)ã€ãれ以外ã®å ´åˆã¯(y,z)。 + /// [MethodImpl(256)] public static (long y, long z) Crt(long[] r, long[] m) - { - Contract.Assert(r.Length == m.Length, reason: $"Length of {nameof(r)} and {nameof(m)} must be same."); - - long r0 = 0, m0 = 1; - for (int i = 0; i < m.Length; i++) - { - Contract.Assert(1 <= m[i], reason: $"All of {nameof(m)} must be greater or equal 1."); - long r1 = InternalMath.SafeMod(r[i], m[i]); - long m1 = m[i]; - if (m0 < m1) - { - (r0, r1) = (r1, r0); - (m0, m1) = (m1, m0); - } - if (m0 % m1 == 0) - { - if (r0 % m1 != r1) return (0, 0); - continue; - } - var (g, im) = InternalMath.InvGcd(m0, m1); - - long u1 = (m1 / g); - if ((r1 - r0) % g != 0) return (0, 0); - - long x = (r1 - r0) / g % u1 * im % u1; - r0 += x * m0; - m0 *= u1; - if (r0 < 0) r0 += m0; - } - return (r0, m0); - } + => ModCalc.Crt(r, m); } } diff --git a/Source/ac-library-csharp/Math/MathLib.FloorSum.cs b/Source/ac-library-csharp/Math/MathLib.FloorSum.cs index 338c1749..00ad33e3 100644 --- a/Source/ac-library-csharp/Math/MathLib.FloorSum.cs +++ b/Source/ac-library-csharp/Math/MathLib.FloorSum.cs @@ -1,45 +1,12 @@ using System.Runtime.CompilerServices; -using AtCoder.Internal; namespace AtCoder { public static partial class MathLib { - /// - /// sum_{i=0}^{-1} floor(*i+/) ã‚’è¿”ã—ã¾ã™ã€‚ç­”ãˆãŒã‚ªãƒ¼ãƒãƒ¼ãƒ•ãƒ­ãƒ¼ã—ãŸãªã‚‰ã°  mod2^64 ã§ç­‰ã—ã„値を返ã—ã¾ã™ã€‚ - /// - /// - /// 制約: - /// 0≤<2^32 - /// 1≤<2^32 - /// 計算é‡: O(log(m)) - /// - /// + /// [MethodImpl(256)] public static long FloorSum(long n, long m, long a, long b) - { - Contract.Assert(0 <= n && n < (1L << 32)); - Contract.Assert(1 <= m && m < (1L << 32)); - var nn = (ulong)n; - var mm = (ulong)m; - ulong aa, bb; - ulong ans = 0; - if (a < 0) - { - var a2 = (ulong)InternalMath.SafeMod(a, m); - ans -= nn * (nn - 1) / 2 * ((a2 - (ulong)a) / mm); - aa = a2; - } - else aa = (ulong)a; - if (b < 0) - { - var b2 = (ulong)InternalMath.SafeMod(b, m); - ans -= nn * ((b2 - (ulong)b) / mm); - bb = b2; - } - else bb = (ulong)b; - - return (long)(ans + InternalMath.FloorSumUnsigned(nn, mm, aa, bb)); - } + => Internal.FloorSum.FloorSumSigned(n, m, a, b); } } diff --git a/Source/ac-library-csharp/Math/MathLib.InvMod.cs b/Source/ac-library-csharp/Math/MathLib.InvMod.cs index 980e2d0b..fac821f9 100644 --- a/Source/ac-library-csharp/Math/MathLib.InvMod.cs +++ b/Source/ac-library-csharp/Math/MathLib.InvMod.cs @@ -5,20 +5,9 @@ namespace AtCoder { public static partial class MathLib { - /// - /// y≡1(mod ) ãªã‚‹ y ã®ã†ã¡ã€0≤y< を満ãŸã™ã‚‚ã®ã‚’è¿”ã—ã¾ã™ã€‚ - /// - /// - /// 制約: gcd(,)=1, 1≤ - /// 計算é‡: O(log) - /// + /// [MethodImpl(256)] public static long InvMod(long x, long m) - { - Contract.Assert(1 <= m, reason: $"1 <= {nameof(m)}"); - var (g, res) = InternalMath.InvGcd(x, m); - Contract.Assert(g == 1, reason: $"gcd({nameof(x)}, {nameof(m)}) must be 1."); - return res; - } + => ModCalc.InvMod(x, m); } } diff --git a/Source/ac-library-csharp/Math/MathLib.PowMod.cs b/Source/ac-library-csharp/Math/MathLib.PowMod.cs index 388dd2a6..1bd7d8ad 100644 --- a/Source/ac-library-csharp/Math/MathLib.PowMod.cs +++ b/Source/ac-library-csharp/Math/MathLib.PowMod.cs @@ -5,15 +5,9 @@ namespace AtCoder { public static partial class MathLib { - /// - /// ^ mod ã‚’è¿”ã—ã¾ã™ã€‚ - /// - /// - /// 制約: 0≤, 1≤ - /// 計算é‡: O(log) - /// + /// [MethodImpl(256)] public static long PowMod(long x, long n, int m) - => InternalMath.PowMod(x, n, m); + => ModCalc.PowMod(x, n, m); } } diff --git a/Source/ac-library-csharp/Math/DynamicModInt.cs b/Source/ac-library-csharp/Math/ModInt/DynamicModInt.cs similarity index 88% rename from Source/ac-library-csharp/Math/DynamicModInt.cs rename to Source/ac-library-csharp/Math/ModInt/DynamicModInt.cs index 9d5f305a..c1ffa405 100644 --- a/Source/ac-library-csharp/Math/DynamicModInt.cs +++ b/Source/ac-library-csharp/Math/ModInt/DynamicModInt.cs @@ -47,10 +47,7 @@ public static class DynamicModIntIdExtension /// /// public readonly struct DynamicModInt - : IEquatable>, IFormattable -#if GENERIC_MATH - , INumberBase> -#endif + : IEquatable>, IFormattable, IModInt> where T : struct { internal readonly uint _v; @@ -105,7 +102,7 @@ public static DynamicModInt Raw(int v) /// - ㌠0 未満ã€ã‚‚ã—ã㯠mod 以上ã®å ´åˆã€è‡ªå‹•ã§ mod ã‚’å–ã‚Šã¾ã™ã€‚ /// [MethodImpl(256)] - public DynamicModInt(long v) : this(Round(v)) { } + public DynamicModInt(long v) : this((uint)ModCalc.SafeMod(v, bt.Mod)) { } /// /// DynamicModInt<> åž‹ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã‚’生æˆã—ã¾ã™ã€‚ @@ -120,17 +117,6 @@ public DynamicModInt(ulong v) : this((uint)(v % bt.Mod)) { } [MethodImpl(256)] private DynamicModInt(uint v) => _v = v; - [MethodImpl(256)] - private static uint Round(long v) - { - Contract.Assert(bt != null, $"{nameof(DynamicModInt)}<{nameof(T)}>.{nameof(Mod)} is undefined."); - var x = v % bt.Mod; - if (x < 0) - { - x += bt.Mod; - } - return (uint)x; - } [MethodImpl(256)] public static DynamicModInt operator ++(DynamicModInt v) @@ -207,7 +193,7 @@ private static uint Round(long v) [MethodImpl(256)] public static implicit operator DynamicModInt(int v) => new DynamicModInt(v); [MethodImpl(256)] - public static implicit operator DynamicModInt(uint v) => new DynamicModInt((long)v); + public static implicit operator DynamicModInt(uint v) => new DynamicModInt((ulong)v); [MethodImpl(256)] public static implicit operator DynamicModInt(long v) => new DynamicModInt(v); [MethodImpl(256)] @@ -223,6 +209,16 @@ private static uint Round(long v) [MethodImpl(256)] public DynamicModInt Pow(long n) => new DynamicModInt(bt.Pow(Value, n)); + /// + /// 自身を x ã¨ã—ã¦ã€x^ ã‚’è¿”ã—ã¾ã™ã€‚ + /// + /// + /// 制約: 0≤|| + /// 計算é‡: O(log()) + /// + [MethodImpl(256)] + public DynamicModInt Pow(ulong n) => new DynamicModInt(bt.Pow(Value, n)); + /// /// 自身を x ã¨ã—ã¦ã€ xy≡1 ãªã‚‹ y ã‚’è¿”ã—ã¾ã™ã€‚ /// @@ -232,7 +228,7 @@ private static uint Round(long v) [MethodImpl(256)] public DynamicModInt Inv() { - var (g, x) = InternalMath.InvGcd(_v, bt.Mod); + var (g, x) = ModCalc.InvGcd(_v, bt.Mod); Contract.Assert(g == 1, reason: $"gcd({nameof(x)}, {nameof(Mod)}) must be 1."); return new DynamicModInt(x); } @@ -243,6 +239,35 @@ public DynamicModInt Inv() [MethodImpl(256)] public bool Equals(DynamicModInt other) => Value == other.Value; public override int GetHashCode() => _v.GetHashCode(); + public static bool TryParse(ReadOnlySpan s, out DynamicModInt result) + { + result = Zero; + DynamicModInt ten = 10u; + s = s.Trim(); + bool minus = false; + if (s.Length > 0 && s[0] == '-') + { + minus = true; + s = s.Slice(1); + } + for (int i = 0; i < s.Length; i++) + { + var d = (uint)(s[i] - '0'); + if (d >= 10) return false; + result = result * ten + d; + } + if (minus) + result = -result; + return true; + } + public static DynamicModInt Parse(ReadOnlySpan s) + { + if (!TryParse(s, out var r)) + Throw(); + return r; + void Throw() => throw new FormatException(); + } + #if GENERIC_MATH static int INumberBase>.Radix => 2; static DynamicModInt IAdditiveIdentity, DynamicModInt>.AdditiveIdentity => default; @@ -269,24 +294,16 @@ public DynamicModInt Inv() static DynamicModInt INumberBase>.MaxMagnitudeNumber(DynamicModInt x, DynamicModInt y) => new DynamicModInt(uint.Max(x._v, y._v)); static DynamicModInt INumberBase>.MinMagnitude(DynamicModInt x, DynamicModInt y) => new DynamicModInt(uint.Min(x._v, y._v)); static DynamicModInt INumberBase>.MinMagnitudeNumber(DynamicModInt x, DynamicModInt y) => new DynamicModInt(uint.Min(x._v, y._v)); - static DynamicModInt INumberBase>.Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider) => long.Parse(s, style, provider); - static DynamicModInt INumberBase>.Parse(string s, NumberStyles style, IFormatProvider provider) => long.Parse(s, style, provider); - static DynamicModInt ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider provider) => long.Parse(s, provider); - static DynamicModInt IParsable>.Parse(string s, IFormatProvider provider) => long.Parse(s, provider); - static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider provider, out DynamicModInt result) - => TryParse(s, NumberStyles.None, provider, out result); - static bool IParsable>.TryParse(string s, IFormatProvider provider, out DynamicModInt result) - => TryParse(s, NumberStyles.None, provider, out result); - static bool INumberBase>.TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider, out DynamicModInt result) - => TryParse(s, style, provider, out result); - static bool INumberBase>.TryParse(string s, NumberStyles style, IFormatProvider provider, out DynamicModInt result) - => TryParse(s, style, provider, out result); - private static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider, out DynamicModInt result) - { - var b = long.TryParse(s, style, provider, out var r); - result = r; - return b; - } + + static DynamicModInt INumberBase>.Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider) => Parse(s); + static DynamicModInt INumberBase>.Parse(string s, NumberStyles style, IFormatProvider provider) => Parse(s); + static DynamicModInt ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider provider) => Parse(s); + static DynamicModInt IParsable>.Parse(string s, IFormatProvider provider) => Parse(s); + static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider provider, out DynamicModInt result) => TryParse(s, out result); + static bool IParsable>.TryParse(string s, IFormatProvider provider, out DynamicModInt result) => TryParse(s, out result); + static bool INumberBase>.TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider, out DynamicModInt result) => TryParse(s, out result); + static bool INumberBase>.TryParse(string s, NumberStyles style, IFormatProvider provider, out DynamicModInt result) => TryParse(s, out result); + bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider provider) => _v.TryFormat(destination, out charsWritten, format, provider); diff --git a/Source/ac-library-csharp/Math/ModInt/IModInterface.cs b/Source/ac-library-csharp/Math/ModInt/IModInterface.cs new file mode 100644 index 00000000..99279c25 --- /dev/null +++ b/Source/ac-library-csharp/Math/ModInt/IModInterface.cs @@ -0,0 +1,78 @@ +#if GENERIC_MATH +using System.Numerics; +#endif + +namespace AtCoder +{ + public interface IModInt +#if GENERIC_MATH + : INumberBase where T : INumberBase +#endif + { + /// + /// 自身を x ã¨ã—ã¦ã€ xy≡1 ãªã‚‹ y ã‚’è¿”ã—ã¾ã™ã€‚ + /// + /// + /// 制約: gcd(x, mod) = 1 + /// + T Inv(); + + /// + /// 自身を x ã¨ã—ã¦ã€x^ ã‚’è¿”ã—ã¾ã™ã€‚ + /// + /// + /// 制約: 0≤|| + /// 計算é‡: O(log()) + /// + T Pow(ulong n); + + /// + /// æ ¼ç´ã•ã‚Œã¦ã„る値を返ã—ã¾ã™ã€‚ + /// + int Value { get; } + +#if GENERIC_MATH + /// + /// mod ã‚’è¿”ã—ã¾ã™ã€‚ + /// + abstract static int Mod { get; } +#endif + } + + /// + /// コンパイル時ã«æ±ºå®šã™ã‚‹ mod を表ã—ã¾ã™ã€‚ + /// + /// + /// + /// public readonly struct Mod1000000009 : IStaticMod + /// { + /// public uint Mod => 1000000009; + /// public bool IsPrime => true; + /// } + /// + /// + [IsOperator] + public interface IStaticMod + { + /// + /// mod ã‚’å–å¾—ã—ã¾ã™ã€‚ + /// + uint Mod { get; } + + /// + /// mod ãŒç´ æ•°ã§ã‚ã‚‹ã‹è­˜åˆ¥ã—ã¾ã™ã€‚ + /// + bool IsPrime { get; } + } + public readonly struct Mod1000000007 : IStaticMod + { + public uint Mod => 1000000007; + public bool IsPrime => true; + } + + public readonly struct Mod998244353 : IStaticMod + { + public uint Mod => 998244353; + public bool IsPrime => true; + } +} diff --git a/Source/ac-library-csharp/Math/StaticModInt.cs b/Source/ac-library-csharp/Math/ModInt/StaticModInt.cs similarity index 86% rename from Source/ac-library-csharp/Math/StaticModInt.cs rename to Source/ac-library-csharp/Math/ModInt/StaticModInt.cs index a3f6e8e6..c74c461c 100644 --- a/Source/ac-library-csharp/Math/StaticModInt.cs +++ b/Source/ac-library-csharp/Math/ModInt/StaticModInt.cs @@ -8,43 +8,6 @@ namespace AtCoder { - /// - /// コンパイル時ã«æ±ºå®šã™ã‚‹ mod を表ã—ã¾ã™ã€‚ - /// - /// - /// - /// public readonly struct Mod1000000009 : IStaticMod - /// { - /// public uint Mod => 1000000009; - /// public bool IsPrime => true; - /// } - /// - /// - [IsOperator] - public interface IStaticMod - { - /// - /// mod ã‚’å–å¾—ã—ã¾ã™ã€‚ - /// - uint Mod { get; } - - /// - /// mod ãŒç´ æ•°ã§ã‚ã‚‹ã‹è­˜åˆ¥ã—ã¾ã™ã€‚ - /// - bool IsPrime { get; } - } - public readonly struct Mod1000000007 : IStaticMod - { - public uint Mod => 1000000007; - public bool IsPrime => true; - } - - public readonly struct Mod998244353 : IStaticMod - { - public uint Mod => 998244353; - public bool IsPrime => true; - } - /// /// 四則演算時ã«è‡ªå‹•ã§ mod ã‚’å–る整数型。mod ã®å€¤ã¯ã‚³ãƒ³ãƒ‘イル時ã«æ±ºå®šã—ã¦ã„ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ /// @@ -61,12 +24,8 @@ public interface IStaticMod /// } /// /// - public readonly struct StaticModInt - : IEquatable>, IFormattable -#if GENERIC_MATH - , INumberBase> -#endif - where T : struct, IStaticMod + public readonly struct StaticModInt : IEquatable>, IFormattable, IModInt> + where T : struct, IStaticMod { internal readonly uint _v; private static readonly T op = default; @@ -107,7 +66,7 @@ public static StaticModInt Raw(int v) /// ㌠0 未満ã€ã‚‚ã—ã㯠mod 以上ã®å ´åˆã€è‡ªå‹•ã§ mod ã‚’å–ã‚Šã¾ã™ã€‚ /// [MethodImpl(256)] - public StaticModInt(long v) : this(Round(v)) { } + public StaticModInt(long v) : this((uint)ModCalc.SafeMod(v, op.Mod)) { } /// /// StaticModInt<> åž‹ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã‚’生æˆã—ã¾ã™ã€‚ @@ -121,17 +80,6 @@ public StaticModInt(ulong v) : this((uint)(v % op.Mod)) { } [MethodImpl(256)] private StaticModInt(uint v) => _v = v; - [MethodImpl(256)] - private static uint Round(long v) - { - var x = v % op.Mod; - if (x < 0) - { - x += op.Mod; - } - return (uint)x; - } - [MethodImpl(256)] public static StaticModInt operator ++(StaticModInt v) { @@ -201,7 +149,7 @@ private static uint Round(long v) [MethodImpl(256)] public static implicit operator StaticModInt(int v) => new StaticModInt(v); [MethodImpl(256)] - public static implicit operator StaticModInt(uint v) => new StaticModInt((long)v); + public static implicit operator StaticModInt(uint v) => new StaticModInt((ulong)v); [MethodImpl(256)] public static implicit operator StaticModInt(long v) => new StaticModInt(v); [MethodImpl(256)] @@ -218,6 +166,19 @@ private static uint Round(long v) public StaticModInt Pow(long n) { Contract.Assert(0 <= n, $"{nameof(n)} must be positive."); + return Pow((ulong)n); + } + + /// + /// 自身を x ã¨ã—ã¦ã€x^ ã‚’è¿”ã—ã¾ã™ã€‚ + /// + /// + /// 制約: 0≤|| + /// 計算é‡: O(log()) + /// + [MethodImpl(256)] + public StaticModInt Pow(ulong n) + { var x = this; var r = new StaticModInt(1U); @@ -250,7 +211,7 @@ public StaticModInt Inv() } else { - var (g, x) = InternalMath.InvGcd(_v, op.Mod); + var (g, x) = ModCalc.InvGcd(_v, op.Mod); Contract.Assert(g == 1, reason: $"gcd({nameof(x)}, {nameof(Mod)}) must be 1."); return new StaticModInt(x); } @@ -261,6 +222,34 @@ public StaticModInt Inv() public override bool Equals(object obj) => obj is StaticModInt m && Equals(m); [MethodImpl(256)] public bool Equals(StaticModInt other) => _v == other._v; public override int GetHashCode() => _v.GetHashCode(); + public static bool TryParse(ReadOnlySpan s, out StaticModInt result) + { + result = Zero; + StaticModInt ten = 10u; + s = s.Trim(); + bool minus = false; + if (s.Length > 0 && s[0] == '-') + { + minus = true; + s = s.Slice(1); + } + for (int i = 0; i < s.Length; i++) + { + var d = (uint)(s[i] - '0'); + if (d >= 10) return false; + result = result * ten + d; + } + if (minus) + result = -result; + return true; + } + public static StaticModInt Parse(ReadOnlySpan s) + { + if (!TryParse(s, out var r)) + Throw(); + return r; + void Throw() => throw new FormatException(); + } #if GENERIC_MATH static int INumberBase>.Radix => 2; @@ -288,24 +277,16 @@ public StaticModInt Inv() static StaticModInt INumberBase>.MaxMagnitudeNumber(StaticModInt x, StaticModInt y) => new StaticModInt(uint.Max(x._v, y._v)); static StaticModInt INumberBase>.MinMagnitude(StaticModInt x, StaticModInt y) => new StaticModInt(uint.Min(x._v, y._v)); static StaticModInt INumberBase>.MinMagnitudeNumber(StaticModInt x, StaticModInt y) => new StaticModInt(uint.Min(x._v, y._v)); - static StaticModInt INumberBase>.Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider) => long.Parse(s, style, provider); - static StaticModInt INumberBase>.Parse(string s, NumberStyles style, IFormatProvider provider) => long.Parse(s, style, provider); - static StaticModInt ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider provider) => long.Parse(s, provider); - static StaticModInt IParsable>.Parse(string s, IFormatProvider provider) => long.Parse(s, provider); - static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider provider, out StaticModInt result) - => TryParse(s, NumberStyles.None, provider, out result); - static bool IParsable>.TryParse(string s, IFormatProvider provider, out StaticModInt result) - => TryParse(s, NumberStyles.None, provider, out result); - static bool INumberBase>.TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider, out StaticModInt result) - => TryParse(s, style, provider, out result); - static bool INumberBase>.TryParse(string s, NumberStyles style, IFormatProvider provider, out StaticModInt result) - => TryParse(s, style, provider, out result); - private static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider, out StaticModInt result) - { - var b = long.TryParse(s, style, provider, out var r); - result = r; - return b; - } + + static StaticModInt INumberBase>.Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider) => Parse(s); + static StaticModInt INumberBase>.Parse(string s, NumberStyles style, IFormatProvider provider) => Parse(s); + static StaticModInt ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider provider) => Parse(s); + static StaticModInt IParsable>.Parse(string s, IFormatProvider provider) => Parse(s); + static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider provider, out StaticModInt result) => TryParse(s, out result); + static bool IParsable>.TryParse(string s, IFormatProvider provider, out StaticModInt result) => TryParse(s, out result); + static bool INumberBase>.TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider provider, out StaticModInt result) => TryParse(s, out result); + static bool INumberBase>.TryParse(string s, NumberStyles style, IFormatProvider provider, out StaticModInt result) => TryParse(s, out result); + bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider provider) => _v.TryFormat(destination, out charsWritten, format, provider); diff --git a/Source/ac-library-csharp/Operators/IOperators.cs b/Source/ac-library-csharp/Operators/IOperators.cs index 7b5d5c15..5143da24 100644 --- a/Source/ac-library-csharp/Operators/IOperators.cs +++ b/Source/ac-library-csharp/Operators/IOperators.cs @@ -142,7 +142,7 @@ public interface ICompareOperator : IComparer #if GENERIC_MATH [System.Obsolete("Use generic math")] #endif - public interface IMinMaxValue + public interface IMinMaxValueOperator { /// /// MinValue @@ -158,7 +158,7 @@ public interface IMinMaxValue #if GENERIC_MATH [System.Obsolete("Use generic math")] #endif - public interface INumOperator : IArithmeticOperator, ICompareOperator, IMinMaxValue + public interface INumOperator : IArithmeticOperator, ICompareOperator, IMinMaxValueOperator { } diff --git a/Source/ac-library-csharp/STL/Deque.cs b/Source/ac-library-csharp/STL/Deque.cs index 30ead34b..495b0283 100644 --- a/Source/ac-library-csharp/STL/Deque.cs +++ b/Source/ac-library-csharp/STL/Deque.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; +using System.Numerics; using System.Runtime.CompilerServices; using AtCoder.Internal; @@ -14,7 +15,6 @@ namespace AtCoder [DebuggerDisplay("Count = {" + nameof(Count) + "}")] public class Deque : IEnumerable, IReadOnlyCollection, ICollection { - [EditorBrowsable(Never)] public T[] data; @@ -30,14 +30,8 @@ public class Deque : IEnumerable, IReadOnlyCollection, ICollection public Deque() : this(1) { } public Deque(int capacity) { - capacity = -#if NET7_0_OR_GREATER - (int)System.Numerics.BitOperations.RoundUpToPowerOf2((uint)capacity + 1u); -#else - 1 << (InternalBit.CeilPow2(capacity + 1)); -#endif - data = new T[capacity]; - mask = capacity - 1; + data = Array.Empty(); + Grow(capacity); } public int Count => (tail - head) & mask; @@ -64,28 +58,58 @@ public T PopLast() [MethodImpl(256)] public void AddFirst(T item) { - data[head = (head - 1) & mask] = item; - if (head == tail) Resize(); + var nxt = (head - 1) & mask; + if (nxt == tail) + { + Grow(); + nxt = (head - 1) & mask; + } + data[nxt] = item; + head = nxt; } [MethodImpl(256)] public void AddLast(T item) { + var nxt = (tail + 1) & mask; + if (head == nxt) + { + Grow(); + nxt = (tail + 1) & mask; + } data[tail] = item; - tail = (tail + 1) & mask; - if (head == tail) Resize(); + tail = nxt; } [EditorBrowsable(Never)] - public void Resize() + public void Grow() => Grow(Math.Max(mask << 1, 0b11)); + + [EditorBrowsable(Never)] + public void Grow(int capacity) { - var oldSize = data.Length; - var newArray = new T[oldSize << 1]; + capacity = +#if NET7_0_OR_GREATER + (int)BitOperations.RoundUpToPowerOf2((uint)capacity + 1u); +#else + 1 << (InternalBit.CeilPow2(capacity + 1)); +#endif + Debug.Assert(BitOperations.PopCount((uint)capacity) == 1); + if (capacity <= data.Length) return; + var oldSize = Count; + var newArray = new T[capacity]; + if (head <= tail) + { + Array.Copy(data, head, newArray, 0, oldSize); + } + else + { + var hsize = data.Length - head; + Debug.Assert(hsize + tail == oldSize); + Array.Copy(data, head, newArray, 0, hsize); + Array.Copy(data, 0, newArray, hsize, tail); + } - var hsize = oldSize - head; - Array.Copy(data, head, newArray, 0, hsize); - Array.Copy(data, 0, newArray, hsize, tail); data = newArray; - mask = data.Length - 1; + mask = capacity - 1; head = 0; tail = oldSize; } @@ -143,7 +167,11 @@ public Enumerator(Deque deque, bool isReverse) { this.deque = deque; this.isReverse = isReverse; - if (isReverse) + if (deque.head == deque.tail) + { + index = last = 0; + } + else if (isReverse) { index = deque.tail; last = deque.head; diff --git a/Source/ac-library-csharp/STL/PriorityQueue/PriorityQueueOp.cs b/Source/ac-library-csharp/STL/PriorityQueue/PriorityQueueOp.cs index 180f26e4..d3b4686a 100644 --- a/Source/ac-library-csharp/STL/PriorityQueue/PriorityQueueOp.cs +++ b/Source/ac-library-csharp/STL/PriorityQueue/PriorityQueueOp.cs @@ -44,11 +44,22 @@ public void Enqueue(T value) UpdateUp(Count - 1); } [MethodImpl(256)] + public bool TryPeek(out T result) + { + if (Count == 0) + { + result = default; + return false; + } + result = data[0]; + return true; + } + [MethodImpl(256)] public bool TryDequeue(out T result) { if (Count == 0) { - result = default(T); + result = default; return false; } result = Dequeue(); @@ -69,7 +80,7 @@ public T Dequeue() public T EnqueueDequeue(T value) { var res = data[0]; - if (_comparer.Compare(value, res) <= 0) + if (Count == 0 || _comparer.Compare(value, res) <= 0) { return value; } @@ -78,6 +89,17 @@ public T EnqueueDequeue(T value) return res; } /// + /// Dequeue ã—ã¦ã‹ã‚‰ ã‚’ Enqueue(T) ã—ã¾ã™ã€‚ + /// + [MethodImpl(256)] + public T DequeueEnqueue(T value) + { + var res = data[0]; + data[0] = value; + UpdateDown(0); + return res; + } + /// /// Dequeue ã—ãŸå€¤ã« ã‚’é©ç”¨ã—㦠Enqueue(T) ã—ã¾ã™ã€‚ /// [MethodImpl(256)] @@ -122,6 +144,10 @@ protected internal void UpdateDown(int i) [EditorBrowsable(Never)] public ReadOnlySpan Unorderd() => data.AsSpan(0, Count); + +#if EMBEDDING + [SourceExpander.NotEmbeddingSource] +#endif private class DebugView { private readonly PriorityQueueOp pq; diff --git a/Source/ac-library-csharp/STL/PriorityQueue/PriorityQueueOp`2.cs b/Source/ac-library-csharp/STL/PriorityQueue/PriorityQueueOp`2.cs index 00d2a73f..e281a5b9 100644 --- a/Source/ac-library-csharp/STL/PriorityQueue/PriorityQueueOp`2.cs +++ b/Source/ac-library-csharp/STL/PriorityQueue/PriorityQueueOp`2.cs @@ -53,12 +53,35 @@ public void Enqueue(TKey key, TValue value) UpdateUp(Count - 1); } [MethodImpl(256)] + public bool TryPeek(out TKey key, out TValue value) + { + if (Count == 0) + { + key = default; + value = default; + return false; + } + (key, value) = (keys[0], values[0]); + return true; + } + [MethodImpl(256)] + public bool TryPeek(out KeyValuePair result) + { + if (Count == 0) + { + result = default; + return false; + } + result = Peek; + return true; + } + [MethodImpl(256)] public bool TryDequeue(out TKey key, out TValue value) { if (Count == 0) { - key = default(TKey); - value = default(TValue); + key = default; + value = default; return false; } (key, value) = Dequeue(); @@ -69,7 +92,7 @@ public bool TryDequeue(out KeyValuePair result) { if (Count == 0) { - result = default(KeyValuePair); + result = default; return false; } result = Dequeue(); @@ -91,7 +114,7 @@ public KeyValuePair Dequeue() public KeyValuePair EnqueueDequeue(TKey key, TValue value) { var res = KeyValuePair.Create(keys[0], values[0]); - if (_comparer.Compare(key, keys[0]) <= 0) + if (Count == 0 || _comparer.Compare(key, keys[0]) <= 0) { return KeyValuePair.Create(key, value); } @@ -101,6 +124,18 @@ public KeyValuePair EnqueueDequeue(TKey key, TValue value) return res; } /// + /// Dequeue ã—ã¦ã‹ã‚‰ ã‚’ Enqueue(T) ã—ã¾ã™ã€‚ + /// + [MethodImpl(256)] + public KeyValuePair DequeueEnqueue(TKey key, TValue value) + { + var res = KeyValuePair.Create(keys[0], values[0]); + keys[0] = key; + values[0] = value; + UpdateDown(0); + return res; + } + /// /// Dequeue ã—ãŸå€¤ã« ã‚’é©ç”¨ã—㦠Enqueue(T) ã—ã¾ã™ã€‚ /// [MethodImpl(256)] @@ -152,6 +187,10 @@ protected internal void UpdateDown(int i) public ReadOnlySpan UnorderdKeys() => keys.AsSpan(0, Count); [EditorBrowsable(Never)] public ReadOnlySpan UnorderdValues() => values.AsSpan(0, Count); + +#if EMBEDDING + [SourceExpander.NotEmbeddingSource] +#endif private class DebugView { private readonly PriorityQueueOp pq; diff --git a/Source/ac-library-csharp/SourceExpander.Embedder.Config.json b/Source/ac-library-csharp/SourceExpander.Embedder.Config.json index 1dab245f..e4a8abdc 100644 --- a/Source/ac-library-csharp/SourceExpander.Embedder.Config.json +++ b/Source/ac-library-csharp/SourceExpander.Embedder.Config.json @@ -10,6 +10,7 @@ "DEBUG", "ATCODER_CONTRACT" ], + "expanding-symbol": "DEBUG", "exclude-attributes": [ "System.Diagnostics.DebuggerBrowsableAttribute", "System.Diagnostics.DebuggerDisplayAttribute", diff --git a/Source/ac-library-csharp/ac-library-csharp.csproj b/Source/ac-library-csharp/ac-library-csharp.csproj index cd2f52d8..c14e3274 100644 --- a/Source/ac-library-csharp/ac-library-csharp.csproj +++ b/Source/ac-library-csharp/ac-library-csharp.csproj @@ -37,7 +37,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Test/Expand.Test/Expand.Test.csproj b/Test/Expand.Test/Expand.Test.csproj new file mode 100644 index 00000000..11c0340f --- /dev/null +++ b/Test/Expand.Test/Expand.Test.csproj @@ -0,0 +1,25 @@ + + + + Exe + net7.0;netcoreapp3.1 + annotations + + 8 + 11 + + $(NoWarn);CS0436;CS8981;CS0649 + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + diff --git a/Test/Expand.Test/Program.cs b/Test/Expand.Test/Program.cs new file mode 100644 index 00000000..e13fff9d --- /dev/null +++ b/Test/Expand.Test/Program.cs @@ -0,0 +1,9 @@ +partial class Program +{ + static void Main() + { +#if EMBEDDING + System.Console.WriteLine(SourceExpander.Testing.AtCoder.MathLib.PowMod(255, 1L << 52, 12)); +#endif + } +} diff --git a/Test/ac-library-csharp.LibraryChecker/BaseSover.cs b/Test/ac-library-csharp.LibraryChecker/BaseSolver.cs similarity index 79% rename from Test/ac-library-csharp.LibraryChecker/BaseSover.cs rename to Test/ac-library-csharp.LibraryChecker/BaseSolver.cs index 170eec7e..d66a1b96 100644 --- a/Test/ac-library-csharp.LibraryChecker/BaseSover.cs +++ b/Test/ac-library-csharp.LibraryChecker/BaseSolver.cs @@ -2,7 +2,7 @@ namespace AtCoder { - internal abstract class BaseSover : CompetitiveVerifier.ProblemSolver + internal abstract class BaseSolver : CompetitiveVerifier.ProblemSolver { public override void Solve() { diff --git a/Test/ac-library-csharp.LibraryChecker/DataStructure/FenwickTreeTest.cs b/Test/ac-library-csharp.LibraryChecker/DataStructure/FenwickTreeTest.cs index a097d9f9..fd49abd4 100644 --- a/Test/ac-library-csharp.LibraryChecker/DataStructure/FenwickTreeTest.cs +++ b/Test/ac-library-csharp.LibraryChecker/DataStructure/FenwickTreeTest.cs @@ -3,7 +3,7 @@ namespace AtCoder.Solvers.DataStructure { - internal class FenwickTreeTest : BaseSover + internal class FenwickTreeTest : BaseSolver { public override string Url => "https://judge.yosupo.jp/problem/point_add_range_sum"; public override void Solve(ConsoleReader cr, Utf8ConsoleWriter cw) diff --git a/Test/ac-library-csharp.LibraryChecker/DataStructure/LazySegtreeTest.cs b/Test/ac-library-csharp.LibraryChecker/DataStructure/LazySegtreeTest.cs index 0eb05651..db873876 100644 --- a/Test/ac-library-csharp.LibraryChecker/DataStructure/LazySegtreeTest.cs +++ b/Test/ac-library-csharp.LibraryChecker/DataStructure/LazySegtreeTest.cs @@ -2,7 +2,7 @@ namespace AtCoder.Solvers.DataStructure { - internal class LazySegtreeTest : BaseSover + internal class LazySegtreeTest : BaseSolver { public override string Url => "https://judge.yosupo.jp/problem/range_affine_range_sum"; public override void Solve(ConsoleReader cr, Utf8ConsoleWriter cw) diff --git a/Test/ac-library-csharp.LibraryChecker/DataStructure/SegtreeTest.cs b/Test/ac-library-csharp.LibraryChecker/DataStructure/SegtreeTest.cs index b36b57e4..71cc2683 100644 --- a/Test/ac-library-csharp.LibraryChecker/DataStructure/SegtreeTest.cs +++ b/Test/ac-library-csharp.LibraryChecker/DataStructure/SegtreeTest.cs @@ -2,7 +2,7 @@ namespace AtCoder.Solvers.DataStructure { - internal class SegtreeTest : BaseSover + internal class SegtreeTest : BaseSolver { public override string Url => "https://judge.yosupo.jp/problem/point_set_range_composite"; public override void Solve(ConsoleReader cr, Utf8ConsoleWriter cw) diff --git a/Test/ac-library-csharp.LibraryChecker/Graph/DsuTest.cs b/Test/ac-library-csharp.LibraryChecker/Graph/DsuTest.cs index 2eff8431..9142d5b6 100644 --- a/Test/ac-library-csharp.LibraryChecker/Graph/DsuTest.cs +++ b/Test/ac-library-csharp.LibraryChecker/Graph/DsuTest.cs @@ -2,7 +2,7 @@ namespace AtCoder.Solvers.Graph { - internal class DsuTest : BaseSover + internal class DsuTest : BaseSolver { public override string Url => "https://judge.yosupo.jp/problem/unionfind"; public override void Solve(ConsoleReader cr, Utf8ConsoleWriter cw) diff --git a/Test/ac-library-csharp.LibraryChecker/Graph/MaxflowTest.cs b/Test/ac-library-csharp.LibraryChecker/Graph/MaxflowTest.cs index cc75c037..38ae6c92 100644 --- a/Test/ac-library-csharp.LibraryChecker/Graph/MaxflowTest.cs +++ b/Test/ac-library-csharp.LibraryChecker/Graph/MaxflowTest.cs @@ -2,7 +2,7 @@ namespace AtCoder.Solvers.Graph { - internal class MaxflowTest : BaseSover + internal class MaxflowTest : BaseSolver { public override string Url => "https://judge.yosupo.jp/problem/bipartitematching"; public override void Solve(ConsoleReader cr, Utf8ConsoleWriter cw) diff --git a/Test/ac-library-csharp.LibraryChecker/Graph/SccTest.cs b/Test/ac-library-csharp.LibraryChecker/Graph/SccTest.cs index 9977b999..5b1558cc 100644 --- a/Test/ac-library-csharp.LibraryChecker/Graph/SccTest.cs +++ b/Test/ac-library-csharp.LibraryChecker/Graph/SccTest.cs @@ -2,7 +2,7 @@ namespace AtCoder.Solvers.Graph { - internal class SccTest : BaseSover + internal class SccTest : BaseSolver { public override string Url => "https://judge.yosupo.jp/problem/scc"; public override void Solve(ConsoleReader cr, Utf8ConsoleWriter cw) diff --git a/Test/ac-library-csharp.LibraryChecker/Graph/TwoSatTest.cs b/Test/ac-library-csharp.LibraryChecker/Graph/TwoSatTest.cs index c493b88f..9aaa655c 100644 --- a/Test/ac-library-csharp.LibraryChecker/Graph/TwoSatTest.cs +++ b/Test/ac-library-csharp.LibraryChecker/Graph/TwoSatTest.cs @@ -3,7 +3,7 @@ namespace AtCoder.Solvers { - internal class TwoSatTest : BaseSover + internal class TwoSatTest : BaseSolver { public override string Url => "https://judge.yosupo.jp/problem/two_sat"; public override void Solve(ConsoleReader cr, Utf8ConsoleWriter cw) diff --git a/Test/ac-library-csharp.LibraryChecker/Math/ConvolutionTest.cs b/Test/ac-library-csharp.LibraryChecker/Math/ConvolutionTest.cs index bc7ffadf..215ed011 100644 --- a/Test/ac-library-csharp.LibraryChecker/Math/ConvolutionTest.cs +++ b/Test/ac-library-csharp.LibraryChecker/Math/ConvolutionTest.cs @@ -2,7 +2,7 @@ namespace AtCoder.Solvers.MathN { - internal class ConvolutionTest : BaseSover + internal class ConvolutionTest : BaseSolver { public override string Url => "https://judge.yosupo.jp/problem/convolution_mod"; public override void Solve(ConsoleReader cr, Utf8ConsoleWriter cw) diff --git a/Test/ac-library-csharp.LibraryChecker/Math/FloorSumTest.cs b/Test/ac-library-csharp.LibraryChecker/Math/FloorSumTest.cs index d5e8b183..5cae923a 100644 --- a/Test/ac-library-csharp.LibraryChecker/Math/FloorSumTest.cs +++ b/Test/ac-library-csharp.LibraryChecker/Math/FloorSumTest.cs @@ -2,7 +2,7 @@ namespace AtCoder.Solvers.MathN { - internal class FloorSumTest : BaseSover + internal class FloorSumTest : BaseSolver { public override string Url => "https://judge.yosupo.jp/problem/sum_of_floor_of_linear"; public override void Solve(ConsoleReader cr, Utf8ConsoleWriter cw) diff --git a/Test/ac-library-csharp.LibraryChecker/String/LcpArrayTest.cs b/Test/ac-library-csharp.LibraryChecker/String/LcpArrayTest.cs index 82506a2e..da2e7be8 100644 --- a/Test/ac-library-csharp.LibraryChecker/String/LcpArrayTest.cs +++ b/Test/ac-library-csharp.LibraryChecker/String/LcpArrayTest.cs @@ -2,7 +2,7 @@ namespace AtCoder.Solvers.String { - internal class LcpArrayTest : BaseSover + internal class LcpArrayTest : BaseSolver { public override string Url => "https://judge.yosupo.jp/problem/number_of_substrings"; public override void Solve(ConsoleReader cr, Utf8ConsoleWriter cw) diff --git a/Test/ac-library-csharp.LibraryChecker/String/SuffixArrayTest.cs b/Test/ac-library-csharp.LibraryChecker/String/SuffixArrayTest.cs index d8125adf..fe737b6f 100644 --- a/Test/ac-library-csharp.LibraryChecker/String/SuffixArrayTest.cs +++ b/Test/ac-library-csharp.LibraryChecker/String/SuffixArrayTest.cs @@ -2,7 +2,7 @@ namespace AtCoder.Solvers.String { - internal class SuffixArrayTest : BaseSover + internal class SuffixArrayTest : BaseSolver { public override string Url => "https://judge.yosupo.jp/problem/suffixarray"; public override void Solve(ConsoleReader cr, Utf8ConsoleWriter cw) diff --git a/Test/ac-library-csharp.LibraryChecker/String/ZAlgorithmTest.cs b/Test/ac-library-csharp.LibraryChecker/String/ZAlgorithmTest.cs index ec5f4043..5b44d25a 100644 --- a/Test/ac-library-csharp.LibraryChecker/String/ZAlgorithmTest.cs +++ b/Test/ac-library-csharp.LibraryChecker/String/ZAlgorithmTest.cs @@ -2,7 +2,7 @@ namespace AtCoder.Solvers.String { - internal class ZAlgorithmTest : BaseSover + internal class ZAlgorithmTest : BaseSolver { public override string Url => "https://judge.yosupo.jp/problem/zalgorithm"; public override void Solve(ConsoleReader cr, Utf8ConsoleWriter cw) diff --git a/Test/ac-library-csharp.LibraryChecker/ac-library-csharp.LibraryChecker.csproj b/Test/ac-library-csharp.LibraryChecker/ac-library-csharp.LibraryChecker.csproj index 235ecbda..336e2e71 100644 --- a/Test/ac-library-csharp.LibraryChecker/ac-library-csharp.LibraryChecker.csproj +++ b/Test/ac-library-csharp.LibraryChecker/ac-library-csharp.LibraryChecker.csproj @@ -10,7 +10,7 @@ - + diff --git a/Test/ac-library-csharp.Test/DataStructure/FenwickTreeDebugViewTest.GenericMath.cs b/Test/ac-library-csharp.Test/DataStructure/FenwickTreeDebugViewTest.GenericMath.cs new file mode 100644 index 00000000..118fe6fc --- /dev/null +++ b/Test/ac-library-csharp.Test/DataStructure/FenwickTreeDebugViewTest.GenericMath.cs @@ -0,0 +1,115 @@ +using System.Linq; +using System.Numerics; +using System.Reflection; +using FluentAssertions; +using Xunit; + +namespace AtCoder +{ + public class FenwickTreeDebugViewGenericMathTest + { +#pragma warning disable CS0618 + class WrapperView where T : IAdditionOperators, ISubtractionOperators, IAdditiveIdentity + { + readonly object debugView; + readonly PropertyInfo itemsProperty; + public WrapperView(FenwickTree fw) + { + var type = typeof(FenwickTree).GetNestedType("DebugView", BindingFlags.NonPublic) + .MakeGenericType(typeof(T)); + debugView = type.GetConstructor(new[] { fw.GetType() }).Invoke(new object[] { fw }); + itemsProperty = debugView.GetType().GetProperty("Items"); + } + public FenwickTree.DebugItem[] GetItems() + { + return (FenwickTree.DebugItem[])itemsProperty.GetValue(debugView); + } + } + static WrapperView CreateWrapper(FenwickTree f) where T : IAdditionOperators, ISubtractionOperators, IAdditiveIdentity => new(f); + static FenwickTree.DebugItem CreateDebugItem(long val, long sum) => new(val, sum); + + [Fact] + public void Empty() + { + var s = new FenwickTree(0); + var view = CreateWrapper(s); + view.GetItems().Should().BeEmpty(); + } + + public static TheoryData Simple_Data = new TheoryData.DebugItem[]> + { + { + 1, + new[] + { + CreateDebugItem(0b000001, 0b000001), + } + }, + { + 2, + new[] + { + CreateDebugItem(0b000001, 0b000001), + CreateDebugItem(0b000010, 0b000011), + } + }, + { + 3, + new[] + { + CreateDebugItem(0b000001, 0b000001), + CreateDebugItem(0b000010, 0b000011), + CreateDebugItem(0b000100, 0b000111), + } + }, + { + 4, + new[] + { + CreateDebugItem(0b000001, 0b000001), + CreateDebugItem(0b000010, 0b000011), + CreateDebugItem(0b000100, 0b000111), + CreateDebugItem(0b001000, 0b001111), + } + }, + { + 5, + new[] + { + CreateDebugItem(0b000001, 0b000001), + CreateDebugItem(0b000010, 0b000011), + CreateDebugItem(0b000100, 0b000111), + CreateDebugItem(0b001000, 0b001111), + CreateDebugItem(0b010000, 0b011111), + } + }, + { + 6, + new[] + { + CreateDebugItem(0b000001, 0b000001), + CreateDebugItem(0b000010, 0b000011), + CreateDebugItem(0b000100, 0b000111), + CreateDebugItem(0b001000, 0b001111), + CreateDebugItem(0b010000, 0b011111), + CreateDebugItem(0b100000, 0b111111), + } + }, + }; + + [Theory] + [MemberData(nameof(Simple_Data))] + public void Simple(int size, object expectedObj) + { + var expected = (FenwickTree.DebugItem[])expectedObj; + var array = Enumerable.Range(0, size).Select(i => $"{(char)('a' + i)}").ToArray(); + var fw = new FenwickTree(size); + for (int i = 0; i < size; i++) + fw.Add(i, 1L << i); + + var view = CreateWrapper(fw); + var items = view.GetItems(); + items.Should().Equal(expected); + } + } +} diff --git a/Test/ac-library-csharp.Test/DataStructure/FenwickTreeDebugViewTest.cs b/Test/ac-library-csharp.Test/DataStructure/FenwickTreeDebugViewTest.cs new file mode 100644 index 00000000..e9855492 --- /dev/null +++ b/Test/ac-library-csharp.Test/DataStructure/FenwickTreeDebugViewTest.cs @@ -0,0 +1,115 @@ +using System.Linq; +using System.Reflection; +using AtCoder.Operators; +using FluentAssertions; +using Xunit; + +namespace AtCoder +{ + public class FenwickTreeDebugViewTest + { +#pragma warning disable CS0618 + class WrapperView where TOp : struct, IAdditionOperator, ISubtractOperator + { + readonly object debugView; + readonly PropertyInfo itemsProperty; + public WrapperView(FenwickTree fw) + { + var type = typeof(FenwickTree).GetNestedType("DebugView", BindingFlags.NonPublic) + .MakeGenericType(typeof(T), typeof(TOp)); + debugView = type.GetConstructor(new[] { fw.GetType() }).Invoke(new object[] { fw }); + itemsProperty = debugView.GetType().GetProperty("Items"); + } + public FenwickTree.DebugItem[] GetItems() + { + return (FenwickTree.DebugItem[])itemsProperty.GetValue(debugView); + } + } + static WrapperView CreateWrapper(FenwickTree f) where TOp : struct, IAdditionOperator, ISubtractOperator => new(f); + static LongFenwickTree.DebugItem CreateDebugItem(long val, long sum) => new(val, sum); + + [Fact] + public void Empty() + { + var s = new LongFenwickTree(0); + var view = CreateWrapper(s); + view.GetItems().Should().BeEmpty(); + } + + public static TheoryData Simple_Data = new TheoryData + { + { + 1, + new[] + { + CreateDebugItem(0b000001, 0b000001), + } + }, + { + 2, + new[] + { + CreateDebugItem(0b000001, 0b000001), + CreateDebugItem(0b000010, 0b000011), + } + }, + { + 3, + new[] + { + CreateDebugItem(0b000001, 0b000001), + CreateDebugItem(0b000010, 0b000011), + CreateDebugItem(0b000100, 0b000111), + } + }, + { + 4, + new[] + { + CreateDebugItem(0b000001, 0b000001), + CreateDebugItem(0b000010, 0b000011), + CreateDebugItem(0b000100, 0b000111), + CreateDebugItem(0b001000, 0b001111), + } + }, + { + 5, + new[] + { + CreateDebugItem(0b000001, 0b000001), + CreateDebugItem(0b000010, 0b000011), + CreateDebugItem(0b000100, 0b000111), + CreateDebugItem(0b001000, 0b001111), + CreateDebugItem(0b010000, 0b011111), + } + }, + { + 6, + new[] + { + CreateDebugItem(0b000001, 0b000001), + CreateDebugItem(0b000010, 0b000011), + CreateDebugItem(0b000100, 0b000111), + CreateDebugItem(0b001000, 0b001111), + CreateDebugItem(0b010000, 0b011111), + CreateDebugItem(0b100000, 0b111111), + } + }, + }; + + [Theory] + [MemberData(nameof(Simple_Data))] + public void Simple(int size, object expectedObj) + { + var expected = (LongFenwickTree.DebugItem[])expectedObj; + var array = Enumerable.Range(0, size).Select(i => $"{(char)('a' + i)}").ToArray(); + var fw = new LongFenwickTree(size); + for (int i = 0; i < size; i++) + fw.Add(i, 1L << i); + + var view = CreateWrapper(fw); + var items = view.GetItems(); + items.Should().Equal(expected); + } + } +} diff --git a/Test/ac-library-csharp.Test/DataStructure/LazySegtreeDebugViewTest.cs b/Test/ac-library-csharp.Test/DataStructure/LazySegtreeDebugViewTest.cs new file mode 100644 index 00000000..44781e9c --- /dev/null +++ b/Test/ac-library-csharp.Test/DataStructure/LazySegtreeDebugViewTest.cs @@ -0,0 +1,230 @@ +using System.Linq; +using System.Reflection; +using FluentAssertions; +using Xunit; + +namespace AtCoder +{ + public class LazySegtreeDebugViewTest + { + class WrapperView where TOp : struct, ILazySegtreeOperator + { + readonly object debugView; + readonly PropertyInfo itemsProperty; + public WrapperView(LazySegtree s) + { + var type = typeof(LazySegtree).GetNestedType("DebugView", BindingFlags.NonPublic) + .MakeGenericType(typeof(T), typeof(F), typeof(TOp)); + debugView = type.GetConstructor(new[] { s.GetType() }).Invoke(new object[] { s }); + itemsProperty = debugView.GetType().GetProperty("Items"); + } + public LazySegtree.DebugItem[] GetItems() + { + return (LazySegtree.DebugItem[])itemsProperty.GetValue(debugView); + } + } + static WrapperView CreateWrapper(LazySegtree s) where TOp : struct, ILazySegtreeOperator => new(s); + static LazySegtree.DebugItem CreateDebugItem(int l, int r, int value, int lazy = 0) + => new(l, r, value, lazy); + readonly struct MaxOp : ILazySegtreeOperator + { + public int Identity => int.MinValue; + public int FIdentity => 0; + + public int Composition(int nf, int cf) => nf + cf; + public int Mapping(int f, int x) => x + f; + public int Operate(int x, int y) => System.Math.Max(x, y); + } + + [Fact] + public void Empty() + { + var s = new LazySegtree(0); + var view = CreateWrapper(s); + view.GetItems().Should().BeEmpty(); + } + + public static TheoryData Simple_Data = new TheoryData.DebugItem[]> + { + { + 1, + new[] + { + CreateDebugItem(0, 1, 0), + } + }, + { + 2, + new[] + { + CreateDebugItem(0, 1, 0), + CreateDebugItem(1, 2, 1), + CreateDebugItem(0, 2, 1), + } + }, + { + 3, + new[] + { + CreateDebugItem(0, 1, 0), + CreateDebugItem(1, 2, 1), + CreateDebugItem(2, 3, 2), + CreateDebugItem(0, 2, 1), + CreateDebugItem(2, 4, 2), + CreateDebugItem(0, 4, 2), + } + }, + { + 4, + new[] + { + CreateDebugItem(0, 1, 0), + CreateDebugItem(1, 2, 1), + CreateDebugItem(2, 3, 2), + CreateDebugItem(3, 4, 3), + CreateDebugItem(0, 2, 1), + CreateDebugItem(2, 4, 3), + CreateDebugItem(0, 4, 3), + } + }, + { + 5, + new[] + { + CreateDebugItem(0, 1, 0), + CreateDebugItem(1, 2, 1), + CreateDebugItem(2, 3, 2), + CreateDebugItem(3, 4, 3), + CreateDebugItem(4, 5, 4), + CreateDebugItem(0, 2, 1), + CreateDebugItem(2, 4, 3), + CreateDebugItem(4, 6, 4), + CreateDebugItem(0, 4, 3), + CreateDebugItem(4, 8, 4), + CreateDebugItem(0, 8, 4), + } + }, + { + 6, + new[] + { + CreateDebugItem(0, 1, 0), + CreateDebugItem(1, 2, 1), + CreateDebugItem(2, 3, 2), + CreateDebugItem(3, 4, 3), + CreateDebugItem(4, 5, 4), + CreateDebugItem(5, 6, 5), + CreateDebugItem(0, 2, 1), + CreateDebugItem(2, 4, 3), + CreateDebugItem(4, 6, 5), + CreateDebugItem(0, 4, 3), + CreateDebugItem(4, 8, 5), + CreateDebugItem(0, 8, 5), + } + }, + }; + + [Theory] + [MemberData(nameof(Simple_Data))] + public void Simple(int size, object expectedObj) + { + var expected = (LazySegtree.DebugItem[])expectedObj; + var array = Enumerable.Range(0, size).ToArray(); + var s = new LazySegtree(array); + + var view = CreateWrapper(s); + var items = view.GetItems(); + items.Should().Equal(expected); + foreach (var item in items) + item.Value.Should().Be(System.Math.Min(item.R, size) - 1); + } + + [Fact] + public void Lazy() + { + var array = Enumerable.Range(0, 5).ToArray(); + var s = new LazySegtree(array); + var view = CreateWrapper(s); + + s.Apply(1, 4); + view.GetItems().Should().Equal(new LazySegtree.DebugItem[] + { + CreateDebugItem(0, 1, 0), + CreateDebugItem(1, 2, 5), + CreateDebugItem(2, 3, 2), + CreateDebugItem(3, 4, 3), + CreateDebugItem(4, 5, 4), + CreateDebugItem(0, 2, 5), + CreateDebugItem(2, 4, 3), + CreateDebugItem(4, 6, 4), + CreateDebugItem(0, 4, 5), + CreateDebugItem(4, 8, 4), + CreateDebugItem(0, 8, 5), + }); + + s.Apply(2, 5, -2); + view.GetItems().Should().Equal(new LazySegtree.DebugItem[] + { + CreateDebugItem(0, 1, 0), + CreateDebugItem(1, 2, 5), + CreateDebugItem(2, 3, 2), + CreateDebugItem(3, 4, 3), + CreateDebugItem(4, 5, 2), + CreateDebugItem(0, 2, 5), + CreateDebugItem(2, 4, 1, -2), + CreateDebugItem(4, 6, 2), + CreateDebugItem(0, 4, 5), + CreateDebugItem(4, 8, 2), + CreateDebugItem(0, 8, 5), + }); + + s.Apply(3, 5, 3); + view.GetItems().Should().Equal(new LazySegtree.DebugItem[] + { + CreateDebugItem(0, 1, 0), + CreateDebugItem(1, 2, 5), + CreateDebugItem(2, 3, 0), + CreateDebugItem(3, 4, 4), + CreateDebugItem(4, 5, 5), + CreateDebugItem(0, 2, 5), + CreateDebugItem(2, 4, 4), + CreateDebugItem(4, 6, 5), + CreateDebugItem(0, 4, 5), + CreateDebugItem(4, 8, 5), + CreateDebugItem(0, 8, 5), + }); + + s.Apply(0, 5, 1); + view.GetItems().Should().Equal(new LazySegtree.DebugItem[] + { + CreateDebugItem(0, 1, 0), + CreateDebugItem(1, 2, 5), + CreateDebugItem(2, 3, 0), + CreateDebugItem(3, 4, 4), + CreateDebugItem(4, 5, 6), + CreateDebugItem(0, 2, 5), + CreateDebugItem(2, 4, 4), + CreateDebugItem(4, 6, 6), + CreateDebugItem(0, 4, 6, 1), + CreateDebugItem(4, 8, 6), + CreateDebugItem(0, 8, 6), + }); + + s[2] = 5; + view.GetItems().Should().Equal(new LazySegtree.DebugItem[] + { + CreateDebugItem(0, 1, 0), + CreateDebugItem(1, 2, 5), + CreateDebugItem(2, 3, 5), + CreateDebugItem(3, 4, 5), + CreateDebugItem(4, 5, 6), + CreateDebugItem(0, 2, 6, 1), + CreateDebugItem(2, 4, 5), + CreateDebugItem(4, 6, 6), + CreateDebugItem(0, 4, 6), + CreateDebugItem(4, 8, 6), + CreateDebugItem(0, 8, 6), + }); + } + } +} diff --git a/Test/ac-library-csharp.Test/DataStructure/LazySegtree_StressTest.cs b/Test/ac-library-csharp.Test/DataStructure/LazySegtree_StressTest.cs index 1d25c604..4e03936e 100644 --- a/Test/ac-library-csharp.Test/DataStructure/LazySegtree_StressTest.cs +++ b/Test/ac-library-csharp.Test/DataStructure/LazySegtree_StressTest.cs @@ -63,10 +63,12 @@ public int Composition(int l, int r) [Fact] public void NaiveTest() { + const int size = Global.IsCi ? 10 : 3; + var mt = MTRandom.Create(); for (int n = 1; n <= 30; n++) { - for (int ph = 0; ph < 10; ph++) + for (int ph = 0; ph < size; ph++) { var seg0 = new LazySegtree<(int l, int r, int time), int, Op>(n); var tm = new TimeManager(n); @@ -109,6 +111,8 @@ public void NaiveTest() [Fact] public void MaxRightTest() { + const int size = Global.IsCi ? 1000 : 100; + var mt = MTRandom.Create(); for (int n = 1; n <= 30; n++) { @@ -121,7 +125,7 @@ public void MaxRightTest() seg0[i] = (i, i + 1, -1); } int now = 0; - for (int q = 0; q < 1000; q++) + for (int q = 0; q < size; q++) { int ty = mt.Next(0, 3); var (l, r) = mt.NextPair(0, n + 1); diff --git a/Test/ac-library-csharp.Test/DataStructure/Native/SegtreeNative.cs b/Test/ac-library-csharp.Test/DataStructure/Native/SegtreeNative.cs new file mode 100644 index 00000000..d141b7ea --- /dev/null +++ b/Test/ac-library-csharp.Test/DataStructure/Native/SegtreeNative.cs @@ -0,0 +1,68 @@ +using System; +using FluentAssertions; + +namespace AtCoder.DataStructure.Native +{ + internal readonly struct MonoidOperator : ISegtreeOperator + { + public string Identity => "$"; + public string Operate(string a, string b) + { + if (!(a == "$" || b == "$" || StringComparer.Ordinal.Compare(a, b) <= 0)) throw new Exception(); + if (a == "$") return b; + if (b == "$") return a; + return a + b; + } + } + internal class SegtreeNaive + { + private static readonly MonoidOperator op = default; + int n; + string[] d; + + public SegtreeNaive(int _n) + { + n = _n; + d = new string[n]; + Array.Fill(d, op.Identity); + } + public string this[int p] + { + set => d[p] = value; + get => d[p]; + } + + public string Prod(int l, int r) + { + var sum = op.Identity; + for (int i = l; i < r; i++) + { + sum = op.Operate(sum, d[i]); + } + return sum; + } + public string AllProd => Prod(0, n); + public int MaxRight(int l, Predicate f) + { + var sum = op.Identity; + f(sum).Should().BeTrue(); + for (int i = l; i < n; i++) + { + sum = op.Operate(sum, d[i]); + if (!f(sum)) return i; + } + return n; + } + public int MinLeft(int r, Predicate f) + { + var sum = op.Identity; + f(sum).Should().BeTrue(); + for (int i = r - 1; i >= 0; i--) + { + sum = op.Operate(d[i], sum); + if (!f(sum)) return i + 1; + } + return 0; + } + } +} diff --git a/Test/ac-library-csharp.Test/DataStructure/SegtreeDebugViewTest.cs b/Test/ac-library-csharp.Test/DataStructure/SegtreeDebugViewTest.cs new file mode 100644 index 00000000..c003040e --- /dev/null +++ b/Test/ac-library-csharp.Test/DataStructure/SegtreeDebugViewTest.cs @@ -0,0 +1,136 @@ +using System.Linq; +using System.Reflection; +using AtCoder.DataStructure.Native; +using FluentAssertions; +using Xunit; + +namespace AtCoder +{ + public class SegtreeDebugViewTest + { + class WrapperView where TOp : struct, ISegtreeOperator + { + readonly object debugView; + readonly PropertyInfo itemsProperty; + public WrapperView(Segtree s) + { + var type = typeof(Segtree).GetNestedType("DebugView", BindingFlags.NonPublic) + .MakeGenericType(typeof(T), typeof(TOp)); + debugView = type.GetConstructor(new[] { s.GetType() }).Invoke(new object[] { s }); + itemsProperty = debugView.GetType().GetProperty("Items"); + } + public Segtree.DebugItem[] GetItems() + { + return (Segtree.DebugItem[])itemsProperty.GetValue(debugView); + } + } + static WrapperView CreateWrapper(Segtree s) where TOp : struct, ISegtreeOperator => new(s); + static Segtree.DebugItem CreateDebugItem(int l, int r, string s) => new(l, r, s); + + [Fact] + public void Empty() + { + var s = new Segtree(0); + var view = CreateWrapper(s); + view.GetItems().Should().BeEmpty(); + } + + public static TheoryData Simple_Data = new TheoryData.DebugItem[]> + { + { + 1, + new[] + { + CreateDebugItem(0, 1, "a"), + } + }, + { + 2, + new[] + { + CreateDebugItem(0, 1, "a"), + CreateDebugItem(1, 2, "b"), + CreateDebugItem(0, 2, "ab"), + } + }, + { + 3, + new[] + { + CreateDebugItem(0, 1, "a"), + CreateDebugItem(1, 2, "b"), + CreateDebugItem(2, 3, "c"), + CreateDebugItem(0, 2, "ab"), + CreateDebugItem(2, 4, "c"), + CreateDebugItem(0, 4, "abc"), + } + }, + { + 4, + new[] + { + CreateDebugItem(0, 1, "a"), + CreateDebugItem(1, 2, "b"), + CreateDebugItem(2, 3, "c"), + CreateDebugItem(3, 4, "d"), + CreateDebugItem(0, 2, "ab"), + CreateDebugItem(2, 4, "cd"), + CreateDebugItem(0, 4, "abcd"), + } + }, + { + 5, + new[] + { + CreateDebugItem(0, 1, "a"), + CreateDebugItem(1, 2, "b"), + CreateDebugItem(2, 3, "c"), + CreateDebugItem(3, 4, "d"), + CreateDebugItem(4, 5, "e"), + CreateDebugItem(0, 2, "ab"), + CreateDebugItem(2, 4, "cd"), + CreateDebugItem(4, 6, "e"), + CreateDebugItem(0, 4, "abcd"), + CreateDebugItem(4, 8, "e"), + CreateDebugItem(0, 8, "abcde"), + } + }, + { + 6, + new[] + { + CreateDebugItem(0, 1, "a"), + CreateDebugItem(1, 2, "b"), + CreateDebugItem(2, 3, "c"), + CreateDebugItem(3, 4, "d"), + CreateDebugItem(4, 5, "e"), + CreateDebugItem(5, 6, "f"), + CreateDebugItem(0, 2, "ab"), + CreateDebugItem(2, 4, "cd"), + CreateDebugItem(4, 6, "ef"), + CreateDebugItem(0, 4, "abcd"), + CreateDebugItem(4, 8, "ef"), + CreateDebugItem(0, 8, "abcdef"), + } + }, + }; + + [Theory] + [MemberData(nameof(Simple_Data))] + public void Simple(int size, object expectedObj) + { + var expected = (Segtree.DebugItem[])expectedObj; + var array = Enumerable.Range(0, size).Select(i => $"{(char)('a' + i)}").ToArray(); + var s = new Segtree(array); + + var naive = new SegtreeNaive(size); + for (int i = 0; i < size; i++) naive[i] = array[i]; + + var view = CreateWrapper(s); + var items = view.GetItems(); + items.Should().Equal(expected); + foreach (var item in items) + item.Value.Should().Be(naive.Prod(item.L, System.Math.Min(item.R, size))); + } + } +} diff --git a/Test/ac-library-csharp.Test/DataStructure/SegtreeTest.cs b/Test/ac-library-csharp.Test/DataStructure/SegtreeTest.cs index f4c99f6b..98f505a9 100644 --- a/Test/ac-library-csharp.Test/DataStructure/SegtreeTest.cs +++ b/Test/ac-library-csharp.Test/DataStructure/SegtreeTest.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Linq; +using AtCoder.DataStructure.Native; using FluentAssertions; using Xunit; @@ -104,71 +105,6 @@ public void CompareNaive() } } - struct MonoidOperator : ISegtreeOperator - { - public string Identity => "$"; - public string Operate(string a, string b) - { - if (!(a == "$" || b == "$" || StringComparer.Ordinal.Compare(a, b) <= 0)) throw new Exception(); - if (a == "$") return b; - if (b == "$") return a; - return a + b; - } - } - class SegtreeNaive - { - private static readonly MonoidOperator op = default; - int n; - string[] d; - - public SegtreeNaive(int _n) - { - n = _n; - d = new string[n]; - Array.Fill(d, op.Identity); - } - public string this[int p] - { - set => d[p] = value; - get => d[p]; - } - - public string Prod(int l, int r) - { - var sum = op.Identity; - for (int i = l; i < r; i++) - { - sum = op.Operate(sum, d[i]); - } - return sum; - } - public string AllProd => Prod(0, n); - public int MaxRight(int l, Predicate f) - { - var sum = op.Identity; - f(sum).Should().BeTrue(); - for (int i = l; i < n; i++) - { - sum = op.Operate(sum, d[i]); - if (!f(sum)) return i; - } - return n; - } - public int MinLeft(int r, Predicate f) - { - var sum = op.Identity; - f(sum).Should().BeTrue(); - for (int i = r - 1; i >= 0; i--) - { - sum = op.Operate(d[i], sum); - if (!f(sum)) return i + 1; - } - return 0; - } - } - - - [Theory] [Trait("Category", "Practice")] [InlineData( @@ -226,7 +162,7 @@ static void Solver(TextReader reader, TextWriter writer) } } } - struct OpPractice : ISegtreeOperator + readonly struct OpPractice : ISegtreeOperator { public int Identity => -1; public int Operate(int a, int b) => Math.Max(a, b); diff --git a/Test/ac-library-csharp.Test/Graph/MaxFlowTest.GenericMath.cs b/Test/ac-library-csharp.Test/Graph/MaxFlowTest.GenericMath.cs index c1c61d23..26d4440d 100644 --- a/Test/ac-library-csharp.Test/Graph/MaxFlowTest.GenericMath.cs +++ b/Test/ac-library-csharp.Test/Graph/MaxFlowTest.GenericMath.cs @@ -168,7 +168,7 @@ public void SelfLoop() var g = new MfGraph(3); g.AddEdge(0, 0, 100).Should().Be(0); - MfGraph.Edge e = new MfGraph.Edge(0, 0, 100, 0); + var e = new MfGraph.Edge(0, 0, 100, 0); g.GetEdge(0).Should().Be(e); } @@ -210,8 +210,10 @@ public void Invalid() [Fact] public void Stress() { + const int size = Global.IsCi ? 10000 : 1000; + var mt = MTRandom.Create(); - for (int phase = 0; phase < 10000; phase++) + for (int phase = 0; phase < size; phase++) { int n = mt.Next(2, 21); int m = mt.Next(1, 101); @@ -223,7 +225,7 @@ public void Stress() { int u = mt.Next(0, n); int v = mt.Next(0, n); - int c = mt.Next(0, 10001); + int c = mt.Next(0, size + 1); g.AddEdge(u, v, c); } int flow = g.Flow(s, t); diff --git a/Test/ac-library-csharp.Test/Graph/MaxFlowTest.cs b/Test/ac-library-csharp.Test/Graph/MaxFlowTest.cs index 8cee734e..aa6c3f05 100644 --- a/Test/ac-library-csharp.Test/Graph/MaxFlowTest.cs +++ b/Test/ac-library-csharp.Test/Graph/MaxFlowTest.cs @@ -171,7 +171,7 @@ public void SelfLoop() var g = new MfGraphInt(3); g.AddEdge(0, 0, 100).Should().Be(0); - MfGraphInt.Edge e = new MfGraphInt.Edge(0, 0, 100, 0); + var e = new MfGraphInt.Edge(0, 0, 100, 0); g.GetEdge(0).Should().Be(e); } @@ -213,8 +213,10 @@ public void Invalid() [Fact] public void Stress() { + const int size = Global.IsCi ? 10000 : 500; + var mt = MTRandom.Create(); - for (int phase = 0; phase < 10000; phase++) + for (int phase = 0; phase < size; phase++) { int n = mt.Next(2, 21); int m = mt.Next(1, 101); diff --git a/Test/ac-library-csharp.Test/Graph/TwoSatTest.cs b/Test/ac-library-csharp.Test/Graph/TwoSatTest.cs index 987d1870..d80ef773 100644 --- a/Test/ac-library-csharp.Test/Graph/TwoSatTest.cs +++ b/Test/ac-library-csharp.Test/Graph/TwoSatTest.cs @@ -39,8 +39,10 @@ public void One() [Fact] public void StressOK() { + const int size = Global.IsCi ? 10000 : 1000; + var mt = MTRandom.Create(); - for (int phase = 0; phase < 10000; phase++) + for (int phase = 0; phase < size; phase++) { int n = mt.Next(1, 21); int m = mt.Next(1, 101); diff --git a/Test/ac-library-csharp.Test/Internal/BarrettTest.cs b/Test/ac-library-csharp.Test/Internal/BarrettTest.cs index 6928771e..d7c45396 100644 --- a/Test/ac-library-csharp.Test/Internal/BarrettTest.cs +++ b/Test/ac-library-csharp.Test/Internal/BarrettTest.cs @@ -25,7 +25,7 @@ public void Barrett() } [Fact] - public void BarrettBorder() + public void BarrettInt32Border() { for (uint mod = int.MaxValue; mod >= int.MaxValue - 20; mod--) { @@ -40,16 +40,42 @@ public void BarrettBorder() } foreach (var a in v) { - long a2 = a; + ulong a2 = a; bt.Mul(a, bt.Mul(a, a)).Should().Be((uint)(a2 * a2 % mod * a2 % mod)); foreach (var b in v) { - long b2 = b; + ulong b2 = b; bt.Mul(a, b).Should().Be((uint)(a2 * b2 % mod)); } } } } + [Fact] + public void BarrettUInt32Border() + { + for (uint mod = uint.MaxValue; mod >= uint.MaxValue - 20; mod--) + { + var bt = new Barrett(mod); + var v = new List(); + for (uint i = 0; i < 10; i++) + { + v.Add(i); + v.Add(mod - i); + v.Add(mod / 2 + i); + v.Add(mod / 2 - i); + } + foreach (var a in v) + { + ulong a2 = a; + bt.Mul(a, bt.Mul(a, a)).Should().Be((uint)(a2 * a2 % mod * a2 % mod)); + foreach (var b in v) + { + ulong b2 = b; + bt.Mul(a, b).Should().Be((uint)(a2 * b2 % mod)); + } + } + } + } } } diff --git a/Test/ac-library-csharp.Test/Internal/InternalMathTest.cs b/Test/ac-library-csharp.Test/Internal/InternalMathTest.cs index 0e3dc42a..14e4982d 100644 --- a/Test/ac-library-csharp.Test/Internal/InternalMathTest.cs +++ b/Test/ac-library-csharp.Test/Internal/InternalMathTest.cs @@ -1,9 +1,11 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Numerics; -using System.Runtime.InteropServices; using FluentAssertions; using Xunit; +#if NET7_0_OR_GREATER +using System; +using System.Runtime.InteropServices; +#endif namespace AtCoder.Internal { @@ -34,17 +36,19 @@ private static bool IsPrimeNaive(long n) [Fact] public void IsPrime() { + const int size = Global.IsCi ? 10000 : 500; + InternalMath.IsPrime(121).Should().BeFalse(); InternalMath.IsPrime(11 * 13).Should().BeFalse(); InternalMath.IsPrime(1_000_000_007).Should().BeTrue(); InternalMath.IsPrime(1_000_000_008).Should().BeFalse(); InternalMath.IsPrime(1_000_000_009).Should().BeTrue(); - for (int i = 0; i <= 10000; i++) + for (int i = 0; i <= size; i++) { InternalMath.IsPrime(i).Should().Be(IsPrimeNaive(i)); } - for (int i = 0; i <= 10000; i++) + for (int i = 0; i <= size; i++) { int x = int.MaxValue - i; InternalMath.IsPrime(x).Should().Be(IsPrimeNaive(x)); @@ -123,7 +127,9 @@ public void InvGcdBound() [Fact] public void PrimitiveRootTestNaive() { - for (int m = 2; m <= 10000; m++) + const int size = Global.IsCi ? 10000 : 500; + + for (int m = 2; m <= size; m++) { if (!InternalMath.IsPrime(m)) continue; //int n = InternalMath.PrimitiveRoot(m); @@ -192,7 +198,8 @@ public void Mul128Bit(ulong a, ulong b) var x = a + (ulong)i; var y = b + (ulong)j; ulong expected = Math.BigMul(x, y, out _); - InternalMath.Mul128BitLogic(x, y).Should().Be(expected); + InternalMath.Mul128Bit(x, y).Should().Be(expected); + Mul128.Mul128Bit(x, y).Should().Be(expected); } } [Fact] @@ -206,7 +213,7 @@ public void Mul128BitRandom() var x = arr[0]; var y = arr[1]; ulong expected = Math.BigMul(x, y, out _); - InternalMath.Mul128BitLogic(x, y).Should().Be(expected); + Mul128.Mul128BitLogic(x, y).Should().Be(expected); } } #endif diff --git a/Test/ac-library-csharp.Test/Math/FloorSumTest.cs b/Test/ac-library-csharp.Test/Math/FloorSumTest.cs index ae7e6935..05144cf1 100644 --- a/Test/ac-library-csharp.Test/Math/FloorSumTest.cs +++ b/Test/ac-library-csharp.Test/Math/FloorSumTest.cs @@ -22,13 +22,15 @@ private static long FloorSumNative(long n, long m, long a, long b) [Fact] public void FloorSum() { - for (int n = 0; n < 20; n++) + int increment(ref int n) => Global.IsCi ? ++n : n += 2; + + for (int n = 0; n < 20; increment(ref n)) { - for (int m = 1; m < 20; m++) + for (int m = 1; m < 20; increment(ref m)) { - for (int a = -20; a < 20; a++) + for (int a = -20; a < 20; increment(ref a)) { - for (int b = -20; b < 20; b++) + for (int b = -20; b < 20; increment(ref b)) { var expected = FloorSumNative(n, m, a, b); MathLib.FloorSum(n, m, a, b).Should() diff --git a/Test/ac-library-csharp.Test/Math/MathLibTest.cs b/Test/ac-library-csharp.Test/Math/MathLibTest.cs index 1d621186..8efda56c 100644 --- a/Test/ac-library-csharp.Test/Math/MathLibTest.cs +++ b/Test/ac-library-csharp.Test/Math/MathLibTest.cs @@ -17,6 +17,7 @@ static long Gcd(long a, long b) [Fact] public void PowMod() { + const int size = Global.IsCi ? 100 : 50; static long Native(long x, long n, int mod) { uint mmod = (uint)mod; @@ -28,11 +29,11 @@ static long Native(long x, long n, int mod) } return (long)z; } - for (int a = -100; a <= 100; a++) + for (int a = -size; a <= size; a++) { - for (int b = 0; b <= 100; b++) + for (int b = 0; b <= size; b++) { - for (int c = 1; c <= 100; c++) + for (int c = 1; c <= size; c++) { MathLib.PowMod(a, b, c).Should().Be(Native(a, b, c)); } @@ -57,9 +58,10 @@ public void InvBoundHand(long x, long mod, long expected) [Fact] public void InvMod() { - for (long a = -100; a <= 100; a++) + const int size = Global.IsCi ? 100 : 50; + for (long a = -size; a <= size; a++) { - for (long b = 1; b <= 1000; b++) + for (long b = 1; b <= size * 10; b++) { if (Gcd(InternalMath.SafeMod(a, b), b) != 1) continue; long c = MathLib.InvMod(a, b); @@ -79,13 +81,14 @@ public void CrtHand() [Fact] public void Crt2() { - for (int a = 1; a <= 20; a++) + const int size = Global.IsCi ? 10 : 6; + for (int a = 1; a <= size * 2; a++) { - for (int b = 1; b <= 20; b++) + for (int b = 1; b <= size * 2; b++) { - for (int c = -10; c <= 10; c++) + for (int c = -size; c <= size; c++) { - for (int d = -10; d <= 10; d++) + for (int d = -size; d <= size; d++) { var (y, m) = MathLib.Crt(new long[] { c, d }, new long[] { a, b }); if (m == 0) @@ -107,17 +110,18 @@ public void Crt2() [Fact] public void Crt3() { - for (int a = 1; a <= 5; a++) + const int size = Global.IsCi ? 6 : 4; + for (int a = 1; a <= size; a++) { - for (int b = 1; b <= 5; b++) + for (int b = 1; b <= size; b++) { - for (int c = 1; c <= 5; c++) + for (int c = 1; c <= size; c++) { - for (int d = -5; d <= 5; d++) + for (int d = -size; d <= size; d++) { - for (int e = -5; e <= 5; e++) + for (int e = -size; e <= size; e++) { - for (int f = -5; f <= 5; f++) + for (int f = -size; f <= size; f++) { var (y, m) = MathLib.Crt(new long[] { d, e, f }, new long[] { a, b, c }); long lcm = a * b / Gcd(a, b); diff --git a/Test/ac-library-csharp.Test/Math/ModIntTest.cs b/Test/ac-library-csharp.Test/Math/ModIntTest.cs index 5cb23c65..85813a7b 100644 --- a/Test/ac-library-csharp.Test/Math/ModIntTest.cs +++ b/Test/ac-library-csharp.Test/Math/ModIntTest.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Runtime.InteropServices; @@ -150,6 +151,54 @@ void RunDynamic() where T : struct } } + [Fact] + public void Pow() + { + RunStatic(); + RunStatic(); + RunStatic(); + RunStatic(); + RunStatic(); + + DynamicModInt.Mod = 998244353; + RunDynamic(); + + DynamicModInt.Mod = 1000000008; + RunDynamic(); + + void RunStatic() where T : struct, IStaticMod + { + var mod = (int)new T().Mod; + var nums = Enumerable.Range(-100, 200).Concat(Enumerable.Range(mod - 100, 200)); + foreach (var n in nums) + { + StaticModInt num = n; + StaticModInt expected = 1; + for (int i = 0; i < 200; i++) + { + num.Pow(i).Should().Be(expected); + expected *= num; + } + } + } + + void RunDynamic() where T : struct + { + var mod = DynamicModInt.Mod; + var nums = Enumerable.Range(-100, 200).Concat(Enumerable.Range(mod - 100, 200)); + foreach (var n in nums) + { + DynamicModInt num = n; + DynamicModInt expected = 1; + for (int i = 0; i < 200; i++) + { + num.Pow(i).Should().Be(expected); + expected *= num; + } + } + } + } + private struct IncrementID : IStaticMod { public uint Mod => 11; @@ -211,6 +260,99 @@ public void Increment() } } + [Fact] + public void Parse() + { + var bigs = new[]{ + BigInteger.Pow(10, 1000), + BigInteger.Pow(10, 1000), + }; + var invalids = new[] + { + "2-2", + "ABC", + "111.0", + "111,1", + }; + RunStatic(); + RunStatic(); + RunStatic(); + RunStatic(); + RunStatic(); + + DynamicModInt.Mod = 998244353; + RunDynamic(); + + DynamicModInt.Mod = 1000000008; + RunDynamic(); + + void RunStatic() where T : struct, IStaticMod + { + var mod = (int)new T().Mod; + var nums = Enumerable.Range(-100, 200).Concat(Enumerable.Range(mod - 100, 200)); + foreach (var n in nums) + { + var s = n.ToString(); + var expected = (n % mod + mod) % mod; + StaticModInt.TryParse(s, out var num1).Should().BeTrue(); + var num2 = StaticModInt.Parse(s); + + num1.Value.Should().Be(expected); + num2.Value.Should().Be(expected); + } + + foreach (var n in bigs) + { + var s = n.ToString(); + var expected = (int)(n % mod + mod) % mod; + StaticModInt.TryParse(s, out var num1).Should().BeTrue(); + var num2 = StaticModInt.Parse(s); + + num1.Value.Should().Be(expected); + num2.Value.Should().Be(expected); + } + + foreach (var s in invalids) + { + StaticModInt.TryParse(s, out _).Should().BeFalse(); + s.Invoking(s => StaticModInt.Parse(s)).Should().ThrowExactly(); + } + } + + void RunDynamic() where T : struct + { + var mod = DynamicModInt.Mod; + var nums = Enumerable.Range(-100, 200).Concat(Enumerable.Range(mod - 100, 200)); + foreach (var n in nums) + { + var s = n.ToString(); + var expected = (n % mod + mod) % mod; + DynamicModInt.TryParse(s, out var num1).Should().BeTrue(); + var num2 = DynamicModInt.Parse(s); + + num1.Value.Should().Be(expected); + num2.Value.Should().Be(expected); + } + + foreach (var n in bigs) + { + var s = n.ToString(); + var expected = (int)(n % mod + mod) % mod; + DynamicModInt.TryParse(s, out var num1).Should().BeTrue(); + var num2 = DynamicModInt.Parse(s); + + num1.Value.Should().Be(expected); + num2.Value.Should().Be(expected); + } + + foreach (var s in invalids) + { + DynamicModInt.TryParse(s, out _).Should().BeFalse(); + s.Invoking(s => DynamicModInt.Parse(s)).Should().ThrowExactly(); + } + } + } + private struct DynamicUsageID { } [Fact] @@ -264,6 +406,7 @@ public void ConstructorStatic() (1 + new StaticModInt(1)).Value.Should().Be(2); } + private struct MemoryID : IStaticMod { public uint Mod => 101; @@ -393,6 +536,8 @@ void RunDynamic() where T : struct [Fact] public void ConvertFrom() { + const int size = Global.IsCi ? 100000 : 5000; + RunStatic(); RunStatic(); RunStatic(); @@ -408,7 +553,7 @@ public void ConvertFrom() void RunStatic() where T : struct, IStaticMod { var mod = (int)new T().Mod; - var max = System.Math.Min(100000, mod); + var max = System.Math.Min(size, mod); for (int i = 0; i < max; i++) { int x = ConvertFrom, int>(i).Value; @@ -428,7 +573,7 @@ void RunStatic() where T : struct, IStaticMod void RunDynamic() where T : struct { var mod = DynamicModInt.Mod; - var max = System.Math.Min(100000, mod); + var max = System.Math.Min(size, mod); for (int i = 0; i < max; i++) { int x = ConvertFrom, int>(i).Value; @@ -452,6 +597,8 @@ TModInt ConvertFrom(TOther v) where TModInt : INumberBase(); RunStatic(); RunStatic(); @@ -467,7 +614,7 @@ public void ConvertTo() void RunStatic() where T : struct, IStaticMod { var mod = (int)new T().Mod; - var max = System.Math.Min(100000, mod); + var max = System.Math.Min(size, mod); for (int i = 0; i < max; i++) { { @@ -492,7 +639,7 @@ void RunStatic() where T : struct, IStaticMod void RunDynamic() where T : struct { var mod = DynamicModInt.Mod; - var max = System.Math.Min(100000, mod); + var max = System.Math.Min(size, mod); for (int i = 0; i < max; i++) { { diff --git a/Test/ac-library-csharp.Test/STL/BinarySearchTest.cs b/Test/ac-library-csharp.Test/STL/BinarySearchTest.cs index d9d23b68..ad5b63ab 100644 --- a/Test/ac-library-csharp.Test/STL/BinarySearchTest.cs +++ b/Test/ac-library-csharp.Test/STL/BinarySearchTest.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using AtCoder.Utils; using FluentAssertions; using Xunit; diff --git a/Test/ac-library-csharp.Test/STL/DequeTest.cs b/Test/ac-library-csharp.Test/STL/DequeTest.cs index 79beeee6..37e61f2c 100644 --- a/Test/ac-library-csharp.Test/STL/DequeTest.cs +++ b/Test/ac-library-csharp.Test/STL/DequeTest.cs @@ -3,12 +3,113 @@ using System.Linq; using AtCoder.Internal; using FluentAssertions; +using MersenneTwister; using Xunit; namespace AtCoder { public class DequeTest { + [Fact] + public void Empty() + { + Impl(new Deque()); + for (int capacity = 0; capacity < 10; capacity++) + { + Impl(new Deque(capacity)); + + var deque = new Deque(capacity); + deque.AddFirst(0); + deque.PopLast(); + Impl(new Deque(capacity)); + } + + static void Impl(Deque deque) + { + deque.GetEnumerator().MoveNext().Should().BeFalse(); + deque.Count.Should().Be(0); + deque.Should().BeEmpty(); + deque.Should().Equal(Array.Empty()); + } + } + + [Fact] + public void Lengths() + { + for (int size = 1; size < 10; size++) + { + var orig = Enumerable.Range(1, size).ToArray(); + var deque = new Deque(); + foreach (var num in orig) + deque.AddLast(num); + deque.Count.Should().Be(size); + deque.Should().Equal(orig); + } + } + + [Fact] + public void Random() + { + var mt = MTRandom.Create(); + var deque = new Deque(); + var list = new LinkedList(); + + void AddFirst(int num) + { + deque.AddFirst(num); + list.AddFirst(num); + deque.Should().Equal(list); + } + + void AddLast(int num) + { + deque.AddLast(num); + list.AddLast(num); + deque.Should().Equal(list); + } + void PopFirst() + { + deque.PopFirst(); + list.RemoveFirst(); + deque.Should().Equal(list); + } + + void PopLast() + { + deque.PopLast(); + list.RemoveLast(); + deque.Should().Equal(list); + } + + + for (int q = 0; q < 10000; q++) + { + var type = mt.Next(4); + if (deque.Count == 0) type %= 2; + + switch (type) + { + case 0: AddFirst(mt.Next()); break; + case 1: AddLast(mt.Next()); break; + case 2: PopFirst(); break; + case 3: PopLast(); break; + } + } + + for (int q = 0; q < 10000; q++) + { + var type = mt.Next(6); + if (deque.Count == 0) type %= 2; + switch (type) + { + case 0: AddFirst(mt.Next()); break; + case 1: AddLast(mt.Next()); break; + case 2: case 4: PopFirst(); break; + case 3: case 5: PopLast(); break; + } + } + } + [Fact] public void Simple() { @@ -129,5 +230,66 @@ public void Enumerate() deque.Should().Equal(new[] { 1, 2, 3, 4, 5 }); deque.Reversed().Should().Equal(new[] { 5, 4, 3, 2, 1 }); } + + [Fact] + public void Grow() + { + { + var deque = new Deque { 1, }; + deque.Should().Equal(new[] { 1, }); + deque.Grow(6); + deque.data.Should().HaveCount(8); + deque.Should().Equal(new[] { 1, }); + } + { + var deque = new Deque { 1, 2, 3, }; + deque.Should().Equal(new[] { 1, 2, 3, }); + deque.Grow(6); + deque.data.Should().HaveCount(8); + deque.Should().Equal(new[] { 1, 2, 3, }); + } + { + var deque = new Deque { 1, 2, 3, }; + deque.Should().Equal(new[] { 1, 2, 3, }); + deque.PopFirst(); + deque.Grow(6); + deque.data.Should().HaveCount(8); + deque.Should().Equal(new[] { 2, 3, }); + } + { + var deque = new Deque { 1, 2, 3, }; + deque.Should().Equal(new[] { 1, 2, 3, }); + deque.PopFirst(); + deque.PopFirst(); + deque.AddLast(-1); + deque.AddLast(-2); + deque.PopFirst(); + deque.Grow(6); + deque.data.Should().HaveCount(8); + deque.Should().Equal(new[] { -1, -2, }); + } + { + var deque = new Deque { 1, 2, 3, }; + deque.Should().Equal(new[] { 1, 2, 3, }); + deque.PopFirst(); + deque.PopFirst(); + deque.PopFirst(); + deque.Should().BeEmpty(); + deque.Grow(6); + deque.data.Should().HaveCount(8); + deque.Should().BeEmpty(); + } + { + var deque = new Deque { 1, 2, 3, }; + deque.Should().Equal(new[] { 1, 2, 3, }); + deque.PopLast(); + deque.PopFirst(); + deque.PopFirst(); + deque.Should().BeEmpty(); + deque.Grow(6); + deque.data.Should().HaveCount(8); + deque.Should().BeEmpty(); + } + } } } diff --git a/Test/ac-library-csharp.Test/STL/PriorityQueueTest.cs b/Test/ac-library-csharp.Test/STL/PriorityQueueTest.cs index 22c908e3..9ae87ed4 100644 --- a/Test/ac-library-csharp.Test/STL/PriorityQueueTest.cs +++ b/Test/ac-library-csharp.Test/STL/PriorityQueueTest.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using AtCoder.Utils; using FluentAssertions; using MersenneTwister; using Xunit; @@ -72,9 +71,11 @@ public void Simple() pq.Enqueue(-lx); foreach (var lx in list) { - pq.TryDequeue(out var res).Should().BeTrue(); + pq.TryPeek(out var res).Should().BeTrue(); + pq.TryDequeue(out res).Should().BeTrue(); res.Should().Be(-lx); } + pq.TryPeek(out _).Should().BeFalse(); pq.TryDequeue(out _).Should().BeFalse(); pq.Count.Should().Be(0); } @@ -82,9 +83,10 @@ public void Simple() [Fact] public void SimpleKV() { + const int size = Global.IsCi ? 500 : 80; var mt = MTRandom.Create(); - for (int n = 0; n < 200; n++) + for (int n = 0; n < size; n++) { var list = new List(); var pq = new PriorityQueueDictionary(); @@ -110,7 +112,8 @@ public void SimpleKV() pq.Enqueue(-lx, lx); foreach (var lx in list) { - pq.TryDequeue(out var res).Should().BeTrue(); + pq.TryPeek(out var res).Should().BeTrue(); + pq.TryDequeue(out res).Should().BeTrue(); res.Should().Be(KeyValuePair.Create(-(long)lx, lx)); } pq.TryDequeue(out _).Should().BeFalse(); @@ -120,10 +123,14 @@ public void SimpleKV() pq.Enqueue(-lx, lx); foreach (var lx in list) { - pq.TryDequeue(out var key, out var val).Should().BeTrue(); + pq.TryPeek(out var key, out var val).Should().BeTrue(); + key.Should().Be(-lx); + val.Should().Be(lx); + pq.TryDequeue(out key, out val).Should().BeTrue(); key.Should().Be(-lx); val.Should().Be(lx); } + pq.TryPeek(out _, out _).Should().BeFalse(); pq.TryDequeue(out _, out _).Should().BeFalse(); pq.Count.Should().Be(0); } @@ -216,6 +223,9 @@ public void EnqueueDequeue() { var pq1 = new PriorityQueue(); var pq2 = new PriorityQueue(); + + pq1.EnqueueDequeue(1).Should().Be(1); + for (int i = 10; i > 0; i--) { pq1.Enqueue(i); @@ -242,6 +252,9 @@ public void EnqueueDequeueKV() { var pq1 = new PriorityQueueDictionary(); var pq2 = new PriorityQueueDictionary(); + + pq1.EnqueueDequeue(1, "ab").Should().Be(KeyValuePair.Create(1, "ab")); + for (int i = 10; i > 0; i--) { pq1.Enqueue(i, i.ToString()); @@ -264,12 +277,12 @@ void EnqueueDequeue(int value) } } + [Fact] public void DequeueEnqueue() { var pq1 = new PriorityQueue(); var pq2 = new PriorityQueue(); - Func func = k => k * 2; for (int i = 10; i > 0; i--) { pq1.Enqueue(i); @@ -279,10 +292,64 @@ public void DequeueEnqueue() for (int i = -1; i < 20; i++) { - EnqueueDequeue(); + DequeueEnqueue(); + } + + void DequeueEnqueue() + { + var value = mt.Next(); + pq1.DequeueEnqueue(value).Should().Be(pq2.Dequeue()); + pq2.Enqueue(value); + pq1.Unorderd().ToArray().Should().BeEquivalentTo(pq2.Unorderd().ToArray()); } + } - void EnqueueDequeue() + [Fact] + public void DequeueEnqueueKV() + { + var pq1 = new PriorityQueueDictionary(); + var pq2 = new PriorityQueueDictionary(); + for (int i = 10; i > 0; i--) + { + pq1.Enqueue(i, i.ToString()); + pq2.Enqueue(i, i.ToString()); + } + var mt = MTRandom.Create(); + + for (int i = -1; i < 20; i++) + { + DequeueEnqueue(); + } + + void DequeueEnqueue() + { + var key = mt.Next(); + var value = mt.Next().ToString(); + pq1.DequeueEnqueue(key, value).Should().Be(pq2.Dequeue()); + pq2.Enqueue(key, value); + pq1.UnorderdKeys().ToArray().Should().BeEquivalentTo(pq2.UnorderdKeys().ToArray()); + pq1.UnorderdValues().ToArray().Should().BeEquivalentTo(pq2.UnorderdValues().ToArray()); + } + } + [Fact] + public void DequeueEnqueueFunc() + { + var pq1 = new PriorityQueue(); + var pq2 = new PriorityQueue(); + int func(int k) => k * 2; + for (int i = 10; i > 0; i--) + { + pq1.Enqueue(i); + pq2.Enqueue(i); + } + var mt = MTRandom.Create(); + + for (int i = -1; i < 20; i++) + { + DequeueEnqueue(); + } + + void DequeueEnqueue() { pq2.Enqueue(func(pq2.Dequeue())); pq1.DequeueEnqueue(func); @@ -291,11 +358,11 @@ void EnqueueDequeue() } [Fact] - public void DequeueEnqueueKV() + public void DequeueEnqueueFuncKV() { var pq1 = new PriorityQueueDictionary(); var pq2 = new PriorityQueueDictionary(); - Func func = (k, v) => (k * 2, (2 * k).ToString()); + (int, string) func(int k, string v) => (k * 2, (2 * k).ToString()); for (int i = 10; i > 0; i--) { pq1.Enqueue(i, i.ToString()); @@ -305,15 +372,15 @@ public void DequeueEnqueueKV() for (int i = -1; i < 20; i++) { - EnqueueDequeue(); + DequeueEnqueue(); } - void EnqueueDequeue() + void DequeueEnqueue() { var (k, v) = pq2.Dequeue(); var (ek, ev) = func(k, v); pq2.Enqueue(KeyValuePair.Create(ek, ev)); - pq1.DequeueEnqueue(func); + pq1.DequeueEnqueue((Func)func); pq1.UnorderdKeys().ToArray().Should().BeEquivalentTo(pq2.UnorderdKeys().ToArray()); pq1.UnorderdValues().ToArray().Should().BeEquivalentTo(pq2.UnorderdValues().ToArray()); } diff --git a/Test/ac-library-csharp.Test/SourceExpanderTest.cs b/Test/ac-library-csharp.Test/SourceExpanderTest.cs index e62b844e..7ff286d5 100644 --- a/Test/ac-library-csharp.Test/SourceExpanderTest.cs +++ b/Test/ac-library-csharp.Test/SourceExpanderTest.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Threading.Tasks; using FluentAssertions; using SourceExpander; @@ -12,17 +13,28 @@ class EmbeddingFact : FactAttribute { #if !EMBEDDING public override string Skip => "SourceExpander.Embedder is disabled."; +#endif + } + class EmbeddingGenericMathFact : EmbeddingFact + { +#if EMBEDDING + public override string Skip => genericMath ? null : "GenericMath is disabled."; +#else + public override string Skip => "SourceExpander.Embedder is disabled."; #endif } #if NETCOREAPP3_0 const bool useIntrinsics = false; + const bool genericMath = false; const string languageVersion = "7.3"; #elif NETCOREAPP3_1 const bool useIntrinsics = true; + const bool genericMath = false; const string languageVersion = "8.0"; #else const bool useIntrinsics = true; + const bool genericMath = true; const string languageVersion = "11.0"; #endif @@ -99,13 +111,41 @@ public async Task EmbeddedNamespaces() "AtCoder.Operators"); } - [EmbeddingFact] public async Task RemoveContract() { var embedded = await EmbeddedData.LoadFromAssembly(typeof(Segtree<,>)); - var codes = embedded.SourceFiles.Select(s => s.CodeBody); - codes.Should().NotContain(code => code.Contains("Contract.Assert")); + var code = string.Join(' ', embedded.SourceFiles.Select(s => s.CodeBody)); + code.Should().NotContain("Contract.Assert"); + } + + [EmbeddingFact] + public async Task RemoveDebugView() + { + var embedded = await EmbeddedData.LoadFromAssembly(typeof(Segtree<,>)); + var code = string.Join(' ', embedded.SourceFiles.Select(s => s.CodeBody)); + code.Should().Contain("CollectionDebugView"); + code.Replace("CollectionDebugView", "CoDe").Should().NotContain("Debug"); + } + + [EmbeddingGenericMathFact] + public async Task FenwickTreeGenericMath() + { + var embedded = await EmbeddedData.LoadFromAssembly(typeof(Segtree<,>)); + var source = embedded.SourceFiles.Single(s => s.FileName.Split('\\', '/').Last() == "FenwickTree.GenericMath.cs"); + source.CodeBody.Should() + .Contain("FenwickTree") + .And + .NotContain("Debug"); } + +#if DEBUG && EMBEDDING + [Fact] + public void DebugExpanded() + { + _ = typeof(SourceExpander.Embedded.Expand.AtCoder.Segtree<,>); + _ = typeof(SourceExpander.Embedded.Expand.AtCoder.Mod1000000007); + } +#endif } } diff --git a/Test/ac-library-csharp.Test/String/StringLibTest.cs b/Test/ac-library-csharp.Test/String/StringLibTest.cs index 08bf4572..08d9f9b4 100644 --- a/Test/ac-library-csharp.Test/String/StringLibTest.cs +++ b/Test/ac-library-csharp.Test/String/StringLibTest.cs @@ -299,19 +299,21 @@ public void SuffixArray() [Fact] public void SuffixArrayInt() { + const int size = Global.IsCi ? 500000 : 50000; + int[] s, sa; - s = Enumerable.Range(0, 500000).SelectMany(i => new[] { i, ~i }).ToArray(); + s = Enumerable.Range(0, size).SelectMany(i => new[] { i, ~i }).ToArray(); sa = StringLib.SuffixArray(s); sa.Should().Equal( - Enumerable.Range(0, 500000).Select(i => 999999 - 2 * i).Concat( - Enumerable.Range(0, 500000).Select(i => 2 * i)) + Enumerable.Range(0, size).Select(i => 2 * size - 1 - 2 * i).Concat( + Enumerable.Range(0, size).Select(i => 2 * i)) ); - s = Enumerable.Range(0, 1000000).ToArray(); + s = Enumerable.Range(0, 2 * size).ToArray(); sa = StringLib.SuffixArray(s); sa.Should().Equal(s); - s = Enumerable.Range(0, 1000000).Reverse().ToArray(); + s = Enumerable.Range(0, 2 * size).Reverse().ToArray(); sa = StringLib.SuffixArray(s); sa.Should().Equal(s); } diff --git a/Test/ac-library-csharp.Test/Utils/ComparerUtil.cs b/Test/ac-library-csharp.Test/Utils/ComparerUtil.cs index 594ad053..f3b7d81b 100644 --- a/Test/ac-library-csharp.Test/Utils/ComparerUtil.cs +++ b/Test/ac-library-csharp.Test/Utils/ComparerUtil.cs @@ -5,7 +5,7 @@ using MersenneTwister; using Xunit; -namespace AtCoder.Utils +namespace AtCoder { public static class ComparerUtil { diff --git a/Test/ac-library-csharp.Test/Utils/ContractAssertUtil.cs b/Test/ac-library-csharp.Test/Utils/ContractAssertUtil.cs deleted file mode 100644 index 1a630250..00000000 --- a/Test/ac-library-csharp.Test/Utils/ContractAssertUtil.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using AtCoder.Internal; -using FluentAssertions.Specialized; - -namespace AtCoder -{ - public static class ContractAssertUtil - { - public static void ThrowContractAssert( - this DelegateAssertions assertions, - string because = "", - params object[] becauseArgs) - where TDelegate : Delegate where TAssertions : DelegateAssertions - { - assertions.Throw(because, becauseArgs); - } - } -} diff --git a/Test/ac-library-csharp.Test/Utils/Extensions.cs b/Test/ac-library-csharp.Test/Utils/Extensions.cs new file mode 100644 index 00000000..40f116eb --- /dev/null +++ b/Test/ac-library-csharp.Test/Utils/Extensions.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.IO; +using AtCoder.Internal; +using FluentAssertions; +using FluentAssertions.Primitives; +using FluentAssertions.Specialized; + +namespace AtCoder +{ + static class Extensions + { + #region Contract + public static void ThrowContractAssert( + this DelegateAssertions assertions, + string because = "", + params object[] becauseArgs) + where TDelegate : Delegate where TAssertions : DelegateAssertions + { + assertions.Throw(because, becauseArgs); + } + #endregion Contract + + #region Random + public static uint NextUInt(this Random rnd) => unchecked((uint)rnd.Next()); + public static (int, int) NextPair(this Random rnd, int lower, int upper) + { + (upper - lower).Should().BeGreaterOrEqualTo(1); + int a, b; + do + { + a = rnd.Next(lower, upper); + b = rnd.Next(lower, upper); + } while (a == b); + if (a > b) (a, b) = (b, a); + return (a, b); + } + public static bool NextBool(this Random rnd) => rnd.Next(2) == 0; + #endregion Random + + #region String + public static IEnumerable ToLines(this string str) + { + using var sr = new StringReader(str); + var line = sr.ReadLine(); + while (line != null) + { + yield return line; + line = sr.ReadLine(); + } + } + + public static void EqualLines(this StringAssertions assertions, string expected) + { + assertions.Subject.ToLines().Should().Equal(expected.ToLines()); + } + #endregion String + } +} diff --git a/Test/ac-library-csharp.Test/Utils/Global.cs b/Test/ac-library-csharp.Test/Utils/Global.cs new file mode 100644 index 00000000..b621dc67 --- /dev/null +++ b/Test/ac-library-csharp.Test/Utils/Global.cs @@ -0,0 +1,22 @@ +using Xunit; + +namespace AtCoder +{ + public class Global + { +#if CI + public const bool IsCi = true; + [Fact] + public void CI() { } +#else + public const bool IsCi = false; + [Fact(Skip = "This is not in CI.")] + public void CI() { } +#endif + } +} + +namespace System.Runtime.CompilerServices +{ + class IsExternalInit { } +} diff --git a/Test/ac-library-csharp.Test/Utils/MathUtil.cs b/Test/ac-library-csharp.Test/Utils/MathUtil.cs index 74f57852..dd003d0b 100644 --- a/Test/ac-library-csharp.Test/Utils/MathUtil.cs +++ b/Test/ac-library-csharp.Test/Utils/MathUtil.cs @@ -39,7 +39,7 @@ public static bool IsPrimitiveRoot(int m, int g) public class MathUtilTest { - private bool IsPrimitiveRootNative(int m, int g) + static bool IsPrimitiveRootNative(int m, int g) { (1 <= g && g < m).Should().BeTrue(); int x = 1; @@ -57,7 +57,8 @@ private bool IsPrimitiveRootNative(int m, int g) [Fact] public void IsPrimitiveRootTest() { - for (int m = 2; m <= 500; m++) + const int size = Global.IsCi ? 500 : 250; + for (int m = 2; m <= size; m++) { if (!InternalMath.IsPrime(m)) continue; for (int g = 1; g < m; g++) @@ -69,7 +70,8 @@ public void IsPrimitiveRootTest() [Fact] public void FactorsTest() { - for (int m = 1; m <= 50000; m++) + const int size = Global.IsCi ? 50000 : 10000; + for (int m = 1; m <= size; m++) { var f = MathUtil.Factors(m); int m2 = m; diff --git a/Test/ac-library-csharp.Test/Utils/RandomUtil.cs b/Test/ac-library-csharp.Test/Utils/RandomUtil.cs deleted file mode 100644 index afdf56de..00000000 --- a/Test/ac-library-csharp.Test/Utils/RandomUtil.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using FluentAssertions; - -namespace AtCoder -{ - static class RandomUtil - { - public static uint NextUInt(this Random rnd) => unchecked((uint)rnd.Next()); - public static (int, int) NextPair(this Random rnd, int lower, int upper) - { - (upper - lower).Should().BeGreaterOrEqualTo(1); - int a, b; - do - { - a = rnd.Next(lower, upper); - b = rnd.Next(lower, upper); - } while (a == b); - if (a > b) (a, b) = (b, a); - return (a, b); - } - public static bool NextBool(this Random rnd) => rnd.Next(2) == 0; - } -} diff --git a/Test/ac-library-csharp.Test/Utils/StringUtil.cs b/Test/ac-library-csharp.Test/Utils/StringUtil.cs deleted file mode 100644 index bd7ef977..00000000 --- a/Test/ac-library-csharp.Test/Utils/StringUtil.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using FluentAssertions; -using FluentAssertions.Primitives; - -namespace AtCoder -{ - static class StringUtil - { - public static IEnumerable ToLines(this string str) - { - using var sr = new StringReader(str); - var line = sr.ReadLine(); - while (line != null) - { - yield return line; - line = sr.ReadLine(); - } - } - - public static void EqualLines(this StringAssertions assertions, string expected) - { - assertions.Subject.ToLines().Should().Equal(expected.ToLines()); - } - } -} diff --git a/Test/ac-library-csharp.Test/ac-library-csharp.Test.csproj b/Test/ac-library-csharp.Test/ac-library-csharp.Test.csproj index bfa31845..1ace234f 100644 --- a/Test/ac-library-csharp.Test/ac-library-csharp.Test.csproj +++ b/Test/ac-library-csharp.Test/ac-library-csharp.Test.csproj @@ -1,17 +1,22 @@  - net7.0;netcoreapp3.1;netcoreapp3.0 + net7.0;netcoreapp3.1 false AtCoder true $(NoWarn);IDE0044;NETSDK1138 + latest + true - true $(DefineConstants);GENERIC_MATH + + $(DefineConstants);CI + + @@ -31,27 +36,28 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers - - + + - + + all - runtime; build; native; contentfiles; analyzers; buildtransitive + runtime;build;native;contentfiles;analyzers;buildtransitive all - runtime; build; native; contentfiles; analyzers; buildtransitive + runtime;build;native;contentfiles;analyzers;buildtransitive diff --git a/ac-library-csharp.sln b/ac-library-csharp.sln index e00a91f2..b8c028e1 100644 --- a/ac-library-csharp.sln +++ b/ac-library-csharp.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30413.136 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34031.279 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ac-library-csharp", "Source\ac-library-csharp\ac-library-csharp.csproj", "{7915FF27-0322-4460-A94E-FA7B86D5E25C}" EndProject @@ -18,12 +18,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ac-library-csharp.Test", "T EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{573A3DC6-BEB2-4E3A-8EB3-E4CB88F3C8F1}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AtCoderAnalyzer", "Source\AtCoderAnalyzer\AtCoderAnalyzer.csproj", "{1557AA29-1069-43ED-8552-791248C9E31C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AtCoderAnalyzer.Test", "Test\AtCoderAnalyzer.Test\AtCoderAnalyzer.Test.csproj", "{522A1037-5060-4CBA-A4A3-99624FAD732E}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ac-library-csharp.LibraryChecker", "Test\ac-library-csharp.LibraryChecker\ac-library-csharp.LibraryChecker.csproj", "{D61D3584-B86E-4C1F-BB8A-A1747A60E834}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Expand.Test", "Test\Expand.Test\Expand.Test.csproj", "{5121294D-76A4-44D4-8C2C-36B29FC162E4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -38,26 +36,22 @@ Global {D0662927-8142-43D2-ABA9-C1977107F0ED}.Debug|Any CPU.Build.0 = Debug|Any CPU {D0662927-8142-43D2-ABA9-C1977107F0ED}.Release|Any CPU.ActiveCfg = Release|Any CPU {D0662927-8142-43D2-ABA9-C1977107F0ED}.Release|Any CPU.Build.0 = Release|Any CPU - {1557AA29-1069-43ED-8552-791248C9E31C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1557AA29-1069-43ED-8552-791248C9E31C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1557AA29-1069-43ED-8552-791248C9E31C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1557AA29-1069-43ED-8552-791248C9E31C}.Release|Any CPU.Build.0 = Release|Any CPU - {522A1037-5060-4CBA-A4A3-99624FAD732E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {522A1037-5060-4CBA-A4A3-99624FAD732E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {522A1037-5060-4CBA-A4A3-99624FAD732E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {522A1037-5060-4CBA-A4A3-99624FAD732E}.Release|Any CPU.Build.0 = Release|Any CPU {D61D3584-B86E-4C1F-BB8A-A1747A60E834}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D61D3584-B86E-4C1F-BB8A-A1747A60E834}.Debug|Any CPU.Build.0 = Debug|Any CPU {D61D3584-B86E-4C1F-BB8A-A1747A60E834}.Release|Any CPU.ActiveCfg = Release|Any CPU {D61D3584-B86E-4C1F-BB8A-A1747A60E834}.Release|Any CPU.Build.0 = Release|Any CPU + {5121294D-76A4-44D4-8C2C-36B29FC162E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5121294D-76A4-44D4-8C2C-36B29FC162E4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5121294D-76A4-44D4-8C2C-36B29FC162E4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5121294D-76A4-44D4-8C2C-36B29FC162E4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {D0662927-8142-43D2-ABA9-C1977107F0ED} = {573A3DC6-BEB2-4E3A-8EB3-E4CB88F3C8F1} - {522A1037-5060-4CBA-A4A3-99624FAD732E} = {573A3DC6-BEB2-4E3A-8EB3-E4CB88F3C8F1} {D61D3584-B86E-4C1F-BB8A-A1747A60E834} = {573A3DC6-BEB2-4E3A-8EB3-E4CB88F3C8F1} + {5121294D-76A4-44D4-8C2C-36B29FC162E4} = {573A3DC6-BEB2-4E3A-8EB3-E4CB88F3C8F1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3DF2A5DC-C174-486C-A24B-1F08FAA0D4F5}