题目
问题描述:
小U非常喜欢字符'R',并且定义字符串的权值为字符'R'的出现次数。现在她手上有一个长度为nn的字符串s,由字符'R'和'B'组成。她想知道,在所有长度为nn、仅由字符'R'和'B'组成的字符串中,字典序不小于字符串s的字符串的权值之和是多少。由于结果可能很大,答案需要对109+7109+7取模。
例如,字符串"RRBRB"的权值为 3,因为其中包含 3 个字符'R'。
样例如图:
先总览代码
我尽量详细解释:看到第一行:#include <bits/stdc++.h>
这是一个在某些编译器(尤其是GCC和Clang)中可用的头文件,它是一个包含了几乎所有标准库头文件的单行包含指令。这个头文件并不是C++标准的一部分,而是GCC编译器的一个扩展,用于方便开发者快速包含所有常用的标准库头文件。
1.计数函数:
这段代码定义了一个名为
countBits 的函数,它接受一个整数 n 作为参数,并返回一个整数。这个函数的目的是计算从1到 n 所有整数的二进制表示中1的总数。
下面是代码的逐行解释:
-
int countBits(int n) {:定义了一个名为countBits的函数,它返回一个整数,并且接受一个整数n作为参数。 -
vector<int> dp(n + 1, 0);:定义了一个动态数组(向量)dp,大小为n + 1,所有元素初始化为0。这个数组将用于存储从1到i的所有整数的二进制表示中1的总数。 -
for (int i = 1; i <= n; ++i) {:开始一个循环,从1开始,直到n。 -
dp[i] = dp[i >> 1] + (i & 1);:对于每个i,计算其二进制表示中1的个数。这里使用了两个技巧:i >> 1:将i右移一位,相当于除以2,用于递归地计算i/2的二进制中1的个数。i & 1:将i与1进行按位与操作,如果i是奇数,结果为1,否则为0。这用于计算i本身的最低位是否为1。
-
int sum = 0;:定义了一个整数变量sum并初始化为0,用于存储从1到n所有整数的二进制表示中1的总数。 -
for (int i = 1; i <= n; ++i) {:开始另一个循环,从1开始,直到n。 -
sum += dp[i];:将dp[i]的值加到sum上,累加每个整数的二进制表示中1的个数。 -
// cout<<n<<" "<<sum<<endl;:这是一个注释掉的代码行,如果取消注释,它将打印出n和sum的值,用于调试。 -
return sum;:函数返回sum,即从1到n所有整数的二进制表示中1的总数。 -
}:结束函数定义。
这个函数使用了动态规划(DP)的思想,通过递归地计算每个整数的二进制表示中1的个数,并将结果存储在 dp 数组中,从而避免了重复计算。这种方法的时间复杂度是O(n),因为每个整数只计算一次。
2. solution 函数
它接受两个参数:一个整数
n 和一个字符串 s。函数的目的是根据字符串 s 中的字符 'R' 来计算一个特定的值。
下面是代码的逐行解释:
int solution(int n, string s) {:定义了一个名为solution的函数,它返回一个整数,并且接受两个参数:一个整数n和一个字符串s。// write code here:这是一个注释,提示开发者在这里编写代码。int num = 0;:定义了一个整数变量num并初始化为0。for (int i = 0; i < n; i++) {:开始一个循环,从0开始,直到小于n(字符串s的长度)。num *= 2;:在每次循环中,将num的值乘以2。if (s[i] == 'R') {:检查字符串s中当前索引i的字符是否为 'R'。num += 1;:如果当前字符是 'R',则将num的值增加1。}:结束if语句和for循环。return countBits((1 << n) - 1) - countBits(num - 1);:函数返回两个countBits函数调用的结果之差。countBits函数(未在代码中定义)可能是用来计算一个整数的二进制表示中1的个数。这里计算的是(1 << n) - 1(即n位全为1的二进制数)的二进制中1的个数减去num - 1的二进制中1的个数。