AtCoder Beginner Contest 140:E - Second Sum

予定があり参加を断念しましたが,やりたくなったので一通り挑戦してみた.

A,Bはなんとか解けた.

Cは問題文の通りにmaxを使って解こうとしたが解説を確認してminを使うことに納得.これ以降問題文に出てくる関数にとらわれないように注意する.

Dは自分の考えがめちゃくちゃで解説を見るとO(N)で解けることを知り納得.

以下Eについてよくわからなかったので記しておく.

問題

{1,2,...,N}の数列が与えられ,長さ2以上の部分列の組み合わせに対して,2番目に大きなものの総和を求める.

自分の解答

int main() {
   int n;
   cin>>n;
   int p[n];
   rep(i,n){
       cin>>p[i];
   }
   ll sum=0;

   rep(i,n-1){
       int second=min(p[i],p[i+1]);
       int first=max(p[i],p[i+1]);
       for(int j=i+1;j<n;j++){
           if(p[j]>first){
               int tmp=first;
               first=p[j];
               second=tmp;
           }else{
               if(p[j]>second&&p[j]<first)second=p[j];                                
           }
           sum+=second;
       }
   }
   cout<<sum;

}

結果

TLE.

今までいくつか見たE問題は手がつかなかったので,TLEを出しただけ進歩ととらえたい.

復習

模範解答(snukeさんのコード)


int main() {
 int n;
 cin >> n;
 vector<int> a(n);
 rep(i,n) cin >> a[i];
 rep(i,n) a[i]--;
 vector<int> idx(n);
 rep(i,n) idx[a[i]] = i;
 set<int> s;
 ll ans = 0;
 for (int x = n-1; x >= 0; --x) {
   int i = idx[x];
   ll c = 0;
   { // calc c
     s.insert(i);
     vector<int> l(2,-1);
     vector<int> r(2,n);
     { // calc l
       auto it = s.find(i);
       rep(j,2) {
         if (it == s.begin()) break;
         --it;
         l[j] = *it;
       }
     }
     { // calc r
       auto it = s.find(i);
       rep(j,2) {
         ++it;
         if (it == s.end()) break;
         r[j] = *it;
       }
     }
     vector<int> ls(2);
     ls[0] = i-l[0]; ls[1] = l[0]-l[1];
     vector<int> rs(2);
     rs[0] = r[0]-i; rs[1] = r[1]-r[0];
     c = (ll)ls[0]*rs[1] + (ll)ls[1]*rs[0];
   }
   ans += c*(x+1);
 }
 cout << ans << endl;
 return 0;
}

解説動画を見たが,set,autoについての知識がなさすぎてちんぷんかんぷんだ.知識がなさすぎるので勉強の必要性を感じた.

そもそも自分の書いたコードを少し変えればいける可能性はないのかなと思った.

わからないけど...




この記事が気に入ったらサポートをしてみませんか?