「解题报告」CF1178B WOW Factor

¿


题目链接

这是一道非常富有启发性的题目,值得一做,闪耀着人类和机器人的智慧光辉的绝佳题目 .

首先注意到 (vv)o(vv) 的结构,可以考虑枚举中间的 o,这样只需要算两边的选法然后用乘法原理即可 .

乘法原理:做一件事,完成它需要分成 n 个步骤,做第一步有 m1 种不同的方法,做第二步有 m2 种不同的方法,……,做第 n 步有 mn 种不同的方法。那么完成这件事共有 N=m1×m2×m3××mn 种不同的方法 .

根据乘法原理,其实就是选择这个字符串有三个步骤,先选左边有 a 种,中间的 o1 种,右边有 b 种,那么总方案数就是 N=a×1×b .

那么考虑怎么求 ab,分别考虑:

Part 1a

厉害的一步到了,令 fi 表示 [si=si+1=v](这里的 [] 叫 Iverson Bracket,大佬教的,[x] 就是 bool(x)

那么如果 o 的位置是 i,那么 a=f1+f2++fi1 就是连续 vv 的个数了,不用考虑冲突,因为只需要选一个不选多个 .

如果每次都直接求和,需要约 106×106 次加法,无法接受,怎么办呢?

发现是要对于每个位置求,于是假设第 i 个位置的答案是 A,第 i+1 个位置的答案是 B(不需要考虑是否为 o,后面说原因),那么

A=f1+f2++fi1B=f1+f2++fi1+fi

惊奇的发现:B=A+fi

这样先算出第一个位置的答案,然后用一个 for 循环就可以求出每个位置的 a 值,使用时只计算有 o 的位置就行了 .

Part 2b

也是类似的做法,如果 o 的位置是 i,那么 b=fi+fi+1++fn 就是连续 vv 的个数 .

假设第 i 个位置的答案是 A,第 i+1 个位置的答案是 B,那么

A=fi+fi+1+fi+2++fnB=fi+1+fi+2++fn

这时候我们得到的是 B=Afi,也是先算出第一个位置的答案用一个 for 循环就可以求出每个位置的 b 值了 .

还可以看 A=B+fi,这样从后往前 for,初始的位置就不需要再用一个 for 循环了 .

总共的时间复杂度为 O(n),可以 Accepted 了 . 记得开 long long

接下来就是简洁的代码,细节很多,要好好考虑:

const int N = 1919810;
string s;
int n, pre[N], suf[N];
int main()
{
	cin >> s; n = s.length(); s = "$" + s; 
	for (int i=1; i<n; i++) pre[i] = pre[i-1] + ((s[i] == 'v') && (s[i+1] == 'v'));
	for (int i=n-1; i>=1; i--) suf[i] = suf[i+1] + ((s[i] == 'v') && (s[i+1] == 'v'));
	ll ans = 0;
	for (int i=1; i<n; i++)
		if (s[i] == 'o') ans += 1ll * pre[i-1] * suf[i];
	printf("%lld\n", ans);
	return 0;
}

可以看出题面的表述相当自然易懂,而每一步的思维却都非常跳跃,思维量很大结果却很简洁,推导答案的形式不涉及很困难的算法,却又不仅限于结论,而是巧妙地结合了 OI 知识,启发选手独自研发题目所需要的算法,为良心出题人点赞!

posted @   yspm  阅读(52)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
😅​
点击右上角即可分享
微信分享提示