CodeForces - 1084C The Fair Nut and String(有趣的题目)多解

题目大意:

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

你可能感兴趣的:(codeforces,victor的DP专练)