chacoderのブログ

競技プログラミングそのほか

A - 勇者ビ太郎 (Bitaro the Brave) JOI 2018/2019 本選 過去問

考察

条件を充たすものをいちいち数えると計算量オーバーしそうなので、あらかじめ累積和的に数を数えておくことにしました。

制約の iがk より小さい と jがlより小さい があるので難しいですが,大きい方から順に累積していくことで解決できそうです。

WAしたコード

書き上げてサンプルを通して提出しましたがWAに。

#include <bits/stdc++.h>
using namespace std;

int on[3010][3010];
int in[3010][3010];

int main(){
  int H,W;
  cin>>H>>W;
  string S;
  char item[3010][3010];
  for(int i=0;i<H;i++){
    cin>>S;
    for(int j=0;j<W;j++){
      item[i][j]=S.at(j);
    }
  }
  
  //on[i][j]にi行のオーブの累積数を入力
  for(int i=0;i<H;i++){
    int temp=0;
    for(int j=W-1;j>=0;j--){
      if(item[i][j]=='O'){
        temp++;
        on[i][j]=temp;
      }
      else{
        if(j==W-1){
          on[i][j]=0;
        }
        else{
          on[i][j]=on[i][j+1];
        }
      }
    }
  }
  
  //in[i][j]にj列のインゴットの累積数を入力
  for(int j=0;j<W;j++){
    int temp=0;
    for(int i=H-1;i>=0;i--){
      if(item[i][j]=='I'){
        temp++;
        in[i][j]=temp;
      }
      else{
        if(i==H-1){
          in[i][j]=0;
        }
        else{
          in[i][j]=in[i+1][j];
        }
      }
    }
  }  
  int ans=0;
  for(int i=0;i<H;i++){
    for(int j=0;j<W;j++){
      if(item[i][j]=='J'){
        ans+=in[i][j]*on[i][j];
        //cout<<i<<" "<<j<<" "<<in[i][j]<<"*"<<on[i][j]<<endl;
      }
    }
  }
  /*for(int i=0;i<H;i++){
    for(int j=0;j<W;j++){
      cout<<in[i][j]<<" "<<on[i][j]<<" ";
    }
    cout<<endl;
  }*/
  
  cout<<ans<<endl;
  return 0;
}

AC

予想はどこかでHとWを間違えているか、オーバーフローです。

3000*3000の配列で900万、積の個数で加算されるのでオーバーフローの可能性が高いと判断しました。

#define int long long して無事にACしました。