题目描述
机房来了新一届的学弟学妹,邪恶的chenzeyu97发现一位学弟与他同名,于是他当起了善良的学长233
“来来来,学弟,我考你道水题检验一下你的水平……”
一个栈内初始有n个红色和蓝色的小球,请你按照以下规则进行操作
-
只要栈顶的小球是红色的,将其取出,直到栈顶的球是蓝色
-
然后将栈顶的蓝球变成红色
- 最后放入若干个蓝球直到栈中的球数为n
以上3步骤为一次操作
如栈中都是红色球,则操作停止,请问几次操作后停止
chenzeyu97出完题发现他自己不能AC所以想请你帮忙
输入输出格式
输入格式:
第一行为一个整数n,表示栈的容量为n
第二行为一个字符串,第i个字符表示自顶向下的第i个球的颜色,R代表红色,B代表蓝色
输出格式:
一个整数表示操作数
输入输出样例
样例1: 3 RBR 样例2: 4 RBBR
样例1:2 样例2:6
说明
50%的数据,1<=n<=20
100%的数据,1<=n<=50
分析:直接模拟只有50分,正解肯定是有数学规律,那么设f[i]表示前i个球全部变成红色的最少次数,我们假设前i-1个已经是红球了,那么如果第i个是蓝球就一定要操作,否则可以不用操作。
我们可以用一次操作把前i-1个变成蓝球,把第i个变成红球,接下来用f[i-1]次操作把前i-1个蓝球变成红色球就好了.也就是说f[i] = f[i-1] + 1.
但是直接这样推得到的答案是不对的,因为我们求f[i-1]的时候可能之前根本就没有算过“f[i-1]”,因为我们只有在当前是蓝球的情况下才会递推下去,那么考虑全是蓝球的情况,可以得到f[i] = 2*f[i-1] + 1,把这个数列保存下来,在统计答案的时候遇到蓝球,ans就+=f[i] - f[i-1].
这道题不可能直接通过题目给的序列推得式子,只能根据特殊情况--全是蓝色的球来求得递推式,很多题目也是这样的,我们先考虑特殊情况,然后再往普通情况下转化.
数列操作问多少次操作成某个状态一般而言要么暴力要么有递推关系式,有的题目有贪心的方法,不过比较少见,在得到递推式之后一定要验证一下正确性.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <queue> using namespace std; char s[60]; int n,flag[60]; long long f[60],ans; int main() { scanf("%d", &n); scanf("%s", s + 1); for (int i = 1; i <= n; i++) if (s[i] == 'R') flag[i] = 1; else flag[i] = 0; for (int i = 1; i <= n; i++) f[i] = f[i - 1] * 2 + 1; for (int i = 1; i <= n; i++) if (!flag[i]) ans += f[i] - f[i - 1]; printf("%lld ", ans); return 0; }