动态规划 题解 100% AC
2025-12-26 16:38:40
发布于:江苏
7阅读
0回复
0点赞
[USACO 2015 February Bronze] COW 题解
题目大意
给定一个长度为 的字符串,仅包含字符 C、O、W。我们需要统计序列 COW 作为子序列(不要求连续)在字符串中出现的次数。
算法分析
暴力解法的问题
最直观的想法是枚举三个位置 ,判断 、、。这样的时间复杂度为 ,对于 来说显然不可行。
高效解法
我们采用动态规划的思想,记录到当前位置为止:
C的数量(即COW中第一个字符的出现次数)- 序列
CO的数量(即第一个字符为C,第二个字符为O的序列数) - 序列
COW的数量(即完整的COW序列数)
具体维护方式:
- 当遇到字符
C时,它本身可以作为新的COW序列的起点 - 当遇到字符
O时,它可以与之前的所有C组成CO序列 - 当遇到字符
W时,它可以与之前的所有CO序列组成完整的COW序列
核心算法
设三个计数器:
c_count: 字符C出现的次数co_count: 序列CO出现的次数cow_count: 序列COW出现的次数
遍历字符串的每个字符:
- 如果是
C:c_count++ - 如果是
O:co_count += c_count(每个C都可以和这个O组成CO) - 如果是
W:cow_count += co_count(每个CO都可以和这个W组成COW)
时间复杂度
- 时间复杂度:,只需要遍历一次字符串
- 空间复杂度:,只需要几个计数器变量
正确性证明
设 表示前 个字符中 C 的个数, 表示前 个字符中 CO 子序列的个数, 表示前 个字符中 COW 子序列的个数。
递推关系:
- 如果 : ,,
- 如果 : ,,
- 如果 : ,,
我们的算法正是模拟了这个递推过程。
代码实现
#include<bits/stdc++.h>
using namespace std;
int main() {
long long n, c = 0, co = 0, cow = 0;
string s;
cin >> n >> s;
for(int i = 0; i < n; i++) {
if(s[i] == 'C') {
c++; // 新的C,可以作为COW的起点
} else if(s[i] == 'O') {
co += c; // 这个O可以和之前的所有C组成CO
} else if(s[i] == 'W') {
cow += co; // 这个W可以和之前的所有CO组成COW
}
}
cout << cow << endl;
return 0;
}
示例分析
示例1
输入:
6
COOWWW
处理过程:
字符 c co cow
C 1 0 0
O 1 1 0
O 1 2 0
W 1 2 2
W 1 2 4
W 1 2 6
输出: 6
其他示例
CWOW: 只有1个COW序列CCOW: 有2个COW序列(两个C都可以和O、W组成序列)CCOOWW: 有8个COW序列
注意事项
- 使用
long long类型存储计数器,因为答案可能很大 - 算法是 的,可以处理 的数据规模
- 注意字符顺序必须是
C→O→W,不能颠倒
总结
本题考察了子序列计数的动态规划思想。通过维护中间状态(C、CO 的数量),我们可以在线性时间内计算出 COW 序列的总数。这种方法可以推广到计算任意固定序列作为子序列出现的次数。
这里空空如也







有帮助,赞一个