Codeforces Round #674 (Div. 3) F. Number of Subsequences

F. Number of Subsequences
Description

You are given a string s consisting of lowercase Latin letters “a”, “b” and “c” and question marks “?”.

Let the number of question marks in the string s be k. Let’s replace each question mark with one of the letters “a”, “b” and “c”. Here we can obtain all 3k possible strings consisting only of letters “a”, “b” and “c”. For example, if s=“ac?b?c” then we can obtain the following strings: [“acabac”, “acabbc”, “acabcc”, “acbbac”, “acbbbc”, “acbbcc”, “accbac”, “accbbc”, “accbcc”].

Your task is to count the total number of subsequences “abc” in all resulting strings. Since the answer can be very large, print it modulo 109+7.

A subsequence of the string t is such a sequence that can be derived from the string t after removing some (possibly, zero) number of letters without changing the order of remaining letters. For example, the string “baacbc” contains two subsequences “abc” — a subsequence consisting of letters at positions (2,5,6) and a subsequence consisting of letters at positions (3,5,6).

Input

The first line of the input contains one integer n (3≤n≤200000) — the length of s.

The second line of the input contains the string s of length n consisting of lowercase Latin letters “a”, “b” and “c” and question marks"?".

Output

Print the total number of subsequences “abc” in all strings you can obtain if you replace all question marks with letters “a”, “b” and “c”, modulo 109+7.

Examples
input
6
ac?b?c
outputCopy
24
input
7
???????
output
2835
input
9
cccbbbaaa
output
0
input
5
a???c
output
46
Note

In the first example, we can obtain 9 strings:

“acabac” — there are 2 subsequences “abc”,
“acabbc” — there are 4 subsequences “abc”,
“acabcc” — there are 4 subsequences “abc”,
“acbbac” — there are 2 subsequences “abc”,
“acbbbc” — there are 3 subsequences “abc”,
“acbbcc” — there are 4 subsequences “abc”,
“accbac” — there is 1 subsequence “abc”,
“accbbc” — there are 2 subsequences “abc”,
“accbcc” — there are 2 subsequences “abc”.
So, there are 2+4+4+2+3+4+1+2+2=24 subsequences “abc” in total.

题意: 第一行输入一个数字n,第二行输入一串字符串,该串字符串只由a、b、c以及英文的“?”组成。"?" 可以变化成任意一个字母变成a、b、c其中的任意一个字母,现在要求在这个字符串中有多少个子串是“abc”,由?任意变化后的所有的子串。

题解: 我们设一数组dp[i][1]代表前i个字符中子列’a‘的个数;dp[i][2]代表前i个字符中子列’ab‘的个数;dp[i][3]代表前i个字符中子列’abc‘的个数。那么最终答案一定是dp[n][3]。

考虑‘?’对子列的影响,因为‘?‘可以代表a、b、c中任意一个字符,所有到了第i个字符时如果前面有x个’?’,那么此处可以组成的字符串的形式就有 3 x 3^x 3x种。如果不考虑‘?'的话,碰到一个’a‘,dp[i][1]就需要加一,如果考虑到’?'的影响,dp[i][1]就得加上 3 x 3^x 3x

考虑用‘?'分别表示这三个字母:

’?‘代表‘a’:前面仍然有dp[i-1][1]个‘a’的子列,仍然有dp[i-1][2]个‘ab’的子列,仍然有dp[i-1][3]个‘abc’,算上第i个字符(即‘?’)这时候,多了 3 x 3^x 3x个a。

’?‘代表’b‘:前面仍然有dp[i-1][1]个‘a’的子列,仍然有dp[i-1][2]个‘ab’的子列,仍然有dp[i-1][3]个‘abc’,算上第i个字符(即‘?’)这时候,多了dp[i-1][1]个ab。

‘?‘代表’c’:前面仍然有dp[i-1][1]个‘a’的子列,仍然有dp[i-1][2]个‘ab’的子列,仍然有dp[i-1][3]个‘abc’,算上第i个字符(即‘?’)这时候,多了dp[i-1][2]个abc。

通过上式状态转移方程,我们可以写出一下代码:

c++ AC 代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 10;
ll dp[maxn][4];
ll base = 1;
char s[maxn];

int main()
{
	int n;
	scanf("%d%s",&n,s+1);
	for(int i=1;i<=n;i++)
	{
		if(s[i]=='a')
		{
			dp[i][1] = (dp[i-1][1] + base) % mod;
			dp[i][2] = dp[i-1][2];
			dp[i][3] = dp[i-1][3];
		}
		else if(s[i]=='b')
		{
			dp[i][1] = dp[i-1][1];
			dp[i][2] = (dp[i-1][1] + dp[i-1][2]) % mod;
			dp[i][3] = dp[i-1][3];
		}
		else if(s[i]=='c')
		{
			dp[i][1] = dp[i-1][1];
			dp[i][2] = dp[i-1][2];
			dp[i][3] = (dp[i-1][2] + dp[i-1][3]) % mod;
		}
		else if(s[i] == '?')
		{
			dp[i][1] = (dp[i-1][1] * 3 + base) % mod;
			dp[i][2] = (dp[i-1][2] * 3 + dp[i-1][1]) % mod;
			dp[i][3] = (dp[i-1][3] * 3 + dp[i-1][2]) % mod;
			base = base * 3 % mod;
		}
	}
	printf("%lld\n",dp[n][3]);
	// system("pause");
	return 0;
}

文章参考自:https://blog.csdn.net/qq_45458915/article/details/108859787

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值