競技プログラミング日記

主に AtCoder の記事です

AtCoder Beginner Contest 162E問題

\(\def \set #1#2{\{ #1 \ \vert \ #2 \}}\)

ABC162E

解法

約数系包除原理に近い考え.
まず gcd \(d\) を全探索して, \(d\) の倍数になる個数を数える. 丁度 \(d\) に対して調べるのが本問の答えだが, 簡単のために 最大とは限らない公約数 \(d\) に対しても調べて, それを利用して求める.

\(f(d) := \#\set{A \in K^{N}}{d = gcd(A)}\),
\(g(d) := \#\set{A \in K^{N}}{d \in cd(A)} = \#\set{A \in K^{N}}{d \leq_{div} gcd(A)}\)

とする.ここで, \(cd(A)\) は \(A\) の公約数全体の集合.

\(\# g(d) = (\lfloor \frac{K}{d} \rfloor)^{N} \)

となる. また, \(d \leq_{div} gcd(A)\) であることは, \(gcd(A) = d, 2d, 3d, \cdots \) であることと同値なので,

\(g(d) = f(d) + f(2d) + f(3d) + \cdots\)

と同値. よって, \(f(d) = g(d) - f(2d) - f(3d) - \cdots\) となるから,\(d\) の大きい方から \(f(d)\) が求まる.

使っている記号,マクロ等 "https://ecsmtlir.hatenablog.com/entry/2022/12/23/131925"

int main() {
  ll n,k;
  cin >> n >> k;

  mint ans = 0;
  vector<mint> f(k+1);
  drep1(d,k){
    f[d] = mint(k/d).pow(n);
    for(ll i = 2*d; i <= k; i += d){
      f[d] -= f[i];
    }

    ans += f[d] * d;
  }

  cout << ans.val() << endl;

  return 0;
}