文章目录
1884. COW
题目
https://www.acwing.com/problem/content/1886/
奶牛贝茜在她最喜欢的牧场中发现了一块石碑,上面刻有神秘的碑文。
碑文的文字似乎来自一种神秘的古代语言,可看作一个只包含 C,O,WC,O,W 三种字符的字符串。
尽管贝茜无法解密该文字,但是她很欣赏 C,O,WC,O,W 按顺序构成她最喜欢的单词 COWCOW。
她想知道 COWCOW 在碑文中一共出现了多少次。
她不介意 C,O,WC,O,W 之间是否存在其他字符,只要这三个字符按正确的顺序出现即可。
她也不介意多个不同的 COWCOW 是否共享了一些字符。
例如,COWCOW 在 CWOWCWOW 中只出现一次,在 CCOWCCOW 中出现两次,在 CCOOWWCCOOWW 中出现八次。
给定碑文中的文字,请帮助贝茜计算 COWCOW 出现的次数。
输入格式
第一行包含 NN。
第二行包含一个长度为 NN 的字符串,其中只包含字符 C,O,WC,O,W。
输出格式
输出给定字符串中 COWCOW 作为子序列(不一定连续)的出现次数。
数据范围
1≤N≤1051≤N≤105
输入样例:
6
COOWWW
输出样例:
6
代码与解释
解法1
看到acwing上面的神仙题解
输入字符串
从前往后遍历
如果遍历到‘O’,它只会与前面的‘C’组成”CO“,所以不需要管后面的‘C’的数量
同理如果遍历到‘W’,它只会与前面的‘CO’组成”COW“,所以不需要管后面的‘CO’的数量
记录当前‘C’,“CO”,“COW”的个数
#include <bits/stdc++.h>
#define pb push_back
#define ppb pop_back
#define lbnd lower_bound
#define ubnd upper_bound
#define endl '\n'
#define all(a) (a).begin(),(a).end()
#define what_is(x) cerr << #x << " is " << x << endl;
#define ini(a) memset(a,0,sizeof(a))
#define case ll T;read(T);for(ll Q=1;Q<=T;Q++)
#define lowbit(x) x&(-x)
#define pr printf
#define sc scanf
#define TIE \
cin.tie(0);cout.tie(0);\
ios::sync_with_stdio(false);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll LLINF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 5e5+10;
const ll N = 5;
void solve(){
ll n, c = 0, w = 0, o = 0;
string s;
cin>>n>>s;
for (ll i=0; i<n; i++) {
if (s[i] == 'C') c++;
else if (s[i] == 'O') o += c;
else w += o;
}
cout<<w<<endl;
}
int main()
{
// TIE;
solve();
// case{solve();}
// case{cout<<"Case "<<Q<<":"<<endl;solve();}
}
解法2
其实是我看解法1看到一半的时候想出来的,但是比解法1多了一次循环,时间复杂度也是O(n)
我在网上还看到了用前缀和来做的,其实原理也是一样
dp的解法原理也是类似https://www.acwing.com/solution/content/86159/
#include <bits/stdc++.h>
#define pb push_back
#define ppb pop_back
#define lbnd lower_bound
#define ubnd upper_bound
#define endl '\n'
#define all(a) (a).begin(),(a).end()
#define what_is(x) cerr << #x << " is " << x << endl;
#define ini(a) memset(a,0,sizeof(a))
#define case ll T;read(T);for(ll Q=1;Q<=T;Q++)
#define lowbit(x) x&(-x)
#define pr printf
#define sc scanf
#define TIE \
cin.tie(0);cout.tie(0);\
ios::sync_with_stdio(false);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll LLINF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 5e5+10;
const ll N = 5;
void solve(){
ll n, c = 0, o = 0, w = 0, ans = 0, allw = 0;
string s;
cin>>n>>s;
for (ll i=0; i<n; i++) if (s[i] == 'W') allw++;
for (ll i=0; i<n; i++) {
if (s[i] == 'C') c++;
else if (s[i] == 'O') ans += c*(allw - w);
else if (s[i] == 'W') w++;
}
cout<<ans<<endl;
}
int main()
{
// TIE;
solve();
// case{solve();}
// case{cout<<"Case "<<Q<<":"<<endl;solve();}
}
解法3
原题解链接:https://www.acwing.com/solution/content/85860/
简单说就是遍历的时候,每一次扫描到字符是W
,那么能和这个W
组合的就是CO
的数量,再加上前面的COW
的数量即可
我觉得这个解法也很有意思
#include <bits/stdc++.h>
#define pb push_back
#define ppb pop_back
#define lbnd lower_bound
#define ubnd upper_bound
#define endl '\n'
#define all(a) (a).begin(),(a).end()
#define what_is(x) cerr << #x << " is " << x << endl;
#define ini(a) memset(a,0,sizeof(a))
#define case ll T;read(T);for(ll Q=1;Q<=T;Q++)
#define lowbit(x) x&(-x)
#define pr printf
#define sc scanf
#define TIE \
cin.tie(0);cout.tie(0);\
ios::sync_with_stdio(false);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll LLINF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 5e5+10;
const ll N = 5;
ll p_c[maxn], p_co[maxn], p_cow[maxn];
char s[maxn];
void solve(){
ll n, c = 0, o = 0, w = 0, ans = 0, allw = 0;
cin>>n;
sc("%s",s+1);
for (int i=1; i<=n; i++) {
if (s[i] == 'C') p_c[i] = p_c[i-1]+1;
else p_c[i] = p_c[i-1];
if (s[i] == 'O') {
p_co[i] = p_c[i] + p_co[i-1];
} else {
p_co[i] = p_co[i-1];
}
if (s[i] == 'W') {
p_cow[i] = p_co[i];
p_cow[i] += p_cow[i-1];
} else {
p_cow[i] += p_cow[i-1];
}
}
cout<<p_cow[n]<<endl;
}
int main()
{
// TIE;
solve();
// case{solve();}
// case{cout<<"Case "<<Q<<":"<<endl;solve();}
}