akatana309
@akatana309 (Oneco)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

[AtCoder]TLEを解消出来ません[解消済み]

Q&A

Closed

質問

AtCoderでどうしてもTLEになります。

解説を読み、考え方は間違っていないと思いますが、コピペはいろいろよろしくないので、どうにか自身でやりたかったのですが自分の実力じゃだめでした。

どこがネックになっているのかを教えていただきたいです。

問題URL「ABC353C問題、Sigma Problem」
以下がコードです。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
using ll = long long;
int main(void)
{
  int n;
  cin >> n;
  vector<int> a(n);
  for(int i = 0; i < n; i++) cin >> a[i];
  sort(a.begin(), a.end());
  
  int r = n-1, l = r-1;
  ll count = 0; 
  while(r > 0)
  {
    while(a[r]+a[l] >= 100000000 && l >= 0) l--;
    count += r-l-1;
    if(r == l+1) break;
    r--;
    l = r-1;
  }
  
  ll sum = 0;
  for(int i = 0; i < n; i++) sum += ll(a[i]) * (n-1);
  sum -= ll(count) * 100000000;
  
  cout << sum << endl;
  return 0;
}

備考

私の考えでは二重ループがやはり良くないのではと考えていますが、解説でも二重ループは使っていますし、それ以外の案が思い浮かびません。

1:私のコードと解説のコードでは何が違うのか
2:そもそも二重ループを使わない方法はないのか

この二点についてももしお答えいただけるのであれば幸いです。

また、今回初めてQiitaで質問を作成したのですが、質問のしかたに問題があればご指摘いただけると今後の役に立ちますのでよろしくお願いいたします。

0

1Answer

私の考えでは二重ループがやはり良くないのではと考えていますが、解説でも二重ループは使っていますし、それ以外の案が思い浮かびません。

同じ二重ループであっても、実行時に何回ループするのか(計算量)が問題です。

あるテストケースで試してみましたが、解説のコードでは、
外側ループ回数ー内側ループ回数が、300000 - 150296 でしたが、
上のコードだと、
外側ループ回数ー内側ループ回数が、150297 - 22549528741 でした。
(答え自体は合っています)
$10^{11}$ではTLEしますから、計算量を減らす工夫が必要ですね。

解説や公式解説動画を見て、ご自身で調べてみてください。

2Like

Comments

  1. @akatana309

    Questioner

    回答ありがとうございました!
    解説を一通り見て計算量について意識しながら改めてコードを見直しましたが、私がやろうとしていたことは尺取り法のみでO(1/2N(N-1))の計算量だと理解しました。
    Nが大きいこの問題では確かにTLEになるのも当然でした。
    結果としては尺取り法と二分探索の組み合わせを行うことで解消することができました!(計算量はわかりません・・・)
    改めて回答していただきありがとうございました!
    別の問題でQiitaを使うことがあると思いますのでご縁がありましたらその時はまたよろしくお願いします!

Your answer might help someone💌