NOI元丹

【题目描述】
小A打算开始炼NOI元丹(什么鬼),据说吃了可以提高NOI时的成绩。
是这么练的。元丹有三种元核,’N’,’O’,’I’。现有很多个这样原核,按顺序排成一行。炼元丹时,从左往右分别挑出’N’,’O’,’I’三个原核吞下。
现在他关心,有几种服用方式……且慢!
他觉得服用方式太少,以至于不能成仙。所以他可以通过某个途径,得到’N’,’O’,’I’的三种原核中的任意一个,至于哪一种由他决定。然后他将获得这个原核的插入到这一排原核中的任意位置(包括最前最后)。
现在你要知道,新的元核序列中能有多少种’N’,’O’,’I’的取出方式。子串的字母并不要求连续。
【输入格式】
第一行,一个整数N,表示字符串的长度。
第二行,一行字符串,里面只有只有’N’,’O’,’I’三种字母。
【输出格式】
表示出最多可以提炼出来的NOI元丹的方案种数。
【样例输入】
5
NOIOI
【样例输出】
6
【分析】
如果不能插入新的字母就太简单了,可是这题要插入新的字母。
如果要插入N,那么这个N一定插在序列最前面,这个画个图就能证明。
如果要插入I,那么这个I一定插在序列最后面,与上同理。
如果要插入O,那么设leftn[i]表示第i个字母左边N的个数,righti[i]表示第i个字母右边I的个数,枚举使leftn[x]*right[x]最大的x即可。

var
  i,n,p:longint;
    leftn,righti:array[0..100001]of qword;
    ans,t,tt:qword;
    s,s1:ansistring;
function max(x,y:qword):qword;
begin
  if x>y then exit(x) else exit(y);
end;
function search(st:ansistring):qword;
var
  f:array[1..3]of qword;
    ch:char;
    i:longint;
begin
  fillchar(f,sizeof(f),0);
  for i:=1 to n+1 do begin
    ch:=st[i];
    if ch='N' then f[1]:=f[1]+1;
    if ch='O' then f[2]:=f[2]+f[1];
    if ch='I' then f[3]:=f[3]+f[2];
  end;
  exit(f[3]);
end;
begin
  ans:=0;
    readln(n);
  readln(s);
    n:=length(s);
    s1:='N'+s;
    ans:=max(ans,search(s1));
    s1:=s+'I';
    ans:=max(ans,search(s1));
    s1:=s;
    leftn[0]:=0;
    for i:=1 to n do begin
      leftn[i]:=leftn[i-1];
      if s[i]='N' then inc(leftn[i]);
    end;
    righti[n+1]:=0;
    for i:=n downto 1 do begin
      righti[i]:=righti[i+1];
        if s[i]='I' then inc(righti[i]);
    end;
    t:=0;
    for i:=1 to n do begin
      tt:=leftn[i]*righti[i];
        if tt>t then begin t:=tt;p:=i; end;
    end;
    s1:=s;
    insert('O',s1,p+1);
    ans:=max(ans,search(s1));
    write(ans);
end.
posted @ 2016-10-29 22:27  JRX2015U43  阅读(110)  评论(0编辑  收藏  举报