見出し画像

abc253に挑んだ初心者の感想

abc253のa問題からd問題までの簡単な解説を載せます.

A - Median?

bが中央値かどうかを調べる問題です.a≦b≦cまたはc≦b≦aが成立すればOKなので以下のようになります.

int a, b, c;

int main(){
  cin >> a >> b >> c;

  if((a <= b && b <= c) || (c <= b && b <= a)) cout << "Yes" << endl;
  else cout << "No" << endl;
}

B - Distance Between Tokens

2つのoのマンハッタン距離を求めます.マンハッタン距離とは格子状の道路を移動する際の距離です.2点(x1, y1)、(x2, y2)間のマンハッタン距離は
                                     d = |x1 - x2| + |y1 - y2| 
となります.

vector<string> field(110);
int h, w;

int main(){
  cin >> h >> w;
  rep(i, 0, h){
    cin >> field.at(i);
  }

  vector<P> p;
  rep(i, 0, h){
    rep(j, 0, w){
      if(field.at(i).at(j)=='o') p.push_back(make_pair(i, j));
    }
  }

  cout << abs(p.at(0).first - p.at(1).first) + abs(p.at(0).second - p.at(1).second) << endl;
}

C. Max - Min Query

多重集合を扱います.mapを用いて、整数keyがvalue個あるとして考えました.mapの計算量は追加、参照、削除、最大値探索、最小値探索が全てmapの要素数の対数なので、操作1、2、3は全てO(logQ)で抑えられます.ちなみに、mapのkeyの最大値はm.rbegin()->first、最小値はm.begin()->firstで求められます.

)int q;
map<int, int> m;

int main(){
  cin >> q;
  rep(i, 0, q){
    int n, x, c;
    cin >> n;
    
    if(n == 1){
      cin >> x;
      if(m.find(x) == m.end()) m[x] = 1;
      else m[x]++;
    }
    else if(n == 2){
      cin >> x >> c;
      if(m.find(x) != m.end()){
        if(m[x] > c) m[x] -= c;
        else m.erase(x);
      }
    }
    else{
      cout << m.rbegin()->first - m.begin()->first << endl;
    }
  }
}

公式の解説ではmultisetという出来合いの多重集合を用いています.多分こちらを用いた方が良いです.

D - FizzBuzz Sum Hard

集合の問題です.全体の総和から、Aの倍数の総和とBの倍数の総和を引き、Aの倍数かつBの倍数の総和(AとBの最小公倍数の総和)を足せばよいと考えました.以下のようにベン図を書けばわかりやすいです.


ll n, a, b;

ll sigma(ll n){
  return n * (n+1) / 2;
}

int main(){
  cin >> n >> a >> b;

  ll res = 0;
  if(a != b) res = sigma(n) - a * sigma(n/a) - b * sigma(n/b) + lcm(a,b) * sigma(n/lcm(a, b));
  else res = sigma(n) - a * sigma(n/a);
  cout << res << endl;
}

さらに、A==Bの場合は条件が変わるので気を付けましょう.

いいなと思ったら応援しよう!