题目描述
小A打算开始炼NOI元丹(什么鬼),据说吃了可以提高NOI时的成绩。
是这么练的。元丹有三种元核,’N’,’O’,’I’。现有很多个这样原核,按顺序排成一行。炼元丹时,从左往右分别挑出’N’,’O’,’I’三个原核吞下。
现在他关心,有几种服用方式……且慢!
他觉得服用方式太少,以至于不能成仙。所以他可以通过某个途径,得到’N’,’O’,’I’的三种原核中的任意一个,至于哪一种由他决定。然后他将获得这个原核的插入到这一排原核中的任意位置(包括最前最后)。
现在你要知道,新的元核序列中能有多少种’N’,’O’,’I’的取出方式。子串的字母并不要求连续。
输入输出格式
输入格式:
第一行,一个整数N,表示字符串的长度。
第二行,一行字符串,里面只有只有’N’,’O’,’I’三种字母。
输出格式:
表示出最多可以提炼出来的NOI元丹的方案种数。
输入输出样例
输入样例#1:
5
NOIOI
输出样例#1:
6
说明
样例解释
他可以获取一个N元核,加到最前面。
NNOIOI | NNOIOI | NNOIOI | NNOIOI | NNOIOI | NNOIOI
~ ~~ | ~ ~ ~ | ~ ~~ | ~~~ | ~~ ~ | ~ ~~
30%的数据N<=200
50%的数据N<=2000
100%的数据3<=N<=100000
【分析】
无敌前缀和!乱搞一番!
这题我拿后缀和做的…其实跟前缀和貌似没有差别呢。
对于增加N,肯定放在第一个之前最棒
对于I,最后一个位置最棒
对于O,枚举一波,每次枚举复杂度O(1),具体求法就是在该位置之前的N的个数乘该位置之后的I的个数。
代码略长了些…考试嘛…脑子比较迷糊…
【代码】
//洛谷月赛 2.NOI元丹
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=100005;
char s[mxn];
ll n,now,ans=0,ans1,ans2,ans3;
ll next[mxn],sum_o[mxn],sum_i[mxn],sum_n[mxn],res[mxn];
int main()
{
/////读入//////
int i,j,h;
scanf("%lld",&n);
scanf("%s",s+1);
now=n+1;
/////初始化//////
for(i=n;i>=1;i--)
{
sum_o[i]=sum_o[i+1];
sum_i[i]=sum_i[i+1];
sum_n[i]=sum_n[i+1];
if(s[i]=='N')
{
sum_n[i]++;
next[i]=now;
now=i;
}
else if(s[i]=='O') sum_o[i]++;
else sum_i[i]++;
}
/////////getN////////
for(i=n;i>=1;i--)
if(s[i]=='N')
{
int tmp=next[i];
res[i]=res[tmp];
tmp--;
fo(j,i+1,tmp)
if(s[j]=='O')
res[i]+=sum_i[j];
ans+=res[i];
}
// printf("pre=%d\n",ans);
ans1=ans;
{//'N'
fo(i,1,n) if(s[i]=='N') {h=i;break;}
ans1+=res[h];
fo(j,1,h)
if(s[j]=='O')
ans1+=sum_i[j];
}
////////////////////////////////////////无敌分割线->getI
now=0;
fo(i,1,n)
if(s[i]=='I')
next[i]=now,now=i;
M(res);
fo(i,1,n)
if(s[i]=='I')
{
int tmp=next[i];
res[i]=res[tmp];
tmp++;
fo(j,tmp,i)
if(s[j]=='O')
res[i]+=sum_n[1]-sum_n[j];
}
{//'I'
for(i=n;i>=1;i--) if(s[i]=='I') {h=i;break;}
ans2+=res[h];
for(j=n;j>h;j--)
if(s[j]=='O')
ans2+=sum_n[1]-sum_n[j];
}
ans2+=ans;
///////////////getO////////////
fo(i,1,n)
ans3=max(ans3,ans+(sum_n[1]-sum_n[i+1])*sum_i[i]);
// printf("N=%lld\nO=%lld\nI=%lld\n",ans1,ans3,ans2);
ans=max(ans1,max(ans2,ans3));
printf("%lld\n",ans);
return 0;
}