0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ABC045 ARC061 の問題を解いてみました

Last updated at Posted at 2023-12-29

A問題

台形の面積を求める問題です。
上底は$a$ ,下底は$b$ ,高さは$h$ として与えられます。
台形の面積の公式は、$(上底+下底) \times 高さ \div 2$ であり、それをプログラムします。

#include <bits/stdc++.h>
using namespace std;
//Created by Karaju

int main() {
	int a, b, h;
	cin >> a >> b >> h;
	cout << (a + b) * h / 2 << endl;
}

B問題

Aさん,Bさん,Cさんが a,b,cと書かれたカードを持っている。(文字列で与えられる)
Aさんのターンから始まり、自分のターンならば先頭のカードを捨てて、
捨てたカードにかかれていた文字の人のターンになる。

というゲームをするので、誰が勝つかを出力してくださいという問題です。

この問題で注意すべき点は、カードが0枚になったときに勝利ではなく、
カードが0枚の状態でターンになれば勝利だという点です。
それを踏まえて繰り返しでこのゲームをシュミレーションして、答えを求めます。

#include <bits/stdc++.h>
using namespace std;
//Created by karaju

int main() {
	string a, b, c;
	int aa = 0, bb = 0, cc = 0;
	//aaはaさんが捨てたカードの枚数。 bb, ccも同様。
	cin >> a >> b >> c;
	char turn = 'a'; //誰のターンか
	while (true) {
		if (turn == 'a') {
			if (aa == a.size()) {  // a さんが 0枚なら
				cout << "A" << endl;
				break;
			}
			turn = a[aa];
			aa++;
		}
		else if (turn == 'b') {
			if (bb == b.size()) { // b さんが 0 枚なら
				cout << "B" << endl;
				break;
			}
			turn = b[bb];
			bb++;
		}
		else {
			if (cc == c.size()) { // c さんが 0 枚なら
				cout << "C" << endl;
				break;
			}
			turn = c[cc];
			cc++;
		}
	}
	
	return 0;
}

C問題

1~9の数字のみで構成される文字列sが与えられます。
文字の間にいくつか + を入れられるので、+ を入れることによってできる文字列を数式とみなして、作成できる全ての数式の和を出力する問題です。
なお、制約は $1\leqq |s|\leqq 10$ です。

この問題は、+を入れるか入れないかを 0と1で表すことによって、
bit式全探索で解くことができます。
計算量も、$O(2^N)$になるが、sの長さの制約が小さいため、TLEを回避できます。

(ch - '0' で文字を数値に変換できます。)

bit全探索について詳しくは

#include <bits/stdc++.h>
using namespace std;
//Created by karaju

int main() {
	string s;
	cin >> s;
	long long ans = 0, b = 0, c = 0;
	for (int i = 0; i < (1<<(s.length()-1)); i++) {
		b = 0; //式の値を記録する
		c = s[0] - '0'; //項の数字を記録する
		//'0'で引くことによって、s[0]をcharからintにする
		for (int j = 0; j < s.length() - 1; j++) {
			if (i & (1 << j)) { //もし+を入れるなら
				b += c;
				c = 0;
			}
			c = c * 10 + s[j + 1] - '0';
            // それぞれの項の数字を計算する
		}
		b += c; 
		ans += b;
	}
	cout << ans << endl;
	
	return 0;
}

D問題

左から$x$列目、上から$y$行目のマスを$(x,y)$と表します。
そして、そのマスを中心とした$3×3$のマスに含まれる黒いマスの数を$b(x,y)$と表します。$(1 < x < W, 1 < y < H,$端のマスを中心とした四角は存在しないため$)$

それぞれのマスの$b(x,y)$を表すことは、配列のサイズの関係でできません。
ここで考察をしてみます。

あるマスを黒く塗りつぶしたとき、その操作が影響するのは周囲9マスの$b(x,y)$です。
$0≤N≤min(10^5,H×W)$ という制約より、操作が影響するマスの数は最大でも$9 \times 10^5$個になるということがわかります。
そのため、操作が影響するマスだけ$b(x,y)$の値を保存しておくことはできます。C++のmapなどを使用して保存しましょう。
操作が影響しなかったマスは、もちろん $b(x,y) = 0$ です。


次に、黒いマスが$j$個ある四角形の数を数える方法を考えます。
黒いマスが$j$個ある四角形の数を記録する配列$Ans_i \ (0 \leq i \leq 9)$ を用意します。
すべてのマスが白い最初の状態では、$b(x, y) = 0$ となる$x,y$の組み合わせは、$(H - 2) \times (W - 2)$ で求められます。
つまり、$Ans_0 = (H - 2) \times (W - 2)$ となります。(端を中心とする四角は存在しないため)

そして、白いマスが黒いマスになるとき、周囲9マスの$b(x,y)$の値を$+1$して、その分配列$Ans$の値を変更することで答えを求められます。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
//Created by karaju.
const int dy[] = {-1, -1, -1, 0, 1, 1, 1, 0, 0};
const int dx[] = {-1, 0, 1, 1, 1, 0, -1, -1, 0};

signed main(){
  ll h, w, n;
  cin >> h >> w >> n;
  
  vector<ll> ans(10, 0);
  //黒いマスが周囲にいくつあるかを保存する配列
  ans[0] = (h - 2LL) * (w - 2LL);
  
  map<pair<int,int>,int> black;
  
  for(int i = 0; i < n; i++){
    int a, b;
    cin >> a >> b;
    
    for(int j = 0; j < 9; j++){ // 3 * 3 のマスについて
      int y = a + dy[j], x = b + dx[j];
      
      if(y >= 2 && x >= 2 && y <= h - 1 && x <= w - 1){
        //解説でいう b(x, y) 
        ans[black[{x, y}]]--;
        black[{x, y}]++;
        ans[black[{x, y}]]++;
      }
    }
  }
  
  for(auto p : ans){
    cout << p << endl;
  }
}
0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?