洛谷1371 NOI元丹

题目描述

小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 long
LL 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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值