AtCoder

ABC096 D問題(Five, Five Everywhere)を解く

AtCoder_ABC096_D

AtCoder が提供しているABC(AtCoder Beginner Contest)096 D問題をC++で解いてみました。ABC096は、2018年5月5日21:00に実施されました。

AtCoder の紹介はこちらに、プログラミングの方針はこちらに記事があります。

D問題 Five, Five Everywhere(Difficulty : 1226)

問題の詳細は、リンク先をご覧ください。

ABC096 D問題 Five, Five Everywhere

興味深い整数の問題を紹介します。AtCoder Problems による Difficulty は 1226 でした。

解答案

問題の本質は以下です。

55555以下の素数から55個を選び、その中の任意の5個の和が合成数となるような組み合わせは存在しますか?

55555以下の素数表は簡単に作成できます。その中から5個を選び、その和が合成数になる例として、入力例1の「3、5、7、11、31」があります。しかし、この方法を拡張するのは難しいです。

視点を変えると、この問題は「$5N+1$ となる素数を55個選ぶ」ことで解決できます。$5N+1$ となる素数を5個選ぶと、その和は5の倍数となり、合成数になります。

C++ プログラム例(ABC096D)

エラトステネスの篩で、55555以下の素数表を作成します(8ー31、38行目)。この素数表から、5で割って1余る素数を配列 result に格納します。

  • 55555以下の素数は、5637個ありました。
  • その中で5で割って1余る素数は、1408個ありました。

最後に、配列 result の先頭から $n$ 個の素数を出力します。以下が、C++プログラムです。

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

#define N 55555
bool is_prime_table[N + 1];
vector<int> primes;

void generate_primes(int n)
{
	is_prime_table[0] = false;
	is_prime_table[1] = false;
	for (int i = 2; i <= n; ++i) {
		is_prime_table[i] = true;
	}

	for (int i = 2; i * i <= n; ++i) {
		if (is_prime_table[i]) {
			for (int j = i + i; j <= n; j += i) {
				is_prime_table[j] = false;
			}
		}
	}

	for (int i = 2; i <= n; ++i) {
		if (is_prime_table[i]) {
			primes.push_back(i);
		}
	}

	return;
}

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

	generate_primes(55555);

	vector<int> result;
	for (int i = 0; i < (int)primes.size(); ++i) {
		if (primes[i] % 5 == 1) {
			result.push_back(primes[i]);
		}
	}

	for (int i = 0; i < n; ++i) {
		cout << result[i] << " \n"[i == n - 1];
	}

	return 0;
}

AC(Accepted=正しいプログラム)と判定されました。

最後に

過去のABCの問題ですが、学びが多かったため記事にしました。高校数学の整数問題でも、「合同式を用いる」と上手く解ける場合があったことを思い出しました。

引き続き ABC の問題を紹介していきます。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA