0
0

【c++】ABC368 A-C問題解説【ACコード付き】

Posted at

AtCoder Beginner Contest 368

A,B,Cの3完。

レートは876→859の-17となり2週連続レートダウン。

5回ほど前のABCで過去最高の898を記録してから、850から900の間を行ったり来たりしている。

やはり何も対策しなかったらレートが落ちるのは当然だし、一度停滞期が来たからと言って諦めたくない。

今年中の青色へは毎回+50を記録しないといけないので相当気合を入れないといけないが、ちゃんと精進していけばレートが上がっていく余地はまだまだ感じるので、言い訳せずに時間を確保して精進するのみ。

A - Cut

昇順に並んでいる $N$ 枚からなるカードの山札を、山の下から $K$ 枚を取り出して、その順番を保ったまま上に重ねた時、上からどのような番号で並んだ状態になるか出力せよ、という問題。

まず $N - K$番から$N$番までのカードを出力し、その後$1$番から$N - K - 1$番までのカードを出力すればよい。

ll N,K;
ll A[1000009];

int main()
{
	cin >> N >> K;
	for (int i = 0; i < N; i++) cin >> A[i];
	for (int i = N - K ; i < N; i++)
	{
		if (i != N - K) cout << " ";
		cout << A[i];
	}
	for (int i = 0; i < N - K; i++) cout << " " << A[i];
	cout << endl;
	return 0;
}

B - Decrease 2 max elements

長さ$N$の正整数列が与えられるので、降順にして前二つの要素を1引く操作を繰り返して、要素が0でないものが1つ以下になるまでの操作回数を求めよ。

ひたすら該当の操作を繰り返す素直な実装にし、降順に並び替えた時の $A[1]$ 、つまり2つ目に大きな要素が0になったら終了するようにする。

ll N;
vector<ll> A(1000009);

int main()
{
	cin >> N;
	for (int i = 0; i < N; i++) cin >> A[i];
	ll count = 0;
	while (1)
	{
		sort(A.begin(), A.begin() + N);
		reverse(A.begin(), A.begin() + N);
		if (A[1] == 0) break;
		A[0]--;
		A[1]--;
		count++;
	}
	cout << count << endl;
	return 0;
}

C - Triple Attack

$N$体の敵がいて、それぞれの体力が $A_i$ である。
0でカウントを始め、カウントが3の倍数の時には3ダメージを与え、そうでない時には1ダメージを与える。前の敵から体力が0以下になるように攻撃をする時、最終的なカウントはいくつになるか、という問題。

最初はひたすら該当の操作を繰り返す実装にしていたが、TLEしたので3回の攻撃を1セットと認識し、3回の攻撃の総和である5で何回攻撃できるかを計算するように計算量を改善した。

ll N;
ll A[1000009];

int main()
{
	cin >> N;
	vector<pair<ll, ll>> enemy(N);
	for (int i = 0; i < N; i++) cin >> A[i];
	ll T = 0;
	ll num = 0;
	while (num < N)
	{
		ll tmp = A[num] / 5;
		A[num] = A[num] % 5;
		T += tmp * 3;
		while (A[num] > 0)
		{
			T++;
			if (T % 3 == 0) A[num] -= 3;
			else A[num]--;
		}
		num++;
	}
	cout << T << endl;
	return 0;
	
}

D - Minimum Steiner Tree

公式解説のpythonを見てcppで実装したコード。

考え方をわかりやすく説明すると、Union-Findのような木構造を思い浮かべたときに、葉(木構造の末端、それ以上下位の階層の分岐が存在しない)が条件を満たす頂点でなければ削除してさらに上位階層(親ノード)をチェックする、条件を満たす頂点だった場合はそれ以上上の階層は残す、という操作を繰り返す。それらを下記のプログラムでは幅優先探索で実装している。

int main() {
    int N, K;
    cin >> N >> K;

    vector<set<int>> edge(N);

    for (int i = 0; i < N - 1; ++i) {
        int a, b;
        cin >> a >> b;
        a--; // 0-indexed に変換
        b--; // 0-indexed に変換
        edge[a].insert(b);
        edge[b].insert(a);
    }

    set<int> V;
    for (int i = 0; i < K; ++i) {
        int v;
        cin >> v;
        V.insert(v - 1); // 0-indexed に変換
    }

    vector<int> deg(N);
    for (int i = 0; i < N; ++i) {
        deg[i] = edge[i].size();
    }

    queue<int> q;
    for (int i = 0; i < N; ++i) {
        if (deg[i] == 1) {
            q.push(i);
        }
    }

    int ans = N;
    while (!q.empty()) {
        int v = q.front();
        q.pop();
        if (V.find(v) != V.end()) continue;

        int vv = *edge[v].begin();
        edge[vv].erase(v);
        ans--;

        if (edge[vv].size() == 1) {
            q.push(vv);
        }
    }

    cout << ans << endl;

    return 0;
}

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