LoginSignup
3
0

More than 3 years have passed since last update.

はじめてのC++ 【47日目】

Posted at

はじめに

お久しぶりです。テスト期間のため投稿を休んでいました。テストが無事終わったので今日からまた始めようと思います。今日は、テスト期間中に受けたAtcoderで、回答ができなかったC問題とD問題の解説と、ロベールについて書こうと思います。

Atcoder ( 2019/05/25 開催 ) ABC 127

C問題

N 枚の ID カードと M個のゲートがあります。\\i番目のゲートは、L_{i},L_{i}+1,...,R_{i}番目のIDカードを持っていれば通過できます。\\一枚だけですべてのゲートを通過できるのは何枚あるでしょう?

私の回答

C問題(不正解)
#include <iostream>

int main(){
  int N =0, M = 0;
  std::cin >> N >> M;
  int L[M+2] = {0}, R[M+2] = {0};
  int count[100001] ={0};
  int ans = 0;
  for(int i =1; i <= M; i++)
  {
    std::cin >> L[i] >> R[i];
  }

  // for(int m = 1; m <= M; m++)
  // {
  //   for(int i = L[m]; i <= R[m]; i++)
  //   {
  //
  //   }
  // }
  for(int m = 1; m <= M; m++)
  {
    // printf("%d_____________________\n",m );

    for(int i = L[1]; i <= R[1]; i++)
    {
      // printf("L[1]の値は%d\n",L[1]);
      // printf("R[1]の値は%d\n",R[1]);
      //
      // printf("iの番号は%d\n",i );

       for(int j = L[m+1]; j <= R[m+1]; j++)
       {
         // printf("L[m+1]の値は%d\n",L[m+1]);
         //
         // printf("jの番号は%d\n",j );
         if( i == j )
         {

           count[i]++;
           // printf("チャリン\n", count[i]);

         }
       }
    }
  }

  for(int i = L[1]; i <= R[1]; i++)
  {
    if( count[i] == M-1)
      ans++;
  }
  std::cout << ans << std::endl;
}

結果は不正解の WA

Atcoderでは、計算量を考える必要がある。3重for文を使って正確な値を導き出すことができても、LTA (Long time answer) になってしまう。
この問題では、 通過できるIDカードが連続しているという点に注目します。
サンプル問題で例えるとこのようになります。
JPEGイメージ-78270AC21B0E-1.jpeg
この図をみたら、 L の値は、最大値を取り、 R の値は最小値を取ればいいことがわかる。
この方法を使うと for文一つだけで実行することができる。
上記の方法でプログラムを書いてみる。

C問題(正解)
#include <iostream>
#include <algorithm>
int main(){
  //NとMの値を初期化
  int N =0, M = 0;
  std::cin >> N >> M;

  int L = 0;
  int R = 0;
  int L_max = 0;
  int R_min = 100005;

  for(int i =0; i <  M; i++)
  {
    std::cin >> L >> R;
    L_max = std::max(L_max,L);
    R_min = std::min(R_min,R);
  }
  if( R_min >= L_max )
    std::cout << R_min - L_max + 1 << std::endl;
  else
    std::cout << 0 << std::endl;

  return 0;
}

D問題

N枚のカードがあり、i番目のカードには整数 A_{i}が書かれています。\\
あなたは、j=1,2,...,Mについて順に以下の操作を1回ずつ行います。\\
操作: カードを B_{j}枚まで選ぶ(0枚でもよい)。\\
選んだカードに書かれている整数をそれぞれ C_{j}に書き換える。\\
M回の操作終了後に N枚のカードに書かれた整数の合計の最大値を求めてください。

この問題では、 std::pairpriority_queue というものを組み合わせて使うことで解くこともできる。
サンプル問題をみてみる。
JPEGイメージ-79A840D8A7D5-1.jpeg

D問題(正解)
#include <iostream>
#include <vector>
#include <queue>
#include <utility>

int main()
{
  int N = 0;//カードの枚数
  int M = 0;//操作の回数
  int A = 0;
  int B = 0;
  int C = 0;
  long long int ans = 0;
  std::cin >> N >> M;//値を入力

  std::priority_queue< std::pair<int, int> > q;//値の高いもの順

  for(int i = 0; i < N; i++)
  {
    std::cin >> A;
    q.push( std::make_pair(A, 1) );

  }

  for(int i = 0; i < M; i++)
  {
    std::cin >> B >> C;
    q.push( std::make_pair(C, B) );

  }

  for(int i = 0; i < N; i++)
  {
    auto p = q.top();
    std::cout << "p.first = " << p.first<< std::endl;
    q.pop();
    ans += p.first;
    if(p.second > 1)
    {
      p.second--;
      q.push(p);
    }
  }

  std::cout << ans << std::endl;

  return 0;
}

priority_queue では、pairの first の値で大きい順にソートしてくれる。
std::pairstd::vector の組み合わせはなかなか使い勝手が良さそうなので使えるように覚えたほうがいいと思う。

ロベールのC++

静的メンバ変数

静的メンバ変数とは、メンバ変数に static をつけることで生成できる。そして、静的メンバ変数はどれだけクラスを作っても共有することができる。

とりあえず普通の変数とコードを書いてみる。

A.h
#ifndef A_H_
#define A_H_

class A {
public:
  A(int num = 0);
  void Show();

private:
  int m_value;
};

#endif // #ifndef A_H_
A.cpp
#include "A.h"
#include <iostream>
A::A( int num )
{
  m_value = num;
}
void A::Show()
{
  std::cout << m_value << std::endl;
}
main.cpp
#include "A.h"

int main()
{
  A a(100);
  A b(300);

  a.Show();
  b.Show();
}
実行結果
100
300

ここで m_valuestatic をつけて、静的メンバ変数にしようと思う。しかし、コンパイルしてみると、リンクエラーというものが出た。調べてみるとリンクエラーは結構厄介なエラーで場所の特定が難しいらしい。
今回は、 static が原因であった。
static をつけると必ず実体を作る必要がある。しかし、今回は実体定義のほうにstaticをつけ、実体化せずにいたのでエラーが起きた。

A.h
#ifndef A_H_
#define A_H_

class A {
public:
  A(int num = 0);
  void Show();

private:
  static int m_value;
};

#endif // #ifndef A_H_
A.cpp
#include "A.h"
#include <iostream>
int A::m_value;
A::A( int num )
{
  m_value = num;
}
void A::Show()
{
  std::cout << m_value << std::endl;
}

main.cpp
#include "A.h"

int main()
{
  A a(100);
  A b(300);

  a.Show();
  b.Show();
}
実行結果
300
300

これで問題なく動作するようになった!

メンバ変数ではなく、グローバル変数に static をつけても、静的メンバ変数みたいな動作をする。しかし、メンバ変数でなければ、クラスに所属しているという意味合いが薄れてしまい、危険である。静的メンバ変数のほうが、安全で扱いやすい!

終わりに

最近暑い!
おやすみなさい。

3
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0