質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

1355閲覧

競技プログラミングの解答がTLEになってしまう

shugo

総合スコア29

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2020/07/06 14:23

編集2020/07/06 14:44

前提・実現したいこと

ご覧いただきありがとうございます。
実行時間制限で解けなかった問題でどうしても解法が気になってしまったので、質問さしていただきます。

・10^18以下の数字l,r(l<r)が与えられており
・m個のばらばらの数字n1,n2...nmが与えられている
(n<10^8である)

この時l~rの数字の中で、
n1の倍数でもなく
n2の倍数でもなく
...
nmの倍数でもない
数字は何個あるでしょうか?

という問題です。

以下は自分が書いたコードです。

C++

1#include <bits/stdc++.h> 2using namespace std; 3 4int main() { 5 long long l,r; 6 7 cin >> l >> r; 8 long long numbers_number=r-l+1; 9 vector<bool> numbers(numbers_number); 10 fill(numbers.begin(), numbers.end(),true); 11 12 int m; 13 cin >> m; 14 vector<int> n(m); 15 for(int i=0; i<m ;i++){ 16 cin >> n.at(i); 17 } 18 19 for(int i=0; i<m ;i++){ 20 int N = n.at(i); 21 int j; 22 if(l%N){ 23 j=l/N+1; 24 } else 25 { 26 j=l/N; 27 } 28 while (true) 29 { 30 numbers.at(j*N-l)=false; 31 j++; 32 if(N*j>r)break; 33 } 34 } 35 36 long long result=0; 37 for(int i=0; i<numbers_number; i++){ 38 if(numbers.at(i)==true){ 39 result++; 40 } 41 } 42 43 cout << result; 44}

発生している問題・エラーメッセージ

この解法ですと、
・l~rの幅が広い場合
→bad_allocとなり配列が宣言できない
要素数が少ない場合だと大丈夫ですが、
要素数1000000000000ぐらいから作成できなくなりました。
・複雑な場合だと制限時間で答えられない

のでTLEになってしまいました。

どのようにすれば、制限時間内に解けるのでしょうか?
よろしければご教授頂きたいです。


補足
実行時間制限は2秒でしたが、この解法ではtimeout(7秒以上)でした

すみません制約が一つ抜けていました。
m個は10以下です。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SHOMI

2020/07/06 14:50

問題文へのリンクを貼っていただけますか? >要素数1000000000000ぐらいから作成できなくなりました。 vector<bool>だけでメモリを116.4GBも要求していますよ…
guest

回答2

0

ベストアンサー

包除原理を使うのがベターでしょうか。
l~rの範囲で、「いずれかの倍数である数」の個数を数え、全体から引きます。

投稿2020/07/06 15:28

swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shugo

2020/07/06 15:34

回答ありがとうございました。 確かに倍数を考えて、全体の数より倍数の数を減らすやり方で解けそうでした。 Nが1の場合は、例外処理を加えれば大丈夫でした。 他の方もありがとうございました。
shugo

2020/07/06 16:01

質問文を見直すと説明が不足していました。 すみません、問題文の中に n1,n2...の中で一つが1で与えられた場合は、 例外的に全ての数を倍数として数えるとありました。 その場合の例外処理の話でした。
swordone

2020/07/06 16:06

別に例外にする必要はないのでは? 1があった時点で答え0で確定して終了ならともかく。
shugo

2020/07/06 16:15

重複の確認の為に今まで出てきた倍数を記憶したのですが、 1の場合のみ 10^18個の領域が必要になるので、例外処理が必要でした。 2の以上は、領域が確保出来たので大丈夫でした。
guest

0

回答ではなく完全に独り言ですが…
10^8は領域確保できて、10^8回ループも時間内に回せますよね。
逆から考えるといけそうかな、と。
l~r(r-l+1)個の数からすべての条件を満たさないものを引いていく感じ?

投稿2020/07/06 14:57

編集2020/07/06 15:20
can110

総合スコア38256

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問