题目
题目大意
对于一个字符串
T
T
,规定它的ABC number是这样的一个三元组的个数:(
1≤i<j<k≤|T|
1
≤
i
<
j
<
k
≤
|
T
|
)使得
Ti=
T
i
=
A
,
Tj=
T
j
=
B
且
Tk=
T
k
=
C
。
现在给你一个只含有A
、B
、C
和
Q
Q
个?
的字符串,你需要用A
、B
或C
把这些?
填满,显然一共有
3Q
3
Q
种填法。对于每种填法,求出此时字符串的ABC number,输出这些ABC number的和模
109+7
10
9
+
7
。
分析
数学大法好。
只有ABC的情况
如果给你一个只有A
、B
、C
的字符串
S
S
,怎么用的方法算出它的ABC number?
(提示:从字符串中的B
入手,组合计数。)
对于字符串中的B
,显然它前面的所有A
它后面的所有C
能够随便配对,如果第
i
i
个字符前面有个A
,后面有
C[i]
C
[
i
]
个C
。如果
S[i]
S
[
i
]
是B
,则包含
S[i]
S
[
i
]
的三元组共有
A[i]×C[i]
A
[
i
]
×
C
[
i
]
个。
例如:ABCACA
,对于唯一的一个B
来说,它前面有
1
1
个A
,后面有个C
,则前面的一个A
,加上当前的B
,可以和右面任何一个C
配对。所以ABC number的三元组有:
(i,j,k)=(1,2,3)
(
i
,
j
,
k
)
=
(
1
,
2
,
3
)
或
(1,2,5)
(
1
,
2
,
5
)
,共
1×2=2
1
×
2
=
2
个。
把每个B
对应的三元组个数加起来就是答案了,即:
加上?后的情况
发现?
可以变成B
,而?
变成A
和C
时在其他情况下已经讨论了,不能重复计算。所以直接把?
当成B
,B
也当成B
,一模一样的计算就行了。
代码
#include<cstdio>
#include<cstring>
#define MAXN 1000000
#define MOD 1000000007
char str[MAXN+5];
long long Pow[MAXN+5];
long long A[MAXN+5],C[MAXN+5],M[MAXN+5],N[MAXN+5];
int main(){
Pow[0]=1;
for(int i=1;i<=MAXN;i++)//初始化3的幂
Pow[i]=Pow[i-1]*3%MOD;
scanf("%s",str+1);
int len=strlen(str+1);
for(int i=1;i<=len;i++){
A[i]=A[i-1]+(str[i]=='A');
M[i]=M[i-1]+(str[i]=='?');
}
for(int i=len;i>=1;i--){
C[i]=C[i+1]+(str[i]=='C');
N[i]=N[i+1]+(str[i]=='?');
}//计算前后缀和
long long Ans=0;
for(int i=1;i<=len;i++){
if(str[i]=='B'||str[i]=='?'){//问号当成B
Ans=(Ans+
A[i]*C[i]*Pow[M[i-1]%MOD+N[i+1]]%MOD+
A[i]*N[i+1]%MOD*Pow[M[i-1]+N[i+1]-1]%MOD+
C[i]*M[i-1]%MOD*Pow[M[i-1]+N[i+1]-1]%MOD+
Pow[M[i-1]+N[i+1]-2]*M[i-1]%MOD*N[i+1])%MOD;
//几种情况
}
}
printf("%lld",Ans);
}