洛谷 P1371 NOI元丹

来源:互联网 发布:windows 10碎片整理 编辑:程序博客网 时间:2024/04/28 03:33

题目描述

小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;}
1 1
原创粉丝点击