/// <summary>
        /// 最長共通接頭辞の長さ
        /// S[l1:]とother.S[l2:]
        /// </summary>
        public int GetLcp(RollingHash other, int l1, int l2)
        {
            if (other == null)
            {
                throw new ArgumentNullException(nameof(other));
            }

            int len = Math.Min(S.Length - l1, other.S.Length - l2);
            int low = -1, high = len + 1;

            while (high - low > 1)
            {
                var mid = low + (high - low) / 2;

                if (!Match(other, l1, l2, mid))
                {
                    high = mid;
                }
                else
                {
                    low = mid;
                }
            }

            return(low);
        }
        /// <summary>
        /// S[l1:]がotherで始まっているか
        /// </summary>
        public bool BeginWith(RollingHash other, int l1)
        {
            if (other == null)
            {
                throw new ArgumentNullException(nameof(other));
            }

            return(Match(other, l1, 0, other.S.Length));
        }
        /// <summary>
        /// 全てのModsでS[l,r)が一致するか
        /// </summary>
        public bool Match(RollingHash other, int l1, int l2, int len)
        {
            if (other == null)
            {
                throw new ArgumentNullException(nameof(other));
            }

            // 範囲外
            if (S.Length < l1 + len || other.S.Length < l2 + len)
            {
                return(false);
            }

            for (int i = 0; i < _mods.Length; i++)
            {
                if (GetHash(l1, l1 + len, i) != other.GetHash(l2, l2 + len, i))
                {
                    return(false);
                }
            }

            return(true);
        }