[ABC206] E - Divide Both

[Q] https://atcoder.jp/contests/abc206/tasks/abc206_e

・考察
0. とるペアは(x < y)として選ぶ。最後にswap分の2倍をする予定。
1. 倍数を固定したときに何通りとれるかを考える。それぞれの倍数でnC2通りずつ。
この時点では、(x, y)に対してg = xになる場合をいったん考慮しない。
2. 2の倍数を選んだ時に、実はgcd=4でした、みたいな(4, 8)とかを除く。
cnt[g] -= cnt[g*2] + cnt[g*3] + …をすればいい。
3. 2 ~ Rの倍数を加算していけばいい。
4. だけど、(x, y)でg==xの場合を除く。これは、倍数の個数-1個。
2,4,6,8が候補だとして、2をとる組み合わせを除くので。4,6,8の3個。

・実装

int main() {
  cincout();
  
  ll L, R;
  cin >> L >> R;
  vector<ll> cnt(R + 10, 0);
  // 1. 倍数を固定したときに、何通りとれるか。それぞれnC2通り
  for(ll i = R; i > 1; --i){ // 降順必須
    ll c = R / i - (L - 1) / i;
    cnt[i] = c * (c - 1) / 2;
    ll g = i * 2;
    // 2. より大きいgでとれるものを省く
    while (g <= R){
      cnt[i] -= cnt[g];
      g += i;
    }
  }
  
  ll ans = 0;
  for(ll i = 2; i <= R; ++i){
    ll c = R / i - (L - 1) / i;
    // 3. i==gになっている場合を除く
    if (i >= L && i <= R){ 
      cnt[i] -= c - 1;
    }
    ans += cnt[i];
  }
  // 0. swap分の2倍
  cout << (ans * 2) << endl;
}


https://atcoder.jp/contests/abc206/submissions/37966450






この記事が気に入ったらサポートをしてみませんか?