Beispiel #1
0
        public static void InitializeFactorial(long max, bool withInverse = false)
        {
            if (withInverse)
            {
                factorial_        = new ModInt[max + 1];
                inverseFactorial_ = new ModInt[max + 1];
                inverse_          = new ModInt[max + 1];

                factorial_[0]        = factorial_[1] = 1;
                inverseFactorial_[0] = inverseFactorial_[1] = 1;
                inverse_[1]          = 1;
                for (int i = 2; i <= max; i++)
                {
                    factorial_[i]        = factorial_[i - 1] * i;
                    inverse_[i]          = p_ - inverse_[p_ % i] * (p_ / i);
                    inverseFactorial_[i] = inverseFactorial_[i - 1] * inverse_[i];
                }
            }
            else
            {
                factorial_        = new ModInt[max + 1];
                inverseFactorial_ = new ModInt[max + 1];

                factorial_[0] = factorial_[1] = 1;
                for (int i = 2; i <= max; i++)
                {
                    factorial_[i] = factorial_[i - 1] * i;
                }

                inverseFactorial_[max] = new ModInt(1) / factorial_[max];
                for (long i = max - 1; i >= 0; i--)
                {
                    inverseFactorial_[i] = inverseFactorial_[i + 1] * (i + 1);
                }
            }
        }
Beispiel #2
0
        public static Span <ModInt> Convolve(ReadOnlySpan <ModInt> a, ReadOnlySpan <ModInt> b)
        {
            int resultLength = a.Length + b.Length - 1;
            int nttLength    = CeilPow2(resultLength);

            var aa = new ModInt[nttLength];

            a.CopyTo(aa);
            var bb = new ModInt[nttLength];

            b.CopyTo(bb);

            var fa = NumberTheoreticTransform(aa);
            var fb = NumberTheoreticTransform(bb);

            for (int i = 0; i < nttLength; ++i)
            {
                fa[i] *= fb[i];
            }

            var convolved = NumberTheoreticTransform(fa, true);

            return(convolved.Slice(0, resultLength));
        }
Beispiel #3
0
        public static ModInt[,] NumberTheoreticTransform2D(
            ModInt[,] a, bool inverses = false, bool extends = false, bool inplaces = true)
        {
            int h = a.GetLength(0);
            int w = a.GetLength(1);

            if (extends)
            {
                h        = CeilPow2(h);
                w        = CeilPow2(w);
                inplaces = false;
            }

            var ret = a;

            if (inplaces == false)
            {
                ret = new ModInt[h, w];
                int hh = a.GetLength(0);
                int ww = a.GetLength(1);
                for (int i = 0; i < hh; i++)
                {
                    for (int j = 0; j < ww; j++)
                    {
                        ret[i, j] = a[i, j];
                    }
                }
            }

            if (h == 1 && w == 1)
            {
                return(ret);
            }

            var b = new ModInt[h, w];

            {
                int n = w;
                int r = inverses
                                        ? (int)(ModInt.P - 1 - (ModInt.P - 1) / n)
                                        : (int)((ModInt.P - 1) / n);
                ModInt s  = ModInt.Pow(ModInt.ROOT, r);
                var    kp = new ModInt[n / 2 + 1];
                kp.AsSpan().Fill(1);

                for (int i = 0; i < n / 2; ++i)
                {
                    kp[i + 1] = kp[i] * s;
                }

                for (int y = 0; y < h; ++y)
                {
                    int l = n / 2;
                    for (int i = 1; i < n; i <<= 1, l >>= 1)
                    {
                        r = 0;
                        for (int j = 0; j < l; ++j, r += i)
                        {
                            s = kp[i * j];
                            for (int k = 0; k < i; ++k)
                            {
                                var p = ret[y, k + r];
                                var q = ret[y, k + r + n / 2];
                                b[y, k + 2 * r]     = p + q;
                                b[y, k + 2 * r + i] = (p - q) * s;
                            }
                        }

                        var temp = ret;
                        ret = b;
                        b   = temp;
                    }

                    if (inverses)
                    {
                        s = ModInt.Inverse(n);
                        for (int i = 0; i < n; ++i)
                        {
                            ret[y, i] = ret[y, i] * s;
                        }
                    }
                }
            }

            for (int i = 0; i < h; ++i)
            {
                for (int j = 0; j < w; ++j)
                {
                    b[i, j] = 0;
                }
            }

            {
                int n = h;
                int r = inverses
                                        ? (int)(ModInt.P - 1 - (ModInt.P - 1) / n)
                                        : (int)((ModInt.P - 1) / n);
                ModInt s  = ModInt.Pow(ModInt.ROOT, r);
                var    kp = new ModInt[n / 2 + 1];
                kp.AsSpan().Fill(1);

                for (int i = 0; i < n / 2; ++i)
                {
                    kp[i + 1] = kp[i] * s;
                }

                for (int x = 0; x < w; ++x)
                {
                    int l = n / 2;
                    for (int i = 1; i < n; i <<= 1, l >>= 1)
                    {
                        r = 0;
                        for (int j = 0; j < l; ++j, r += i)
                        {
                            s = kp[i * j];
                            for (int k = 0; k < i; ++k)
                            {
                                var p = ret[k + r, x];
                                var q = ret[k + r + n / 2, x];
                                b[k + 2 * r, x]     = p + q;
                                b[k + 2 * r + i, x] = (p - q) * s;
                            }
                        }

                        var temp = ret;
                        ret = b;
                        b   = temp;
                    }

                    if (inverses)
                    {
                        s = ModInt.Inverse(n);
                        for (int i = 0; i < n; ++i)
                        {
                            ret[i, x] = ret[i, x] * s;
                        }
                    }
                }
            }

            return(ret);
        }
Beispiel #4
0
        public static Span <ModInt> NumberTheoreticTransform(
            Span <ModInt> a, bool inverses = false, bool extends = false, bool inplaces = true)
        {
            int n = a.Length;

            if (extends)
            {
                n        = CeilPow2(n);
                inplaces = false;
            }

            var ret = a;

            if (inplaces == false)
            {
                ret = new ModInt[n];
                a.CopyTo(ret);
            }

            if (n == 1)
            {
                return(ret);
            }

            var b = new ModInt[n].AsSpan();
            int r = inverses
                                ? (int)(ModInt.P - 1 - (ModInt.P - 1) / n)
                                : (int)((ModInt.P - 1) / n);
            ModInt s  = ModInt.Pow(ModInt.ROOT, r);
            var    kp = new ModInt[n / 2 + 1];

            kp.AsSpan().Fill(1);

            for (int i = 0; i < n / 2; ++i)
            {
                kp[i + 1] = kp[i] * s;
            }

            int l = n / 2;

            for (int i = 1; i < n; i <<= 1, l >>= 1)
            {
                r = 0;
                for (int j = 0; j < l; ++j, r += i)
                {
                    s = kp[i * j];
                    for (int k = 0; k < i; ++k)
                    {
                        var p = ret[k + r];
                        var q = ret[k + r + n / 2];
                        b[k + 2 * r]     = p + q;
                        b[k + 2 * r + i] = (p - q) * s;
                    }
                }

                var temp = ret;
                ret = b;
                b   = temp;
            }

            if (inverses)
            {
                s = ModInt.Inverse(n);
                for (int i = 0; i < n; ++i)
                {
                    ret[i] = ret[i] * s;
                }
            }

            return(ret);
        }