【AtCoder】ABC104 We Love ABC

  • 题目
  • 题目大意
  • 分析
    • 只有ABC的情况
    • 加上?后的情况
  • 代码

题目

beta传送门

题目大意

对于一个字符串 T T ,规定它的ABC number是这样的一个三元组的个数: (i,j,k) ( i , j , k ) 1i<j<k|T| 1 ≤ i < j < k ≤ | T | )使得 Ti= T i = A Tj= T j = B Tk= T k = C

现在给你一个只含有ABC Q Q ?的字符串 S S ,你需要用ABC把这些?填满,显然一共有 3Q 3 Q 种填法。对于每种填法,求出此时字符串的ABC number,输出这些ABC number的和模 109+7 10 9 + 7

分析

数学大法好。

只有ABC的情况

如果给你一个只有ABC的字符串 S S ,怎么用 O(n) O ( n ) 的方法算出它的ABC number
(提示:从字符串中的B入手,组合计数。)


对于字符串中的B,显然它前面的所有A它后面的所有C能够随便配对,如果第 i i 个字符前面 A[i] A [ 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,后面有 2 2 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对应的三元组个数加起来就是答案了,即:

1i|S|Si=B(A[i]×C[i]) ∑ 1 ≤ i ≤ | S | S i = B ( A [ i ] × C [ i ] )

加上?后的情况

发现?可以变成B,而?变成AC时在其他情况下已经讨论了,不能重复计算。所以直接把?当成BB也当成B,一模一样的计算就行了。

代码

#include
#include

#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);
}

你可能感兴趣的:(----------,数学,----------,#,数论,#,组合数学,数论,数学,AtCoder,组合数学)