예제 #1
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);
        }
예제 #2
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);
        }