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]\),有点类似于组合数
- \(f[i][j]=f[i-1][j]+(s[i]==p[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;
}