【Codeforces 804B】找规律 | 思维 | 快速幂 | E

思维题第二发…

804B. Minimum number of steps

time limit per test: 1 seconds
memory limit per test: 256 megabytes
input: standard input
output: standard output

Tags:数学 思维 快速幂

题目描述(bba?满脑子都是 PPO…)

给定一个仅由 a a a b b b 组成的串。如果串中存在子串 a b ab ab,则将其置换成 b b a bba bba,持续到不含 a b ab ab 为止。

问一共置换了多少次( %   1 0 9 + 7 \%\ 10^9 + 7 % 109+7 )?



输入

仅一行。一个只含 a 、 b a、b ab 的字符串。

长度范围: 1 ≤ l e n ≤ 1 0 6 1 \le len \le 10^6 1len106



输出

一个整数,为置换次数( %   1 0 9 + 7 \%\ 10^9 + 7 % 109+7 )。



输入样例1

ab

输出样例

1


输入样例2

aab

输出样例

3



分析

咋回事?老老实实找规律吧。

会发现置换的顺序其实没有关系,但是每次置换都让 a a a 向右冒泡一格。

观察样例,再写个 a a a b aaab aaab 会发现得换 7 7 7 次,似乎就是 2 n − 1 2^n - 1 2n1



证明:

我们可以从左往右地对 a a a 进行替换。整个过程中我们总是让 a a a 聚在一起然后再一次性同时跨过某个 b b b

这样对原串中的每个 b b b 都可以独立地进行分析并且不会重复计数(考察每个 b b b 的时候它的前面都紧挨着数个连续的 a a a)。

这样对于每个 b b b,如果它前面有 n a n_a na a a a,就得有:

∑ i = 1 n a ( 1 2 i )   = =   1 × ( 1 − 2 n a ) 1 − 2   = =   2 n a − 1 \sum\limits_{i=1}^{n_a}(\frac{1}{2^i})\ ==\ \frac{1 \times (1-2^{n_a})}{1-2}\ ==\ 2^{n_a}-1 i=1na(2i1) == 121×(12na) == 2na1

这么多次置换(相邻的 a a a 1 1 1 次,相间的 a a a 2 2 2 次,以此类推…)



思路:

这就很简单啦。把串遍历一遍,遇见 a a a 的时候进行计数,遇见 b b b 的时候把 2 n a − 1 2^{n_a}-1 2na1 累加到 a n s ans ans 上即可。

(因为置换不改变 a a a 个数,所以不用模拟置换的全过程。轮到某个 b b b 时前面连续的 a a a 的个数就是原串中他前面的 a a a 的个数)



时间复杂度:
  • 外层遍历, O ( n ) O(n) O(n)
  • 内层做快速幂, O ( log ⁡ n ) O(\log n) O(logn)
  • 总时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)




AC代码

#include <stdio.h>

#define LL long long
#define PC putchar
template<typename T>void PRT(const T a){if(a<0){PC(45),PRT(-a);return;}if(a>=10)PRT(a/10);PC(a%10+48);}
template<typename T>void UPRT(const T a){if(a>=10)UPRT(a/10);PC(a%10+48);}

#define MOD 1000000007
LL QP(LL a, LL n){LL s=1;while(n){if(n&1)s=s*a%MOD;a=a*a%MOD;n>>=1;}return s;}

constexpr int ML(1e6+7);
char s[ML];

int main()
{
	scanf("%s", s);
	int cnt = 0;
	LL ans = 0;
	for (char *p=s; *p; ++p)
	{
		if (*p == 'a')
			++cnt;
		else
			ans += QP(2, cnt) - 1, ans %= MOD;
	}
	UPRT(ans);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值