1884. COW

1884. COW

题目链接

AcWing 1884. COW

奶牛贝茜在她最喜欢的牧场中发现了一块石碑,上面刻有神秘的碑文。

碑文的文字似乎来自一种神秘的古代语言,可看作一个只包含 \(C,O,W\) 三种字符的字符串。

尽管贝茜无法解密该文字,但是她很欣赏 \(C,O,W\) 按顺序构成她最喜欢的单词 \(COW\)

她想知道 \(COW\) 在碑文中一共出现了多少次。

她不介意 \(C,O,W\) 之间是否存在其他字符,只要这三个字符按正确的顺序出现即可。

她也不介意多个不同的 \(COW\) 是否共享了一些字符。

例如,\(COW\)\(CWOW\) 中只出现一次,在 \(CCOW\) 中出现两次,在 \(CCOOWW\) 中出现八次。

给定碑文中的文字,请帮助贝茜计算 \(COW\) 出现的次数。

输入格式

第一行包含 \(N\)

第二行包含一个长度为 \(N\) 的字符串,其中只包含字符 \(C,O,W\)

输出格式

输出给定字符串中 \(COW\) 作为子序列(不一定连续)的出现次数。

数据范围

\(1≤N≤10^5\)

输入样例:

6
COOWWW

输出样例:

6

数位dp

  • 状态表示:\(f[i][j]\) 表示子序列的前 \(j\) 个字符在母串的前 \(i\) 个字符中出现的次数

  • 状态计算:

    • \(f[i][1]=f[i-1][1]+(s[i]==p[1])\)
    • \(f[i][j]=f[i-1][j]+(s[i]==p[j])*f[i-1][j-1]\)
      分析:1.相当于一个字符在母串中出现的次数,这个比较好理解。2.如果母串的最后一个字符与子序列的最后一个字符不相等,寻找出现次数,则必须在母串最后一个字符为 \(p[j]\) 的位置,此时 \(f[i][j]=f[i-1][j]\);如果相等,则母串的最后一个字符 \(s[i]\) 对出现次数的贡献为 \(f[i-1][j-1]\),即子序列 \(p\) 的前 \(j-1\) 个字符出现的次数,此时 \(f[i][j]=f[i-1][j]+f[i-1][j-1]\),有点类似于组合数
  • 时间复杂度:\(O(3\times n)\)

递推

分别按序记录字母 \(C\) 出现的次数,当出现字母 \(O\) 时加上前面 \(C\) 出现的次数即 \(CO\) 出现的总次数,同理可计算出 \(COW\) 出现的总次数

  • 时间复杂度:\(O(n)\)

代码

  • dp
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
char s[N];
int n;
long long f[N][3];
int main()
{
    string p=" COW";
    scanf("%d%s",&n,s+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=3;j++)
        {
            f[i][1]=f[i-1][1]+(s[i]==p[1]);
            f[i][j]=f[i-1][j]+(s[i]==p[j])*f[i-1][j-1];
        }
    printf("%lld",f[n][3]);
    return 0;
}
  • 递推
#include<bits/stdc++.h>
using namespace std;
long long a,b,c;
int n;
char s[100005];
int main()
{
    scanf("%d%s",&n,s);
    for(int i=0;i<n;i++)
        if(s[i]=='C')a++;
        else if(s[i]=='O')b+=a;
        else
            c+=b;
    printf("%lld",c);
    return 0;
}
posted @ 2022-01-22 23:53  zyy2001  阅读(117)  评论(0编辑  收藏  举报