using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static string InputPattern = "InputX";
static List<string> GetInputList()
{
var WillReturn = new List<string>();
if (InputPattern == "Input1") {
WillReturn.Add("5");
WillReturn.Add("JOIOI");
//6
}
else if (InputPattern == "Input2") {
WillReturn.Add("7");
WillReturn.Add("JJJOIII");
//18
}
else if (InputPattern == "Input3") {
WillReturn.Add("4");
WillReturn.Add("OIIJ");
//2
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static void Main()
{
List<string> InputList = GetInputList();
string S = InputList[1];
int UB = S.Length - 1;
var AnswerList = new List<long>();
// Jは、1番左に追加が最適
AnswerList.Add(ExecDP("J" + S));
// Iは、1番右に追加が最適
AnswerList.Add(ExecDP(S + "I"));
// Oを追加すると、左のJの数 * 右のIの数だけ解が増える
long BaseCnt = ExecDP(S);
// Jの数のフェニック木
var InsFenwick_Tree_J = new Fenwick_Tree(UB);
// Iの数のフェニック木
var InsFenwick_Tree_I = new Fenwick_Tree(UB);
for (int I = 0; I <= UB; I++) {
if (S[I] == 'J') InsFenwick_Tree_J.Add(I, 1);
if (S[I] == 'I') InsFenwick_Tree_I.Add(I, 1);
}
for (int I = 0; I <= UB - 1; I++) {
int LeftRangeSta = 0;
int LeftRangeEnd = I;
int RightRangeSta = I + 1;
int RightRangeEnd = UB;
long Cnt_J = InsFenwick_Tree_J.GetSum(LeftRangeSta, LeftRangeEnd);
long Cnt_I = InsFenwick_Tree_I.GetSum(RightRangeSta, RightRangeEnd);
long ProdVal = Cnt_J * Cnt_I;
AnswerList.Add(BaseCnt + ProdVal);
}
Console.WriteLine(AnswerList.Max());
}
// 文字列を引数として、場合の数を返す
static long ExecDP(string pStr)
{
// 場合の数[状態]
// 0 なにもなし
// 1 J
// 2 O
long UB = 2;
long[] DPArr = new long[UB + 1];
DPArr[0] = 1;
long Answer = 0;
foreach (char EachChar in pStr) {
for (long I = UB; 0 <= I; I--) {
if (DPArr[I] == 0) continue;
if (I == 0 && EachChar == 'J') {
DPArr[1] += DPArr[I];
}
if (I == 1 && EachChar == 'O') {
DPArr[2] += DPArr[I];
}
if (I == 2 && EachChar == 'I') {
Answer += DPArr[I];
}
}
}
return Answer;
}
}
// フェニック木
#region Fenwick_Tree
internal class Fenwick_Tree
{
private long[] mBitArr;
private long mExternalArrUB;
// ノードのIndexの列挙を返す
internal IEnumerable<long> GetNodeIndEnum()
{
for (long I = 0; I <= mExternalArrUB; I++) {
yield return I;
}
}
// 木のノードのUBを返す
internal long GetUB()
{
return mExternalArrUB;
}
// コンストラクタ(外部配列のUBのみ指定)
internal Fenwick_Tree(long pExternalArrUB)
{
mExternalArrUB = pExternalArrUB;
// フェニック木の外部配列は0オリジンで、
// フェニック木の内部配列は1オリジンなため、2を足す
mBitArr = new long[pExternalArrUB + 2];
}
// コンストラクタ(初期化用の配列指定)
internal Fenwick_Tree(long[] pArr)
: this(pArr.GetUpperBound(0))
{
for (long I = 0; I <= pArr.GetUpperBound(0); I++) {
this.Add(I, pArr[I]);
}
}
// コンストラクタ(初期化用のList指定)
internal Fenwick_Tree(List<long> pList)
: this(pList.Count - 1)
{
for (int I = 0; I <= pList.Count - 1; I++) {
this.Add(I, pList[I]);
}
}
// [pSta,pEnd] のSumを返す
internal long GetSum(long pSta, long pEnd)
{
return GetSum(pEnd) - GetSum(pSta - 1);
}
// [0,pEnd] のSumを返す
internal long GetSum(long pEnd)
{
pEnd++; // 1オリジンに変更
long Sum = 0;
while (pEnd >= 1) {
Sum += mBitArr[pEnd];
pEnd -= pEnd & -pEnd;
}
return Sum;
}
// [I] に Xを加算
internal void Add(long pI, long pX)
{
pI++; // 1オリジンに変更
while (pI <= mBitArr.GetUpperBound(0)) {
mBitArr[pI] += pX;
pI += pI & -pI;
}
}
}
#endregion