コード例 #1
0
        /// <summary>
        /// 畳み込みを mod <typeparamref name="TMod"/> で計算します。
        /// </summary>
        /// <remarks>
        /// <para><paramref name="a"/>, <paramref name="b"/> の少なくとも一方が空の場合は空配列を返します。</para>
        /// <para>制約:</para>
        /// <para>- 2≤<typeparamref name="TMod"/>≤2×10^9</para>
        /// <para>- <typeparamref name="TMod"/> は素数</para>
        /// <para>- 2^c | (<typeparamref name="TMod"/> - 1) かつ |<paramref name="a"/>| + |<paramref name="b"/>| - 1 ≤ 2^c なる c が存在する</para>
        /// <para>計算量: O((|<paramref name="a"/>|+|<paramref name="b"/>|)log(|<paramref name="a"/>|+|<paramref name="b"/>|) + log<typeparamref name="TMod"/>)</para>
        /// </remarks>
        public static Int32[] Convolution <TMod>(ReadOnlySpan <Int32> a, ReadOnlySpan <Int32> b) where TMod : struct, IStaticMod
        {
            var n = a.Length;
            var m = b.Length;

            if (n == 0 || m == 0)
            {
                return(Array.Empty <Int32>());
            }

            var a2 = new StaticModInt <TMod> [n];
            var b2 = new StaticModInt <TMod> [m];

            for (int i = 0; i < a2.Length; i++)
            {
                a2[i] = new StaticModInt <TMod>(a[i]);
            }
            for (int i = 0; i < b2.Length; i++)
            {
                b2[i] = new StaticModInt <TMod>(b[i]);
            }

            var c2 = Convolution(a2, b2);
            var c  = new Int32[n + m - 1];

            for (int i = 0; i < c.Length; i++)
            {
                c[i] = (Int32)c2[i].Value;
            }
            return(c);
        }
コード例 #2
0
        /// <summary>
        /// 畳み込みを mod <typeparamref name="TMod"/> で計算します。
        /// </summary>
        /// <remarks>
        /// <para><paramref name="a"/>, <paramref name="b"/> の少なくとも一方が空の場合は空配列を返します。</para>
        /// <para>制約:</para>
        /// <para>- 2≤<typeparamref name="TMod"/>≤2×10^9</para>
        /// <para>- <typeparamref name="TMod"/> は素数</para>
        /// <para>- 2^c | (<typeparamref name="TMod"/> - 1) かつ |<paramref name="a"/>| + |<paramref name="b"/>| - 1 ≤ 2^c なる c が存在する</para>
        /// <para>計算量: O((|<paramref name="a"/>|+|<paramref name="b"/>|)log(|<paramref name="a"/>|+|<paramref name="b"/>|) + log<typeparamref name="TMod"/>)</para>
        /// </remarks>
        public static Span <StaticModInt <TMod> > Convolution <TMod>(ReadOnlySpan <StaticModInt <TMod> > a, ReadOnlySpan <StaticModInt <TMod> > b)
            where TMod : struct, IStaticMod
        {
            var n = a.Length;
            var m = b.Length;

            if (n == 0 || m == 0)
            {
                return(Array.Empty <StaticModInt <TMod> >());
            }

            if (System.Math.Min(n, m) <= 60)
            {
                return(ConvolutionNaive(a, b));
            }

            int z = 1 << Internal.InternalMath.CeilPow2(n + m - 1);

            var aTemp = new StaticModInt <TMod> [z];

            a.CopyTo(aTemp);

            var bTemp = new StaticModInt <TMod> [z];

            b.CopyTo(bTemp);

            return(Convolution(aTemp.AsSpan(), bTemp.AsSpan(), n, m, z));
        }
コード例 #3
0
        static StaticModInt <T>[] ConvNative <T>(StaticModInt <T>[] a, StaticModInt <T>[] b) where T : struct, IStaticMod
        {
            int n = a.Length, m = b.Length;
            var c = new StaticModInt <T> [n + m - 1];

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < m; j++)
                {
                    c[i + j] += a[i] * b[j];
                }
            }
            return(c);
        }
コード例 #4
0
        public void Mid()
        {
            var mt = MTRandom.Create();
            int n = 1234, m = 2345;
            var a = new StaticModInt <Mod998244353> [n];
            var b = new StaticModInt <Mod998244353> [m];

            for (int i = 0; i < n; i++)
            {
                a[i] = mt.NextUInt();
            }
            for (int i = 0; i < m; i++)
            {
                b[i] = mt.NextUInt();
            }
            MathLib.Convolution(a, b).Should().Equal(ConvNative(a, b));
        }
コード例 #5
0
        public void MemoryStatic()
        {
            var mt = MTRandom.Create();

            for (int n = 0; n < 100; n++)
            {
                var arr      = new StaticModInt <MemoryID> [n];
                var expected = new uint[n];
                for (int i = 0; i < n; i++)
                {
                    var v = mt.NextUInt();
                    arr[i]      = v;
                    expected[i] = v % 101;
                }
                MemoryMarshal.Cast <StaticModInt <MemoryID>, uint>(arr).ToArray()
                .Should().Equal(expected);
            }
        }
コード例 #6
0
        /// <summary>
        /// 畳み込みを mod <typeparamref name="TMod"/> で計算します。
        /// </summary>
        /// <remarks>
        /// <para><paramref name="a"/>, <paramref name="b"/> の少なくとも一方が空の場合は空配列を返します。</para>
        /// <para>制約:</para>
        /// <para>- 2≤<typeparamref name="TMod"/>≤2×10^9</para>
        /// <para>- <typeparamref name="TMod"/> は素数</para>
        /// <para>- 2^c | (<typeparamref name="TMod"/> - 1) かつ |<paramref name="a"/>| + |<paramref name="b"/>| - 1 ≤ 2^c なる c が存在する</para>
        /// <para>計算量: O((|<paramref name="a"/>|+|<paramref name="b"/>|)log(|<paramref name="a"/>|+|<paramref name="b"/>|) + log<typeparamref name="TMod"/>)</para>
        /// </remarks>
        public static ulong[] Convolution <TMod>(ulong[] a, ulong[] b) where TMod : struct, IStaticMod
        {
            var n = a.Length;
            var m = b.Length;

            if (n == 0 || m == 0)
            {
                return(Array.Empty <ulong>());
            }

            if (System.Math.Min(n, m) <= 60)
            {
                var c = ConvolutionNaive <TMod>(a.Select(TakeMod).ToArray(),
                                                b.Select(TakeMod).ToArray());
                return(c.Select(ci => (ulong)ci.Value).ToArray());
            }
            else
            {
                int z = 1 << Internal.InternalMath.CeilPow2(n + m - 1);

                var aTemp = new StaticModInt <TMod> [z];
                for (int i = 0; i < a.Length; i++)
                {
                    aTemp[i] = TakeMod(a[i]);
                }

                var bTemp = new StaticModInt <TMod> [z];
                for (int i = 0; i < b.Length; i++)
                {
                    bTemp[i] = TakeMod(b[i]);
                }

                var c      = Convolution <TMod>(aTemp, bTemp, n, m, z)[0..(n + m - 1)];
                var result = new ulong[c.Length];
                for (int i = 0; i < result.Length; i++)
                {
                    result[i] = (ulong)c[i].Value;
                }
                return(result);
            }

            StaticModInt <TMod> TakeMod(ulong x) => StaticModInt <TMod> .Raw((int)(x % default(TMod).Mod));
        }
コード例 #7
0
        public void SimpleSMod()
        {
            var mt = MTRandom.Create();

            for (int n = 1; n < 20; n++)
            {
                for (int m = 1; m < 20; m++)
                {
                    var a = new StaticModInt <Mod998244353> [n];
                    var b = new StaticModInt <Mod998244353> [m];

                    for (int i = 0; i < n; i++)
                    {
                        a[i] = mt.NextUInt();
                    }
                    for (int i = 0; i < m; i++)
                    {
                        b[i] = mt.NextUInt();
                    }
                    MathLib.Convolution(a, b).Should().Equal(ConvNative(a, b));
                }
            }
            for (int n = 1; n < 20; n++)
            {
                for (int m = 1; m < 20; m++)
                {
                    var a = new StaticModInt <Mod924844033> [n];
                    var b = new StaticModInt <Mod924844033> [m];

                    for (int i = 0; i < n; i++)
                    {
                        a[i] = mt.NextUInt();
                    }
                    for (int i = 0; i < m; i++)
                    {
                        b[i] = mt.NextUInt();
                    }
                    MathLib.Convolution(a, b).Should().Equal(ConvNative(a, b));
                }
            }
        }
コード例 #8
0
        /// <summary>
        /// 畳み込みを mod <typeparamref name="TMod"/> で計算します。
        /// </summary>
        /// <remarks>
        /// <para><paramref name="a"/>, <paramref name="b"/> の少なくとも一方が空の場合は空配列を返します。</para>
        /// <para>制約:</para>
        /// <para>- 2≤<typeparamref name="TMod"/>≤2×10^9</para>
        /// <para>- <typeparamref name="TMod"/> は素数</para>
        /// <para>- 2^c | (<typeparamref name="TMod"/> - 1) かつ |<paramref name="a"/>| + |<paramref name="b"/>| - 1 ≤ 2^c なる c が存在する</para>
        /// <para>計算量: O((|<paramref name="a"/>|+|<paramref name="b"/>|)log(|<paramref name="a"/>|+|<paramref name="b"/>|) + log<typeparamref name="TMod"/>)</para>
        /// </remarks>
        public static int[] Convolution <TMod>(int[] a, int[] b) where TMod : struct, IStaticMod
        {
            var n = a.Length;
            var m = b.Length;

            if (n == 0 || m == 0)
            {
                return(Array.Empty <int>());
            }

            if (System.Math.Min(n, m) <= 60)
            {
                var c = ConvolutionNaive <TMod>(a.Select(ai => new StaticModInt <TMod>(ai)).ToArray(),
                                                b.Select(bi => new StaticModInt <TMod>(bi)).ToArray());
                return(c.Select(ci => ci.Value).ToArray());
            }
            else
            {
                int z = 1 << Internal.InternalMath.CeilPow2(n + m - 1);

                var aTemp = new StaticModInt <TMod> [z];
                for (int i = 0; i < a.Length; i++)
                {
                    aTemp[i] = new StaticModInt <TMod>(a[i]);
                }

                var bTemp = new StaticModInt <TMod> [z];
                for (int i = 0; i < b.Length; i++)
                {
                    bTemp[i] = new StaticModInt <TMod>(b[i]);
                }

                var c      = Convolution <TMod>(aTemp, bTemp, n, m, z)[0..(n + m - 1)];
                var result = new int[c.Length];
                for (int i = 0; i < result.Length; i++)
                {
                    result[i] = c[i].Value;
                }
                return(result);
            }
        }
コード例 #9
0
        private static StaticModInt <TMod>[] ConvolutionNaive <TMod>(ReadOnlySpan <StaticModInt <TMod> > a, ReadOnlySpan <StaticModInt <TMod> > 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 <TMod> [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);
        }
コード例 #10
0
        private static StaticModInt <TMod>[] ConvolutionFFT <TMod>(ReadOnlySpan <StaticModInt <TMod> > a, ReadOnlySpan <StaticModInt <TMod> > b)
            where TMod : struct, IStaticMod
        {
            int n = a.Length, m = b.Length;
            int z  = 1 << InternalBit.CeilPow2(n + m - 1);
            var a2 = new StaticModInt <TMod> [z];
            var b2 = new StaticModInt <TMod> [z];

            a.CopyTo(a2);
            b.CopyTo(b2);

            var result = ConvolutionFFTInner(a2, b2);

            Array.Resize(ref result, n + m - 1);
            var iz = new StaticModInt <TMod>(z).Inv();

            for (int i = 0; i < result.Length; i++)
            {
                result[i] *= iz;
            }

            return(result);
        }
コード例 #11
0
 public StaticModInt <T> Divide(StaticModInt <T> x, StaticModInt <T> y) => x / y;
コード例 #12
0
        public void Inv()
        {
            for (int i = 1; i < 10; i++)
            {
                int x = new StaticModInt <InvID11>(i).Inv().Value;
                ((long)x * i % 11).Should().Be(1);
            }


            for (int i = 1; i < 12; i++)
            {
                if (Gcd(i, 12) != 1)
                {
                    continue;
                }
                int x = new StaticModInt <InvID12>(i).Inv().Value;
                ((long)x * i % 12).Should().Be(1);
            }

            for (int i = 1; i < 100000; i++)
            {
                int x = new StaticModInt <InvID1000000007>(i).Inv().Value;
                ((long)x * i % 1000000007).Should().Be(1);
            }

            for (int i = 1; i < 100000; i++)
            {
                if (Gcd(i, 1000000008) != 1)
                {
                    continue;
                }
                int x = new StaticModInt <InvID1000000008>(i).Inv().Value;
                ((long)x * i % 1000000008).Should().Be(1);
            }

            for (int i = 1; i < 100000; i++)
            {
                int x = new StaticModInt <InvID998244353>(i).Inv().Value;
                ((long)x * i % 998244353).Should().Be(1);
            }

            DynamicModInt <InvID998244353> .Mod = 998244353;
            for (int i = 1; i < 100000; i++)
            {
                int x = new DynamicModInt <InvID998244353>(i).Inv().Value;
                x.Should().BeGreaterOrEqualTo(0);
                x.Should().BeLessOrEqualTo(998244353 - 1);
                ((long)x * i % 998244353).Should().Be(1);
            }


            DynamicModInt <InvID1000000008> .Mod = 1000000008;
            for (int i = 1; i < 100000; i++)
            {
                if (Gcd(i, 1000000008) != 1)
                {
                    continue;
                }
                int x = new DynamicModInt <InvID1000000008>(i).Inv().Value;
                ((long)x * i % 1000000008).Should().Be(1);
            }
        }
コード例 #13
0
 public StaticModInt <T> Subtract(StaticModInt <T> x, StaticModInt <T> y) => x - y;
コード例 #14
0
 public StaticModInt <T> Add(StaticModInt <T> x, StaticModInt <T> y) => x + y;
コード例 #15
0
 public StaticModInt <T> Decrement(StaticModInt <T> x) => -- x;
コード例 #16
0
 public StaticModInt <T> Increment(StaticModInt <T> x) => ++ x;
コード例 #17
0
 public StaticModInt <T> Minus(StaticModInt <T> x) => - x;
コード例 #18
0
 StaticModInt <T> IDivisionOperator <StaticModInt <T> > .Modulo(StaticModInt <T> x, StaticModInt <T> y) => throw new NotSupportedException();
コード例 #19
0
 public StaticModInt <T> Multiply(StaticModInt <T> x, StaticModInt <T> y) => x * y;