Official

I - Count Setwise Coprime Editorial by toam


\(S\) のすべての要素を割り切る整数のうち最大のものを \(\gcd(S)\) とします.


解法1 \(O(R^{3/4})\)

\(L\) 以上 \(R\) 以下の正整数からなる集合 \(S\) であって,\(\gcd(S)=1\) となるものの個数を \(f(L,R)\) と表すことにします.このとき,\(f(L,R)\)\(2^{R-L+1}-1\) から \(\gcd(S)=2,3,4\ldots\) となる \(S\) の個数を引いた値になります. \(\gcd(S)=g\) となる \(S\) の個数は \(f(\lceil L/g \rceil,\lfloor R/g \rfloor)\) と等しいため

\[ f(L,R)=2^{R-L+1}-1-\displaystyle \sum_{g=2}^R f(\lceil L/g \rceil,\lfloor R/g \rfloor) \]

が成り立ちます.これを再帰的に求めればよいです.シグマの中身については \((\lceil L/g \rceil,\lfloor R/g \rfloor)\) が同じ値をまとめて処理することで,計算量は expected \(O(R^{3/4})\) になります(この計算量で通ることを想定しています).計算量解析については過去の ABC-Ex の解説を参考にしてください.

\(\Theta(R)\) 解法を落としたい関係上,TL が厳しめに設定されています.メモ化の方法によっては TLE するかもしれません.

mod = 998244353
memo = {}

def calc(L, R):
    if L + R in memo:
        return memo[L + R]
    res = pow(2, R - L + 1, mod) - 1
    g = 2
    while g <= R:
        l = (L - 1) // g
        r = R // g
        ng = R // r
        if l > 0:
            ng = min(ng, (L - 1) // l)
        res -= calc(l + 1, r) * (ng - g + 1)
        res %= mod
        g = ng + 1
    memo[L + R] = res
    return res

L, R = map(int, input().split())
print(calc(L, R))

解法2 \(\tilde{O}(R^{2/3})\)

\(L\) 以上 \(R\) 以下の正整数からなる集合のうち, \(\gcd(S)\)\(d\) の倍数であるものの個数を \(h(d)(=2^{\lfloor R/d \rfloor-\lfloor (L-1)/d \rfloor}-1)\) と置くと,答えは Möbius 関数を \(\mu(n)\) として \(\displaystyle \sum_{d=1}^R \mu (d)h(d)\) になります.\(h(d)\) の値が同じとなるように \(R\) 以下の正整数 を \(m\) 個の区間 \([d_0+1,d_1],[d_1+1,d_2],\ldots,[d_{m-1}+1,d_m]\ (d_0=0, d_m=R)\) に分けると,Mertens 関数 (Möbius 関数の累積和) を \(M(n)\) として

\[ \displaystyle \sum_{d=1}^R \mu (d)h(d)=\sum_{i=1}^m \sum_{d=d_{i-1}+1}^{d_i} \mu(d) h(d_i)=\sum _{i=1}^m (M(d_i)-M(d_{i-1}))h(d_i) \]

となります.\(d_i\)\(\lfloor R/n \rfloor\)\(\lfloor (L-1)/n\rfloor\) といった形で表されるものに限られるため,\(M(\lfloor R/n \rfloor), M(\lfloor (L-1)/n\rfloor)\) の値が分かればよく,これは \(\tilde{O}(R^{2/3})\) で求めることができます.\(M(\lfloor R/n \rfloor)\) の求め方については maspy さんの記事 Dirichlet 積と、数論関数の累積和 を参考にしてください.

posted:
last update: