【备战秋招】每日一题:2023.04.20-蚂蚁暑期实习-第二题-RB字符串

题目内容

塔子哥是一个程序员,他最近在处理一些字符串相关的任务。他喜欢 R 字符,因为在某些任务中,这个字符通常表示“正确”的结果。另一方面,他不喜欢 B 字符,因为在某些任务中,这个字符通常表示“错误”的结果。

为了解决他的任务,塔子哥定义了字符串的权值为字符串中 R 字符的出现次数。例如,对于字符串 BBRBRB,它的权值为 2 2 2,因为其中有 2 2 2R 字符。

现在,塔子哥面临一个问题,他有一个长度为 n n n 的字符串 s s s,它仅由 RB 组成。他想知道,长度为 n n n 的仅由 RB 组成的字符串中,字典序不小于 s s s 的字符串的权值之和是多少?因此,他需要编写一个程序来解决这个问题。

由于答案可能太大,需要对 1 0 9 + 7 10^9+7 109+7 取模后再输出。

输入描述

输入第一行为一个整数 n n n ,表示字符串的长度。

输入第二行为一个长度为 n n n 的字符串 s s s ,字符串中元素组成仅为 RB

2 ≤ n ≤ 1 0 5 2\le n \le 10^5 2n105

输出描述

输出一个整数,代表长度为 n n n 的、字典序不小于 s s s 的字符串权值之和。

样例

输入

3
RBR

输出

7

样例解释

共有 3 3 3 个字符串符合要求:
RBR 的权值为 2 2 2

RRB 的权值为 2 2 2

RRR 的权值为 3 3 3

思路:数学题 or 数位dp

step1:转换题意

R R R 看作1, B B B看作0.原字符串变成一个二进制数 x x x.那么题目意思转化为:输出值域 [ x , 2 ∣ x ∣ − 1 ] [x,2^{|x|}-1] [x,2x1] 内每个数的二进制位1的个数的总和。

step2:数学

一个直观的想法就是直接上数位dp。那么就是一道非常裸的数位dp。但是这里给出另一种做法:

由于 y ≥ x y \geq x yx , 那么从二进制位上来观察, y y y x x x一定是有一段公共前缀(这个前缀可以为空)。并且在某一个位置 i i i , 满足 x i = 0 , y i = 1 x_i = 0 , y_i = 1 xi=0,yi=1 . 之后的 [ i + 1 , n ] [i+1,n] [i+1,n] 这些位置上,对 y y y 没有限制.

所以我们枚举这个"变化点" i ∈ [ 1 , n + 1 ]   a n d   x i = 0 i \in [1 , n + 1]\ and\ x_i = 0 i[1,n+1] and xi=0 ( i = n + 1 i=n+1 i=n+1代表 y = x y=x y=x) . 对于一个固定的 i i i , 答案就是 前缀中 1 1 1的个数 * 2 n − i − 1 2^{n-i-1} 2ni1 加上 [ 0 , 2 n − i − 1 − 1 ] [0,2^{n-i-1}-1] [0,2ni11] 中1的个数.

第一部分好算,前缀和一下,乘一下。第二部分考虑每一位的贡献也能够发现答案就是 2 n − i − 2 ∗ ( n − i − 1 ) 2^{n-i-2}*(n-i-1) 2ni2(ni1)

代码

python

mod = 10**9 + 7
p2 = [1]
# 求[0,2^{x}-1] 中1的个数 , 公式如上
def cnt1 (x):
	if x == 0:
		return 0
	return p2[x - 1] * x % mod
n = int(input())
a = list(input())
# 预处理2^i 在mod意义下的值
for i in range(n + 5):
	p2.append(p2[-1] * 2 % mod)
# 将RB字符串 转化为 01字符串
b = [0] * n
for i in range(n):
	if a[i] == 'R':
		b[i] = 1
	else:
		b[i] = 0
# 求前缀中1的个数
p = [0]
for x in b:
	p.append(p[-1] + x)
# 枚举 变化点 i
ans = p[-1]
for i in range(n):
	if b[i] == 0:
        # 答案的第二部分
		ans = (ans + cnt1(n - i - 1)) % mod
        # 答案的第一部分
		ans = (ans + p2[n - i - 1] * (p[i + 1] + 1) % mod) % mod
print(ans)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

塔子哥学算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值