洛谷1371 NOI元丹

来源:互联网 发布:软件测试英文工作报告 编辑:程序博客网 时间:2024/05/17 05:16

题目描述

小A打算开始炼NOI元丹(什么鬼),据说吃了可以提高NOI时的成绩。

是这么练的。元丹有三种元核,’N’,’O’,’I’。现有很多个这样原核,按顺序排成一行。炼元丹时,从左往右分别挑出’N’,’O’,’I’三个原核吞下。

现在他关心,有几种服用方式……且慢!

他觉得服用方式太少,以至于不能成仙。所以他可以通过某个途径,得到’N’,’O’,’I’的三种原核中的任意一个,至于哪一种由他决定。然后他将获得这个原核的插入到这一排原核中的任意位置(包括最前最后)。

现在你要知道,新的元核序列中能有多少种’N’,’O’,’I’的取出方式。子串的字母并不要求连续。 输入输出格式 输入格式:

第一行,一个整数N,表示字符串的长度。

第二行,一行字符串,里面只有只有’N’,’O’,’I’三种字母。

输出格式:

表示出最多可以提炼出来的NOI元丹的方案种数。

正着扫一遍求出f[i][0/1/2]表示前i个,’N’ ‘NO’ ‘NOI’的个数,
倒着扫一遍求出g[i][0/1/2]表示i..n,’I’ ‘OI’ ‘NOI’的个数。
N一定加在开头,I一定加在末尾,枚举O的位置,总复杂度O(n)。

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>using namespace std;#define LL long longLL f[100010][3],g[100010][3];int a[100010],n;char s[100010];int main(){    int i,j,k,p,q,x,y,z;    LL ans;    scanf("%d",&n);    scanf("%s",s+1);    for (i=1;i<=n;i++)      if (s[i]=='O') a[i]=1;      else if (s[i]=='I') a[i]=2;    for (i=1;i<=n;i++)    {        f[i][0]=f[i-1][0];        f[i][1]=f[i-1][1];        f[i][2]=f[i-1][2];        if (!a[i]) f[i][0]++;        if (a[i]==1) f[i][1]+=f[i-1][0];        if (a[i]==2) f[i][2]+=f[i-1][1];    }    for (i=n;i;i--)    {        g[i][0]=g[i+1][0];        g[i][1]=g[i+1][1];        g[i][2]=g[i+1][2];        if (!a[i]) g[i][2]+=g[i+1][1];        if (a[i]==1) g[i][1]+=g[i+1][0];        if (a[i]==2) g[i][0]++;    }    ans=max(f[n][2]+f[n][1],f[n][2]+g[1][1]);    for (i=1;i<n;i++)      ans=max(ans,f[n][2]+f[i][0]*g[i+1][0]);    cout<<ans<<endl;}
0 1
原创粉丝点击