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

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

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

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

Q&A

解決済

1回答

1628閲覧

AtCoder ABC169 F問題 実行速度向上の方法 (動的計画法)

shake9

総合スコア19

Python

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

0グッド

0クリップ

投稿2020/06/01 17:06

編集2020/06/02 06:00

前提・実現したいこと

AtCoder ABC169 F問題に関する質問です。
下記のプログラムを作成しましたが、TLEとなってしまいました。
どこを修正すれば良いかをお聞きしたいです。
27testfile中7WAとなっているようで、問題文中のtestfileに関しては正常に作動しました。

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

TLE 時間超過

該当のソースコード

Python

1n,s = map(int, input().split()) 2a = list(map(int, input().split())) 3 4MOD = 998244353 5 6dp = [[0]*(s+1) for i in range(n+1)] #動的計画法を用いる 参照渡しによるバグを防ぐためリスト内包表記 7dp[0][0] = 1 8 9for i in range(n): 10 for ss in range(s+1): 11 if(ss >= a[i]): 12 dp[i+1][ss] = (dp[i][ss]*2 + dp[i][ss-a[i]])%MOD #非常に大きな数になると考えられるため先にMOD計算を行う 13 else: 14 dp[i+1][ss] = dp[i][ss]*2 % MOD 15 16print(dp[n][s])

試したこと

12行目について
dp[i+1][ss] = (dp[i][ss]*2 + dp[i][ss-a[i]])%MOD

dp[i+1][ss] = (dp[i][ss]*2%MOD + dp[i][ss-a[i]])%MOD
としましたが、逆にTLEとなるケースが2つ増えてしまいました。

##以降はyudedaka67様のご回答を参考にさせていただき試した修正

二重配列の廃止

Python

1... 2dp = [[0]*(s+1) for i in range(n+1)] #動的計画法を用いる 参照渡しによるバグを防ぐためリスト内包表記 34dp = [0]*(s+1) 5 6ループ部分を以下に変更 7for i in range(n): 8 for ss in range(s,-1,-1): 9 if(ss >= a[i]): 10 dp[ss] = (dp[ss]*2 + dp[ss-a[i]])%MOD #非常に大きな数になると考えられるため先にMOD計算を行う 11 else: 12 dp[ss] = dp[ss]*2 % MOD

→TLEとなるファイルが7から5に

###Numpyの導入
######numpy.zerosによるベクトル生成
これだけだと逆にimportする分TLEが増えてしまいました
######numpyのベクトルの整数倍を用いる

Python

1...for iの中身を修正 2ddp = dp * 2 3 for ss in range(s,-1,-1): 4 if(ss >= a[i]): 5 ddp[ss] += dp[ss-a[i]]%MOD #非常に大きな数になると考えられるため先にMOD計算を行う 6 dp = ddp % MOD

これでもTLEとなるようでした

######numpyのベクトルの加算を用いる

Python

1...for iの中身を修正 2ddp = dp * 2 % MOD 3ddp[a[i]:] += dp[:-a[i]] #非常に大きな数になると考えられるため先にMOD計算を行う 4dp = ddp % MOD

こうすることで1/S倍ほどになり、ACできました。

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

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

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

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

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

set0gut1

2020/06/01 21:31

処理系を python から pypy に変えるだけで定数倍速くなって AC することあるのでちょっと試してみてください。
shake9

2020/06/02 05:30

PyPyでも提出できるのですね、ありがとうございます、ACできました! まさか実行時間が1/10になるとは…勉強になりました。
set0gut1

2020/06/02 05:31

回答してる方の「Python自体の遅さの問題」ってのが本質情報でしたね
guest

回答1

0

ベストアンサー

残念ながらアルゴリズム的な問題ではなくPython自体の遅さの問題のようです。
numpyのような高速なライブラリを使うか、地道に定数倍の改善を続けるしかありません。
とりあえず二重配列をやめれば大きく改善するはずです(ssを逆順に更新していけば二重配列は不要)。

投稿2020/06/01 18:12

yudedako67

総合スコア2047

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

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

shake9

2020/06/02 06:00

ありがとうございます、細部の見直しを繰り返した結果無事ACできました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問