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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

PyPy

PyPy(パイパイ)は、RPythonで記述されたPythonの実装のひとつです。CPythonとの互換性に重点を置いて開発されており、コードを必要に応じて機械語にコンパイルする「JITコンパイル機能」を備えています。

Q&A

解決済

1回答

716閲覧

AtCoder ABC158 高速化の方法と計算量の見積もり

shake9

総合スコア19

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

PyPy

PyPy(パイパイ)は、RPythonで記述されたPythonの実装のひとつです。CPythonとの互換性に重点を置いて開発されており、コードを必要に応じて機械語にコンパイルする「JITコンパイル機能」を備えています。

0グッド

1クリップ

投稿2020/06/13 15:27

解決したいこと

以下のコードを提出しましたが、TLEとなってしまいました。
(44ファイル中12ファイルTLE)
計算量を改善するにはどうすべきだったのでしょうか。

問題は以下の通りです。
https://atcoder.jp/contests/abc158/tasks/abc158_e

疑問点と知りたいこと

自分の予想では、Numpyを使えば繰り返し内部の計算量はO(1)程度だと予測し、全体の計算量はO(N)程度であり、問題ないと考えていました。
しかし、実際にはTLEとなってしまい、O(10^9)以上の計算量が必要となっていたと考えられます。
このコードの計算量はどれほどだったのでしょうか。また、それはどのようにして予測できたのでしょうか。

該当のソースコード

python

1s = list(map(int, input().strip())) 2 3dp = np.zeros(p,dtype = int) #動的計画法 4 5count = 0 6d = 1 7for i in range(n): #1の位から順に数を追加していく 8 ne_ar = np.zeros(p,dtype = int) 9 if(p == 2 or p == 5): #10と互いに素ではない場合 10 ne = int(s[n-i-1]) % p 11 if(ne == 0): 12 dp[0] += 1 13 count += dp[0] # 14 else: 15 ne = (int(s[n-i-1]) * d) % p #10とは互いに素なので、sと同じ位で考えて良い 16 ne_ar[ne:] += dp[:(p-ne)] #新しく追加する数の余りをずらす 17 ne_ar[:ne] += dp[(p-ne):] 18 ne_ar[ne] += 1 #新しい数のみの時 19 dp = ne_ar 20 d *= 10 21 d %= p 22 count += ne_ar[0] #neを一番上の位とする部分集合の数を足す 23 24print(count) 25

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

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

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

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

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

guest

回答1

0

ベストアンサー

ne_ar[ne:] += dp[:(p-ne)] #新しく追加する数の余りをずらす ne_ar[:ne] += dp[(p-ne):] ne_ar[ne] += 1 #新しい数のみの時

配列をコピーしているので、ここで時間計算量 O(P) 掛かりそうな気がします。
numpyは詳しくないので実は参照が使われて計算量O(1)になっていたらごめんなさい

投稿2020/06/13 16:22

maai

総合スコア463

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

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

shake9

2020/06/13 17:03

自分もNumpyには詳しくないので分からないです。 ただ、以下の例ではNumpyを使うことで単純な加算を行う場合に対して大幅な時間短縮ができました。 そのため、O(P)よりは小さいのでは、と思っています。(O(1)なのかどうかは分かりません) https://teratail.com/questions/266785
maai

2020/06/13 17:53

しまった、+= はベクトル加算なのでコピーでは無いですね… 266785 は、 Pythonのリストをnumpy arrayに置き換えることで数十倍高速化する感じなので、入力に対する計算量オーダが改善している訳では無いです。 N要素の単純なベクトル加算は、どう頑張ってもNに比例する時間が掛かってしまいます。 もう1箇所気づきました。 for i in range(n): #1の位から順に数を追加していく ne_ar = np.zeros(p,dtype = int) np.zeros(p,dtype = int)で0埋めされた長さpの配列を確保しています。 これの時間計算量がO(P)、この行が呼ばれる回数がN回なので、時間計算量はO(NP)以上となり、制限時間に間に合わない気がします。
shake9

2020/06/14 09:47

ありがとうございます。 そうなのですね、納得できました。 この方法ではどう頑張っても長さPの配列をN回用意する必要がありそうなので、別の方法を検討することにします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問