题目大意:
给你一个由小写字母组成的字符串 s ,让你找一种序列:
1、对于任意一个 i ,使得 s[ p[ i ] ] == ‘a’
2、对于任意一个 i ,存在 p[ i ] < j < p[i + 1],且s[ p[ i ] ] == ‘b’
求这种序列有多少个,答案 mod 1e9
解法一: 数学 + 思维
思路:把字符串换成这样aabaaabaabaa(有多个b就把它缩为一个),相当于有若干个b把a分成了若干块,这样转变成数学问题,对于每个块的大小ai,我都有ai+1种选法,答案乘以ai+1即可,算完之后ans-1就是真正的答案,为什么要减一,因为每块都可以不选,那么有一种非法情况是所有块都不选,所以要减一。
注意细节
#include<bits/stdc++.h>
using namespace std;
//string s[210];
//bool vis[110];
typedef long long ll;
const int maxn = 3e6 + 5;
const int mod = 1e9 + 7;
char s[maxn];
int main(){
cin >> s ;
int n = strlen(s);
ll ans = 1,res = 1;
for(int i = 0 ; i < n ; i++){
if(s[i] == 'a')res ++;
else if(s[i] == 'b'){
ans = ans * res % mod , res = 1;
}
}
ans = ans * res % mod;
ans = (ans - 1 + mod) % mod;
cout << ans << endl;
return 0;
}
解法二:思维
解法就是每段a的情况相乘,对于一段长度为sum的’a’我们有sum+1种操作,因为可以不挑选这一段的’a’,在最后-1就是排除掉所有的’a’都不挑选的情况。
#include<bits/stdc++.h>
#define ll long long
const int mod = 1e9 + 7;
using namespace std;
int main()
{
string str;
ll ans = 0;
cin>>str;
str += 'b';
int len = str.length();
ans = 1;
ll num1 = 1;
for(int i = 0; i < len; i++){
if(str[i] == 'a') num1++;
else if(str[i] == 'b'){
ans = ans * num1 % mod;
num1 = 1;
}
}
ans -= 1;
cout << ans << endl;
}
解法三 :DP
首先预处理字符串 S ,使得串中不存在除 a 、b 意外的字母且任意两个 b 不相邻,然后定义一个 last 变量存上一个 b 位置之前有多少序列,然后递推 dp:dp[ i ] = dp[ i - 1] + last + 1
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char a[100005], s[100005];
ll dp[100005] = {0}, p = 0;
int main()
{
ll i;
scanf("%s", s + 1);
int len = strlen(s + 1);
a[p] = '*';
for(i = 1; i <= len; i++)
{
if(s[i] == 'a')a[++p] = s[i];
else if(s[i] == 'b' && a[p] != 'b')a[++p] = s[i];
}
ll last = 0;
for(i = 1; i <= p; i++)
{
if(a[i] == 'a')dp[i] = dp[i - 1] + last + 1;
else last = dp[i - 1], dp[i] = dp[i - 1];
dp[i] %= 1000000007;
}
printf("%lld\n", dp[p]);
return 0;
}