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?

Atcoder解いてみた AtCoder Beginner Contest D - Enough Array

0
Posted at

AtCoder Beginner Contest D - Enough Array

問題はこちら

回答

尺取り法の練習

K未満の区間を数えて全体から引く
以下、間違ったコード
常に、半壊区間[l,r) l=Kとなる時も、lowerKに1が足されてしまう

#include <iostream>
#include <string>
#include <map>
#include <unordered_map>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <limits.h>
#include <bitset>
#include <list>
#include <set>
#include <numeric>
#include <tuple>

int N;
long long K;
std::vector<long long> A;

int main()
{
	std::cin.tie(0);
	std::ios::sync_with_stdio(false);

	std::cin >> N >> K;
	
	for (int i = 0; i < N; i++) {
		long long a;
		std::cin >> a;
		A.push_back(a);
	}


	int right = 1;
	
	long long lowerK = 0;
	long long sum = A[0];
	for (int left = 0; left < N; left++) {
		// [l,r)を保つ
		if (right == left) {
			right++;
			sum = A[left];
		}


		while (right < N && sum + A[right] < K) {
			sum += A[right];
			right++;
		}

		// sum + A[right]がK以上になってしまったらlowerKは0にしたいが、1が加算されてしまう
		lowerK += (right - left);

		sum -= A[left];
	}

	long long n = static_cast<long long>(N);
	long long ans = (n * (n - 1) / 2 + n) - lowerK;

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

	return 0;
}

K以下の区間の数を求めるときは、以下のタイプの書き方がいい

#include <iostream>
#include <string>
#include <map>
#include <unordered_map>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <limits.h>
#include <bitset>
#include <list>
#include <set>
#include <numeric>
#include <tuple>

int N;
long long K;
std::vector<long long> A;

int main()
{
	std::cin.tie(0);
	std::ios::sync_with_stdio(false);

	std::cin >> N >> K;

	for (int i = 0; i < N; i++) {
		long long a;
		std::cin >> a;
		A.push_back(a);
	}


	int right = 0;

	long long lowerK = 0;
	long long sum = 0;
	for (int left = 0; left < N; left++) {

		while (right < N && sum + A[right] < K) {
			sum += A[right];
			right++;
		}

		lowerK += (right - left);

		if (left == right) {
			right++;
		}
		else {
			sum -= A[left];
		}
	}

	long long n = static_cast<long long>(N);
	long long ans = (n * (n - 1) / 2 + n) - lowerK;

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

	return 0;
}

「K未満の区間を数えて全体から引く」よりも、「和が K 以上になる最小の right を探して直接数え上げる」 しゃくとり法にする方が条件分岐がシンプルになり、バグを防ぎやすくなる。

#include <iostream>
#include <vector>

int main() {
    std::cin.tie(0);
    std::ios::sync_with_stdio(false);

    int N;
    long long K;
    std::cin >> N >> K;

    std::vector<long long> A(N);
    for (int i = 0; i < N; i++) {
        std::cin >> A[i];
    }

    long long ans = 0;
    long long sum = 0;
    int right = 0;

    for (int left = 0; left < N; left++) {
        // sum が K 以上になるまで right を進める
        while (right < N && sum < K) {
            sum += A[right];
            right++;
        }

        // sum が K 以上になれば、[left, right) 以降の right~N までの区間はすべて K 以上
        if (sum >= K) {
            ans += (N - right + 1);
        } else {
            // right == N に達しても sum < K の場合はこれ以上 left を進めても K 以上になれないため終了
            break;
        }

        // left を進める準備
        sum -= A[left];
    }

    std::cout << ans << std::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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?