Problem:
勇者ビ太郎(Bitaro the Brave)
勇者のビ太郎は，魔王と対峙することとなった．
ビ太郎は，縦$H$ 行，横$W$ 列のマス目上に宝石(Jewel)，オーブ(Orb)，金塊(Ingot) を配置し，魔法を発動することによって魔王に攻撃をしようとしている．以下，マス目のうち上から$i$ 行目($1 \leq i \leq H$)，左から$j$ 列目($1 \leq j \leq W$) のマスを，マス($i, j$) と表す．
ビ太郎は今，それぞれのマスにこれら3 種類のうち1 個を配置した．今から魔法を発動しようとしているが，この魔法の威力はマス目上の宝石，オーブ，金塊の配置によって決まる．具体的には，次の条件を満たす整数($i, j, k, l$) ($1 \leq i < k \leq H, 1 \leq j < l \leq W$) の組の個数が，魔法の威力である．
条件：マス($i, j$) には宝石が，マス($i, l$) にはオーブが，マス($k, j$) には金塊が置かれている．
ビ太郎は，この魔法の威力が気になっている．
マス目上の宝石，オーブ，金塊の配置が与えられたとき，ビ太郎が発動する魔法の威力を求めるプログラムを作成せよ．
入力
入力は以下の形式で標準入力から与えられる．
$H$ $W$
$S_1$
:
$S_H$
$S_i$ ($1 \leq i \leq H$) は長さ$W$ の文字列で，その$j$ 文字目($1 \leq j \leq W$) がJ のときはマス($i, j$) に宝石が，O の ときはマス($i, j$) にオーブが，I のときはマス($i, j$) に金塊が置かれていることを表す．
出力
標準出力に，魔法の威力を表す整数を1 行で出力せよ．
制約
$2 \leq H \leq 3 000$．
$2 \leq W \leq 3 000$．
$S_i$ は長さ$W$ の文字列である($1 \leq i \leq H$)．
$S_i$ の各文字はJ，O，I のいずれかである($1 \leq i \leq H$)．
入出力例
入力例1
3 4
JOIJ
JIOO
IIII
出力例1
3
この入力例では，($i, j, k, l$) = (1, 1, 3, 2), (2, 1, 3, 3), (2, 1, 3, 4) の3 個の組が条件を満たすので，答えは3 である．
入力例2
4 4
JJOO
JJOO
IIJO
IIIJ
出力例2
17
情報オリンピック日本委員会作 『第18 回日本情報オリンピック(JOI 2018/2019) 本選』

Submitted solutions:

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

class Solution {
public:
    int h, w;
    vector<vector<pair<int, int>>> data;// O I
    set<pair<int, int>> st;
    Solution() {
        cin >> h >> w;
        data.assign(h + 1, vector<pair<int, int>>(w + 1, {0, 0}));
    }
    ~Solution() {}

    void solution() {
        for (int i = 0; i < h; ++i) {
            string str;
            cin >> str;

            for (int j = 0; j < w; ++j) {
                if (str[j] == 'J') {
                    st.insert({i, j});

                    if (i == 0 && j == 0) {
                        continue;
                    } else if (i == 0) {
                        data[i][j] = {data[i][j - 1].first, 0};
                    } else if (j == 0) {
                        data[i][j] = {0, data[i - 1][j].second};
                    } else {
                        data[i][j] = {data[i][j - 1].first, data[i - 1][j].second};
                    }

                } else if (str[j] == 'O') {
                    auto [itO, itI] = data[i][w];
                    data[i][w] = {itO + 1, 0};

                    if (i == 0) {
                        data[i][j] = {itO + 1, 0};
                    } else {
                        data[i][j] = {itO + 1, data[i - 1][j].second};
                    }

                } else if (str[j] == 'I') {
                    auto [itO, itI] = data[h][j];
                    data[h][j] = {0, itI + 1};

                    if (j == 0) {
                        data[i][j] = {0, itI + 1};

                    } else {
                        data[i][j] = {data[i][j - 1].first, itI + 1};
                    }
                }
            }
        }
        long long count(0l);
        for (auto [i, j] : st) {
            int opa = data[i][w].first - data[i][j].first;
            int ingot = data[h][j].second - data[i][j].second;

            count += (long long) opa * ingot;
        }
        cout << count << '\n';
    }
} ;
int main() {
    Solution solute;
    solute.solution();
    return 0;
}
accuracy: 1
time_ms: 760
memory_kb: 242572
final_rank: 14

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

class Solution {
public:
    int h, w;
    vector<vector<pair<int, int>>> data;// O I
    set<pair<int, int>> st;
    Solution() {
        cin >> h >> w;
        data.assign(h + 1, vector<pair<int, int>>(w + 1, {0, 0}));
    }
    ~Solution() {}

    void solution() {
        for (int i = 0; i < h; ++i) {
            string str;
            cin >> str;

            for (int j = 0; j < w; ++j) {
                if (str[j] == 'J') {
                    st.insert({i, j});

                    if (i == 0 && j == 0) {
                        continue;
                    } else if (i == 0) {
                        data[i][j] = {data[i][j - 1].first, 0};
                    } else if (j == 0) {
                        data[i][j] = {0, data[i - 1][j].second};
                    } else {
                        data[i][j] = {data[i][j - 1].first, data[i - 1][j].second};
                    }

                } else if (str[j] == 'O') {
                    auto [itO, itI] = data[i][w];
                    data[i][w] = {itO + 1, 0};

                    if (i == 0) {
                        data[i][j] = {itO + 1, 0};
                    } else {
                        data[i][j] = {itO + 1, data[i - 1][j].second};
                    }

                } else if (str[j] == 'I') {
                    auto [itO, itI] = data[h][j];
                    data[h][j] = {0, itI + 1};

                    if (j == 0) {
                        data[i][j] = {0, itI + 1};

                    } else {
                        data[i][j] = {data[i][j - 1].first, itI + 1};
                    }
                }
            }
        }
        int count(0);
        for (auto [i, j] : st) {
            int opa = data[i][w].first - data[i][j].first;
            int ingot = data[h][j].second - data[i][j].second;

            count += opa * ingot;
        }
        cout << count << '\n';
    }
} ;
int main() {
    Solution solute;
    solute.solution();
    return 0;
}
accuracy: 0.5121951219512195
time_ms: 10
memory_kb: 9136
final_rank: 15

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
#include<utility>
#include<set>
#include<deque>
#include <unordered_map>
#include<string>
#include<cmath>

using namespace std;

int MIN = -1e9;
const int MOD = 10000;

int main() {
	int H, W;
	cin >> H >> W;
	vector<vector<char>>J(H, vector<char>(W));
	vector<vector<long long>>O(H, vector<long long>(W, 0));
	vector<vector<long long>>I(H, vector<long long>(W, 0));

	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			char c;
			cin >> c;
			J[i][j] = c;
			if (c == 'O') {
				O[i][j] = 1;
			}
			else if (c == 'I') {
				I[i][j] = 1;
			}
		}
	}

	for (int i = 1; i < H; i++) {
		for (int j = 0; j < W; j++) {
			I[i][j] += I[i - 1][j];
		}
	}

	for (int i = 0; i < H; i++) {
		for (int j = 1; j < W; j++) {
			O[i][j] += O[i][j-1];
		}
	}

	long long ans = 0;

	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			if (J[i][j] == 'J') {
				ans += (I[H - 1][j] - I[i][j]) * (O[i][W-1] - O[i][j]);
			}
		}
	}

	cout << ans<<endl;
}
accuracy: 1
time_ms: 350
memory_kb: 152564
final_rank: 13

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

int T[3100];
char in[3100][3100];
int main(){
  int a,b;scanf("%d%d",&a,&b);
  for(int i=0;i<a;i++)scanf("%s",in[i]);
  long long ret=0;
  for(int i=a-1;i>=0;i--){
    int tmp=0;
    for(int j=b-1;j>=0;j--){
      if(in[i][j]=='O')tmp++;
      if(in[i][j]=='I')T[j]++;
      if(in[i][j]=='J'){
        ret+=tmp*T[j];
      }
    }
  }
  cout<<ret<<endl;
}
accuracy: 1
time_ms: 50
memory_kb: 12600
final_rank: 2

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

int T[3100];
char in[3100][3100];
int main(){
	int a,b;scanf("%d%d",&a,&b);
	for(int i=0;i<a;i++)scanf("%s",in[i]);
	long long ret=0;
	for(int i=a-1;i>=0;i--){
		int tmp=0;
		for(int j=b-1;j>=0;j--){
			if(in[i][j]=='O')tmp++;
			if(in[i][j]=='I')T[j]++;
			if(in[i][j]=='J'){
				ret+=tmp*T[j];
			}
		}
	}
	cout<<ret<<endl;
}
accuracy: 1
time_ms: 50
memory_kb: 12620
final_rank: 3

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

int T[3100];
char in[3100][3100];
int main(){
  int a,b;scanf("%d%d",&a,&b);
  for(int i=0;i<a;i++)scanf("%s",in[i]);
  long long ret=0;
  for(int i=a-1;i>=0;i--){
    int tmp=0;
    for(int j=b-1;j>=0;j--){
      if(in[i][j]=='O')tmp++;
      if(in[i][j]=='I')T[j]++;
      if(in[i][j]=='J'){
        ret+=tmp*T[j];
      }
    }
  }
  cout<<ret<<endl;
}
accuracy: 1
time_ms: 50
memory_kb: 12556
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); ++i)

int main(){
    int h,w;
    cin >> h >> w;

    vector<vector<char>> grid(h,vector<char>(w));
    vector<vector<int>> x(h,vector<int>(w,0)),y(h,vector<int>(w,0));
    rep(i,h){
        string s;
        cin >> s;
        rep(j,w){
            grid[i][j]=s[j];
            if(grid[i][j]=='O'){
                x[i][j]++;
            }
            else if(grid[i][j]=='I'){
                y[i][j]++;
            }
        }
    }
    vector<vector<int>> X(h,vector<int>(w,0)),Y(h,vector<int>(w,0));
    rep(i,h){
        X[i][0]=x[i][0];
        rep(j,w-1){
            X[i][j+1]=X[i][j]+x[i][j+1];
        }
    }
    rep(j,w){
        Y[0][j]=y[0][j];
        rep(i,h-1){
            Y[i+1][j]=Y[i][j]+y[i+1][j];
        }
    }
    long long res=0;
    rep(i,h){
        rep(j,w){
            if(grid[i][j]=='J'){
                res+=(X[i][w-1]-X[i][j])*(Y[h-1][j]-Y[i][j]);
            }
        }
    }
    cout << res << endl;
}
accuracy: 1
time_ms: 300
memory_kb: 153040
final_rank: 12

code_snippet: #include <bits/stdc++.h>


using namespace std;
//make -f ../makefile SRC=
/*
TODO
prefix sum
*/


//------------------------------------------------------------------------------
bool DEBUG = false;
const int INF = 2147483647;

const int MAX_N = 3000;
static char GRID[MAX_N][MAX_N+5];
const char JEWEL = 'J';
const char ORB = 'O';
const char INGOT = 'I';

static int L[MAX_N][MAX_N]; // prefix sum of ORB towards left
static int T[MAX_N][MAX_N]; // prefix sum of INGOT towards top

//------------------------------------------------------------------------------
int64_t solve(int M, int N)
{
    //--------------------------------------------------------------------------
    // base cases:
    //--------------------------------------------------------------------------
    // init:
    for (int m=0; m<M; ++m) L[m][N-1] = ( GRID[m][N-1]==ORB ? 1 : 0 );

    for (int m=0; m<M; ++m)
        for (int n=N-2; n>=0; --n)
            L[m][n] = (GRID[m][n]==ORB) + L[m][n+1];

    for (int n=0; n<N; ++n) T[M-1][n] = ( GRID[M-1][n]==INGOT ? 1 : 0 );

    for (int n=0; n<N; ++n)
        for (int m=M-2; m>=0; --m)
            T[m][n] = (GRID[m][n]==INGOT) + T[m+1][n];
    
    //--------------------------------------------------------------------------
    // compute:
    int64_t res = 0;
    for (int m=0; m<M; ++m)
        for (int n=0; n<N; ++n)
            if (GRID[m][n] == JEWEL)
                res += L[m][n] * T[m][n];

    //--------------------------------------------------------------------------
    // report:
    return res;
}

//------------------------------------------------------------------------------
void test()
{

}

//------------------------------------------------------------------------------
int main()
{
    //test(); return 0;
    //DEBUG = true;
    //--------------------------------------------------------------------------
    int M, N, num;
    num = scanf("%d %d ", &M, &N);
    for (int m=0; m<M; ++m) num = scanf("%s ", GRID[m]);
    int64_t res = solve(M, N);
    printf("%ld\n", res);
    //--------------------------------------------------------------------------
    return 0;
}
//------------------------------------------------------------------------------
accuracy: 1
time_ms: 70
memory_kb: 82648
final_rank: 4

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

int H, W;
int sumI[3009][3009];
int sumO[3009][3009];
char C[3009][3009];

int main() {
	// Step 1. Input
	cin >> H >> W;
	for (int i = 1; i <= H; i++) {
		for (int j = 1; j <= W; j++) cin >> C[i][j];
	}

	// Step 2. Get Answer
	for (int i = H; i >= 1; i--) {
		for (int j = W; j >= 1; j--) {
			sumO[i][j] = sumO[i][j + 1] + (C[i][j] == 'O' ? 1 : 0);
			sumI[i][j] = sumI[i + 1][j] + (C[i][j] == 'I' ? 1 : 0);
		}
	}

	// Step 3. Output
	long long Answer = 0;
	for (int i = 1; i <= H; i++) {
		for (int j = 1; j <= W; j++) {
			if (C[i][j] != 'J') continue;
			Answer += 1LL * sumO[i][j] * sumI[i][j];
		}
	}
	cout << Answer << endl;
	return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 82920
final_rank: 6

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

long long H, W;
long long SumO[3009][3009];
long long SumI[3009][3009];
char C[3009][3009];

int main() {
	// Step 1. Input
	cin >> H >> W;
	for (int i = 1; i <= H; i++) {
		for (int j = 1; j <= W; j++) cin >> C[i][j];
	}

	// Step 2. Cumulative Sum
	for (int i = H; i >= 1; i--) {
		for (int j = W; j >= 1; j--) SumO[i][j] = SumO[i][j + 1] + (C[i][j] == 'O' ? 1 : 0);
	}
	for (int i = H; i >= 1; i--) {
		for (int j = W; j >= 1; j--) SumI[i][j] = SumI[i + 1][j] + (C[i][j] == 'I' ? 1 : 0);
	}

	// Step 3. Output
	long long Answer = 0;
	for (int i = 1; i <= H; i++) {
		for (int j = 1; j <= W; j++) {
			if (C[i][j] == 'J') {
				Answer += SumO[i][j] * SumI[i][j];
			}
		}
	}
	cout << Answer << endl;
	return 0;
}
accuracy: 1
time_ms: 230
memory_kb: 153464
final_rank: 11

code_snippet: #include <iostream>
#include <string>
using namespace std;

int h, w;
string arr[3000];

int calcO(int y, int x) {
    unsigned int countO = 0;
    for (int i = x; i < w; i++) {
        if (arr[y][i] == 'O') {
            countO++;
        } 
    }
    return countO;
}


int calcI(int y, int x) {
    int countI = 0;
    for (int i = y; i < h; i++) {
        if (arr[i][x] == 'I') {
            countI++;
        } 
    }
    return countI;
}

int main() {
    cin >> h >> w;

    for (int i = 0; i < h; i++) {
        cin >> arr[i];
    }
    int count = 0;
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            if (arr[i][j] == 'J') {
                int numO = calcO(i, j);
                int numI = calcI(i, j);
                count  += numO * numI;
            }
        }
    }
    cout << count << endl;
}
accuracy: 0.5121951219512195
time_ms: 50
memory_kb: 3412
final_rank: 18

code_snippet: #include <iostream>
#include <string>
using namespace std;

int h, w;
string arr[3000];

int calcO(int y, int x) {
    unsigned long long countO = 0;
    for (int i = x; i < w; i++) {
        if (arr[y][i] == 'O') {
            countO++;
        } 
    }
    return countO;
}


int calcI(int y, int x) {
    int countI = 0;
    for (int i = y; i < h; i++) {
        if (arr[i][x] == 'I') {
            countI++;
        } 
    }
    return countI;
}

int main() {
    cin >> h >> w;

    for (int i = 0; i < h; i++) {
        cin >> arr[i];
    }
    int count = 0;
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            if (arr[i][j] == 'J') {
                int numO = calcO(i, j);
                int numI = calcI(i, j);
                count  += numO * numI;
            }
        }
    }
    cout << count << endl;
}
accuracy: 0.5121951219512195
time_ms: 50
memory_kb: 3412
final_rank: 18

code_snippet: #include <iostream>
#include <string>
using namespace std;

int h, w;
string arr[3000];

int calcO(int y, int x) {
    unsigned long countO = 0;
    for (int i = x; i < w; i++) {
        if (arr[y][i] == 'O') {
            countO++;
        } 
    }
    return countO;
}


int calcI(int y, int x) {
    int countI = 0;
    for (int i = y; i < h; i++) {
        if (arr[i][x] == 'I') {
            countI++;
        } 
    }
    return countI;
}

int main() {
    cin >> h >> w;

    for (int i = 0; i < h; i++) {
        cin >> arr[i];
    }
    int count = 0;
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            if (arr[i][j] == 'J') {
                int numO = calcO(i, j);
                int numI = calcI(i, j);
                count  += numO * numI;
            }
        }
    }
    cout << count << endl;
}
accuracy: 0.5121951219512195
time_ms: 50
memory_kb: 3360
final_rank: 17

code_snippet: #include <iostream>
#include <string>
using namespace std;

int h, w;
string arr[3000];

int calcO(int y, int x) {
    long countO = 0;
    for (int i = x; i < w; i++) {
        if (arr[y][i] == 'O') {
            countO++;
        } 
    }
    return countO;
}


int calcI(int y, int x) {
    int countI = 0;
    for (int i = y; i < h; i++) {
        if (arr[i][x] == 'I') {
            countI++;
        } 
    }
    return countI;
}

int main() {
    cin >> h >> w;

    for (int i = 0; i < h; i++) {
        cin >> arr[i];
    }
    int count = 0;
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            if (arr[i][j] == 'J') {
                int numO = calcO(i, j);
                int numI = calcI(i, j);
                count  += numO * numI;
            }
        }
    }
    cout << count << endl;
}
accuracy: 0.5121951219512195
time_ms: 50
memory_kb: 3344
final_rank: 16

code_snippet: #include <iostream>
#include <string>
using namespace std;

int h, w;
string arr[3000];

int calcO(int y, int x) {
    int countO = 0;
    for (int i = x; i < w; i++) {
        if (arr[y][i] == 'O') {
            countO++;
        } 
    }
    return countO;
}


int calcI(int y, int x) {
    int countI = 0;
    for (int i = y; i < h; i++) {
        if (arr[i][x] == 'I') {
            countI++;
        } 
    }
    return countI;
}

int main() {
    cin >> h >> w;

    for (int i = 0; i < h; i++) {
        cin >> arr[i];
    }
    int count = 0;
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            if (arr[i][j] == 'J') {
                int numO = calcO(i, j);
                int numI = calcI(i, j);
                count  += numO * numI;
            }
        }
    }
    cout << count << endl;
}
accuracy: 0.5121951219512195
time_ms: 60
memory_kb: 3360
final_rank: 20

code_snippet: #include <iostream>
#include <vector>
#include <string>

using namespace std;

const int MAX_H = 3010;
const int MAX_W = 3010;

long long o[MAX_H][MAX_W] = {};
long long l[MAX_H][MAX_W] = {};

int main() {
    int h, w;
    long long ans = 0;
    string s[MAX_H];
    cin >> h >> w;
    
    // 入力の読み込み
    for (int i = 0; i < h; i++) {
        cin >> s[i];
        for (int j = 0; j < w; j++) {
            if (s[i][j] == 'O') o[i][j]++;
            if (s[i][j] == 'I') l[i][j]++;
        }
    }

    // 右方向へのオーブの累積和
    for (int i = 0; i < h; i++) {
        for (int j = w - 2; j >= 0; j--) {
            o[i][j] += o[i][j + 1];
        }
    }

    // 下方向への金塊の累積和
    for (int i = h - 2; i >= 0; i--) {
        for (int j = 0; j < w; j++) {
            l[i][j] += l[i + 1][j];
        }
    }

    // 宝石がある場所から威力を計算
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            if (s[i][j] == 'J') {
                ans += o[i][j] * l[i][j];
            }
        }
    }

    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 180
memory_kb: 156088
final_rank: 10

code_snippet: #include<bits/stdc++.h>
using namespace std;
using ll = long long;
using vi=vector<int>;   
using vvi=vector<vi>;
#define rep(i,n) for(int i=0;i<(int)n;i++)
#define rep1(i,n) for(int i=1;i<=(int)n;i++)


int main() {      
	int h,w;cin>>h>>w;
	vector<string>s(h);
	rep(i,h)cin>>s[i];
	vvi ingot(h+1,vi(w+1,0));
	vvi orb(h+1,vi(w+1,0));
	rep(i,h){
		rep(j,w){
			if(s[i][j]=='O'){
			    orb[i+1][j+1]=1;
			}   
			if(s[i][j]=='I'){
			     ingot[i+1][j+1]=1;
			}
		}
	}                      
	ll ans=0;         
	rep(i,h)rep(j,w)orb[i][j+1]+=orb[i][j];  
	rep(i,h)rep(j,w)ingot[i+1][j]+=ingot[i][j];
	rep(i,h)rep(j,w){
		if(s[i][j]!='J')continue;  
		
		 ans+=(orb[i+1][w]-orb[i+1][j])*(ingot[h][j+1]-ingot[i][j+1]);
	}
	
	cout<<ans<<endl;
	
	                                             
	
}
accuracy: 1
time_ms: 190
memory_kb: 85044
final_rank: 5

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

int H, W;
int Sum1[3009][3009];
int Sum2[3009][3009];
char C[3009][3009];

int main() {
	// Step 1. Input
	cin >> H >> W;
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) cin >> C[i][j];
	}

	// Step 2. Cumulative Sum
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			if (C[i][j] == 'O') Sum1[i][j] = 1;
			if (C[i][j] == 'I') Sum2[i][j] = 1;
		}
	}
	for (int i = H - 1; i >= 0; i--) {
		for (int j = W - 1; j >= 0; j--) {
			Sum1[i][j] += Sum1[i][j + 1];
			Sum2[i][j] += Sum2[i + 1][j];
		}
	}

	// Step 3. Output
	long long Answer = 0;
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			if (C[i][j] != 'J') continue;
			Answer += Sum1[i][j] * Sum2[i][j];
		}
	}
	cout << Answer << endl;
	return 0;
}
accuracy: 1
time_ms: 260
memory_kb: 82840
final_rank: 7

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

int H, W;
char C[3009][3009];
int Sum1[3009][3009];
int Sum2[3009][3009];

int main() {
	// Step 1. Input
	cin >> H >> W;
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) cin >> C[i][j];
	}

	// Step 2. Ruisekiwa
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			if (C[i][j] == 'O') Sum1[i][j] = 1;
			if (C[i][j] == 'I') Sum2[i][j] = 1;
		}
	}
	for (int i = H - 1; i >= 0; i--) {
		for (int j = W - 1; j >= 0; j--) {
			Sum1[i][j] += Sum1[i][j + 1];
			Sum2[i][j] += Sum2[i + 1][j];
		}
	}

	// Step 3. Output
	long long Answer = 0;
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			if (C[i][j] == 'J') Answer += 1LL * Sum1[i][j] * Sum2[i][j];
		}
	}
	cout << Answer << endl;
	return 0;
}
accuracy: 1
time_ms: 270
memory_kb: 82976
final_rank: 9

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

int H, W;
int Sum1[3009][3009];
int Sum2[3009][3009];
char C[3009][3009];

int main() {
	// Step 1. Input
	cin >> H >> W;
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) cin >> C[i][j];
	}

	// Step 2. Get Sum
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			if (C[i][j] == 'O') Sum1[i][j] = 1;
			if (C[i][j] == 'I') Sum2[i][j] = 1;
		}
	}
	for (int i = H - 1; i >= 0; i--) {
		for (int j = W - 1; j >= 0; j--) {
			Sum1[i][j] += Sum1[i][j + 1];
			Sum2[i][j] += Sum2[i + 1][j];
		}
	}

	// Step 3. Output
	long long Answer = 0;
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			if (C[i][j] != 'J') continue;
			Answer += 1LL * Sum1[i][j] * Sum2[i][j];
		}
	}
	cout << Answer << endl;
	return 0;
}
accuracy: 1
time_ms: 270
memory_kb: 82900
final_rank: 8