public static void CalculateInv(Span <StaticModInt <T> > a) { var n = a.Length; var h = InternalMath.CeilPow2(n); for (int ph = h; ph >= 1; ph--) { // ブロックサイズの半分 int w = 1 << (ph - 1); // ブロック数 int p = 1 << (h - ph); var iNow = StaticModInt <T> .Raw(1); // 各ブロックの s 段目 for (int s = 0; s < w; s++) { int offset = s << (h - ph + 1); for (int i = 0; i < p; i++) { var l = a[i + offset]; var r = a[i + offset + p]; a[i + offset] = l + r; a[i + offset + p] = StaticModInt <T> .Raw( unchecked ((int)((ulong)(default(T).Mod + l.Value - r.Value) * (ulong)iNow.Value % default(T).Mod))); } iNow *= sumIE[InternalBit.BSF(~(uint)s)]; } } }
private static StaticModInt <T>[] CalcurateSumIE() { int g = InternalMath.PrimitiveRoot((int)default(T).Mod); int cnt2 = InternalBit.BSF(default(T).Mod - 1); var e = new StaticModInt <T>(g).Pow((default(T).Mod - 1) >> cnt2); var ie = e.Inv(); var sumIE = new StaticModInt <T> [cnt2 - 2]; // es[i]^(2^(2+i)) == 1 Span <StaticModInt <T> > es = stackalloc StaticModInt <T> [cnt2 - 1]; Span <StaticModInt <T> > ies = stackalloc StaticModInt <T> [cnt2 - 1]; for (int i = es.Length - 1; i >= 0; i--) { // e^(2^(2+i)) == 1 es[i] = e; ies[i] = ie; e *= e; ie *= ie; } var now = StaticModInt <T> .Raw(1); for (int i = 0; i < sumIE.Length; i++) { sumIE[i] = ies[i] * now; now *= es[i]; } return(sumIE); }
public static void Calculate(Span <StaticModInt <T> > a) { var n = a.Length; var h = InternalMath.CeilPow2(n); for (int ph = 1; ph <= h; ph++) { // ブロックサイズの半分 int w = 1 << (ph - 1); // ブロック数 int p = 1 << (h - ph); var now = StaticModInt <T> .Raw(1); // 各ブロックの s 段目 for (int s = 0; s < w; s++) { int offset = s << (h - ph + 1); for (int i = 0; i < p; i++) { var l = a[i + offset]; var r = a[i + offset + p] * now; a[i + offset] = l + r; a[i + offset + p] = l - r; } now *= sumE[InternalBit.BSF(~(uint)s)]; } } }
public void ConvolutionEmptyTest(int lengthA, int lengthB) { var aInt = new int[lengthA]; var bInt = new int[lengthB]; var aUInt = new uint[lengthA]; var bUInt = new uint[lengthB]; var aLong = new long[lengthA]; var bLong = new long[lengthB]; var aULong = new ulong[lengthA]; var bULong = new ulong[lengthB]; var aMod = new StaticModInt <Mod998244353> [lengthA]; var bMod = new StaticModInt <Mod998244353> [lengthB]; var actualInt = AtCoder.Math.Convolution(aInt, bInt); var actualUInt = AtCoder.Math.Convolution(aUInt, bUInt); var actualLong = AtCoder.Math.Convolution(aLong, bLong); var actualULong = AtCoder.Math.Convolution(aULong, bULong); var actualModInt = AtCoder.Math.Convolution(aMod, bMod); var actualModIntSpan = AtCoder.Math.Convolution((ReadOnlySpan <StaticModInt <Mod998244353> >)aMod, bMod); Assert.Equal(Array.Empty <int>(), actualInt); Assert.Equal(Array.Empty <uint>(), actualUInt); Assert.Equal(Array.Empty <long>(), actualLong); Assert.Equal(Array.Empty <ulong>(), actualULong); Assert.Equal(Array.Empty <StaticModInt <Mod998244353> >(), actualModInt); Assert.Equal(Array.Empty <StaticModInt <Mod998244353> >(), actualModIntSpan.ToArray()); }
public void DivisionNotPrimeTest(int input, int expected) { var m = StaticModInt <Mod15> .Raw(input); var actual = 1 / m; Assert.Equal(expected, actual); }
private StaticModInt <T>[][] ToMatrix(VectorizedStaticModInt <T>[] c, int len0, int len1) { Debug.Assert(len0 * len1 <= c.Length * 8); var rt = new StaticModInt <T> [len0][]; for (int i = 0; i < rt.Length; i++) { var row = rt[i] = new StaticModInt <T> [len1]; var src = MemoryMarshal.Cast <VectorizedStaticModInt <T>, uint>(c.AsSpan(S8 * i)); var dst = MemoryMarshal.Cast <StaticModInt <T>, uint>(row); src[..dst.Length].CopyTo(dst);
public StaticModIntFactor(int max) { fac = new StaticModInt <T> [++max]; finv = new StaticModInt <T> [max]; fac[0] = fac[1] = 1; finv[0] = finv[1] = 1; for (var i = 2; i < max; i++) { fac[i] = fac[i - 1] * i; } finv[^ 1] = 1 / fac[^ 1];
public static long Calc(int n) { n >>= 2; var a = new StaticModInt <Mod377487361> [n]; var b = new StaticModInt <Mod377487361> [n]; for (int i = 0; i < n; i++) { a[i] = i + 1234; b[i] = i + 5678; } var c = MathLib.Convolution(a, b); return(c[0].Value); }
private void ConvolutionMod <T>(int lengthA, int lengthB, ulong seed) where T : struct, IStaticMod { var rand = new XorShift(seed); var a = new StaticModInt <T> [lengthA]; var b = new StaticModInt <T> [lengthB]; var aRaw = new ulong[lengthA]; var bRaw = new ulong[lengthB]; for (int i = 0; i < a.Length; i++) { aRaw[i] = rand.Next(); a[i] = StaticModInt <T> .Raw((int)(aRaw[i] % default(T).Mod)); } for (int i = 0; i < b.Length; i++) { bRaw[i] = rand.Next(); b[i] = StaticModInt <T> .Raw((int)(bRaw[i] % default(T).Mod)); } var expected = new StaticModInt <T> [a.Length + b.Length - 1]; for (int i = 0; i < a.Length; i++) { for (int j = 0; j < b.Length; j++) { expected[i + j] += a[i] * b[j]; } } // 各種オーバーロードについてテスト var actualModInt = AtCoder.Math.Convolution(a, b); var actualModIntSpan = AtCoder.Math.Convolution((ReadOnlySpan <StaticModInt <T> >)a, b); var actualInt = AtCoder.Math.Convolution <T>(a.Select(ai => ai.Value).ToArray(), b.Select(bi => bi.Value).ToArray()); var actualUInt = AtCoder.Math.Convolution <T>(a.Select(ai => (uint)ai.Value).ToArray(), b.Select(bi => (uint)bi.Value).ToArray()); var actualLong = AtCoder.Math.Convolution <T>(a.Select(ai => (long)ai.Value).ToArray(), b.Select(bi => (long)bi.Value).ToArray()); var actualULong = AtCoder.Math.Convolution <T>(aRaw, bRaw); Assert.Equal(expected, actualModInt); Assert.Equal(expected, actualModIntSpan.ToArray()); Assert.Equal(expected.Select(ei => ei.Value), actualInt); Assert.Equal(expected.Select(ei => (uint)ei.Value), actualUInt); Assert.Equal(expected.Select(ei => (long)ei.Value), actualLong); Assert.Equal(expected.Select(ei => (ulong)ei.Value), actualULong); }
private static StaticModInt <T>[] CalcurateSumE() { int g = InternalMath.PrimitiveRoot <T>(); int cnt2 = InternalBit.BSF(default(T).Mod - 1); var e = new StaticModInt <T>(g).Pow((default(T).Mod - 1) >> cnt2); var ie = e.Inv(); var sumE = new StaticModInt <T> [30]; // es[i]^(2^(2+i)) == 1 Span <StaticModInt <T> > es = #if !NETCOREAPP3_0_OR_GREATER new #else stackalloc #endif StaticModInt <T> [cnt2 - 1]; Span <StaticModInt <T> > ies = #if !NETCOREAPP3_0_OR_GREATER new #else stackalloc #endif StaticModInt <T> [cnt2 - 1]; for (int i = es.Length - 1; i >= 0; i--) { // e^(2^(2+i)) == 1 es[i] = e; ies[i] = ie; e *= e; ie *= ie; } var now = StaticModInt <T> .Raw(1); for (int i = 0; i <= cnt2 - 2; i++) { sumE[i] = es[i] * now; now *= ies[i]; } return(sumE); }
public ModCombination(int max = 1000000) { if (max >= default(T).Mod) { ThrowArgumentOutOfRangeException(); } _factorials = new StaticModInt <T> [max + 1]; _invFactorials = new StaticModInt <T> [max + 1]; _factorials[0] = _factorials[1] = StaticModInt <T> .Raw(1); _invFactorials[0] = _invFactorials[1] = StaticModInt <T> .Raw(1); for (int i = 2; i < _factorials.Length; i++) { _factorials[i] = _factorials[i - 1] * StaticModInt <T> .Raw(i); } _invFactorials[^ 1] = _factorials[^ 1].Inverse();
public void Solve(ConsoleReader cr, ConsoleWriter cw) { int n = cr; int q = cr; var seg = new Segtree <(StaticModInt <Mod998244353> a, StaticModInt <Mod998244353> b), SegtreeSolverOp>( cr.Repeat(n).Select(cr => (StaticModInt <Mod998244353> .Raw(cr), StaticModInt <Mod998244353> .Raw(cr)))); for (int i = 0; i < q; i++) { int t = cr; if (t == 0) { int p = cr; int c = cr; int d = cr; seg[p] = (StaticModInt <Mod998244353> .Raw(c), StaticModInt <Mod998244353> .Raw(d)); } else { int l = cr; int r = cr; int x = cr; var(a, b) = seg[l..r];
public static void Calculate(Span <StaticModInt <T> > a) { CheckPow2(a.Length); var n = a.Length; var h = InternalBit.CeilPow2(n); var regLength = Vector <uint> .Count; #if !NETCOREAPP3_0_OR_GREATER var copyTmp = new uint[regLength]; #endif // 全要素がmodのVector<uint>を作成(比較および加減算用) var modV = new Vector <uint>(default(T).Mod); for (int ph = 1; ph <= h; ph++) { // ブロックサイズの半分 int w = 1 << (ph - 1); // ブロック数 int p = 1 << (h - ph); var now = StaticModInt <T> .Raw(1); // 各ブロックの s 段目 for (int s = 0; s < w; s++) { int offset = s << (h - ph + 1); var ls = a.Slice(offset, p); var rs = a.Slice(offset + p, p); if (p < regLength) { for (int i = 0; i < p; i++) { var l = ls[i]; var r = rs[i] * now; ls[i] = l + r; rs[i] = l - r; } } else { foreach (ref var r in rs) { r *= now; } // uintとして再解釈 var lu = MemoryMarshal.Cast <StaticModInt <T>, uint>(ls); var ru = MemoryMarshal.Cast <StaticModInt <T>, uint>(rs); for (int i = 0; i < lu.Length; i += regLength) { var luSliced = lu.Slice(i); var ruSliced = ru.Slice(i); var u = new Vector <uint>(luSliced); var v = new Vector <uint>(ruSliced); var add = u + v; var sub = u - v; var ge = Vector.GreaterThanOrEqual(add, modV); add = Vector.ConditionalSelect(ge, add - modV, add); ge = Vector.GreaterThanOrEqual(sub, modV); sub = Vector.ConditionalSelect(ge, sub + modV, sub); #if !NETCOREAPP3_0_OR_GREATER add.CopyTo(copyTmp); copyTmp.CopyTo(luSliced); sub.CopyTo(copyTmp); copyTmp.CopyTo(ruSliced); #else add.CopyTo(luSliced); sub.CopyTo(ruSliced); #endif } } now *= sumE[InternalBit.BSF(~(uint)s)]; } } }
public void Deconstruct(out int count, out StaticModInt <Mod1000000007> way) => (count, way) = (Count, Way);
public CountAndWay(int count, StaticModInt <Mod1000000007> way) { Count = count; Way = way; }