题目大意:
给你一个由小写字母组成的字符串 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; }