Codeforces Round #674 (Div. 3)

Codeforces Round #674 (Div. 3)

F. Number of Subsequences

题意:

给你一个字符串只有abc和?其中?可以换成abc问有多少个abc子串。

题解:

直接枚举b用\(lsum[i]\)表示前i个字符中 a 的个数,$ rsum[i]$表示第i个数到第n个中c字符的个数

那么每次枚举个b 答案就加上 \(lsum[i] * rsum[i]\);

那 ?怎么办呢

我们可以用 \(lcnt[i],rcnt[i]\) 与上面一样分别表示前缀?与后缀?的个数。

当我枚举的第\(i\)字母b的时候答案就是:

$lsun[i - 1] * rsum[i + 1] * 3 ^ {lcnt[i - 1] }*3 ^{rcnt[i + 1]} $

$lcnt[i - 1] * rsum[i + 1] * 3 ^{lcnt[i - 1] - 1} * 3 ^ {rcnt[i + 1]} $

$ rcnt[i + 1] * lsum[i - 1] * 3^{rcnt[i + 1] - 1} * 3 ^ {lcnt[i - 1]} $

$lcnt[i - 1] * rcnt[i + 1] * 3 ^ {lcnt[i - 1] - 1} * 3 ^ {rcnt[i - 1] - 1} $

答案就是这四个公式的值相加。

当枚举到问好是可以把问号看成b就和上面的公式一样了。

#include<bits/stdc++.h>
using namespace std;

const int N = 2e5 + 7;

typedef long long ll;

char s[N];

int n;

const ll mod = 1e9 + 7;

ll dp[200], fn[N], lsum[N], rsum[N], lcnt[N], rcnt[N];

void solve() {
    cin >> n >> (s + 1);

    fn[0] = 1;
    for (int i = 1; i <= n; i++) {
        fn[i] = fn[i - 1] * 3 % mod;
        if (s[i] == 'a') {
            lsum[i] = (lsum[i - 1] + 1) % mod;
            lcnt[i] = lcnt[i - 1];
        } else if (s[i] == '?') {
            lsum[i] = lsum[i - 1] ;
            lcnt[i] = lcnt[i - 1] + 1;
        } else {
            lsum[i] = lsum[i - 1];
            lcnt[i] = lcnt[i - 1];
        }
    }

    for (int i = n; i; i--) {
        if (s[i] == 'c') {
            rsum[i] = (rsum[i + 1] + 1) % mod;
            rcnt[i] = rcnt[i + 1];
        } else if (s[i] == '?') {
            rsum[i] = rsum[i + 1];
            rcnt[i] = rcnt[i + 1] + 1;
        } else {
            rsum[i] = rsum[i + 1];
            rcnt[i] = rcnt[i + 1];
        }
    }

    ll ans = 0;

    for (int i = 1; i <= n; i++) {
        if (s[i] == 'b' || s[i] == '?') {
            ll cat = lsum[i - 1] * rsum[i + 1] % mod;
            cat = cat * fn[lcnt[i - 1]] % mod;
            cat = cat * fn[rcnt[i + 1]] % mod;
            ll cn = lcnt[i - 1] * rsum[i + 1] % mod;
            cn = cn * fn[rcnt[i + 1]] % mod;
            if (lcnt[i - 1] - 1 >= 0)
                cn = cn * fn[lcnt[i - 1] - 1] % mod;
            ll ct = lcnt[i - 1] * rcnt[i + 1] % mod;
            if (lcnt[i - 1] - 1 >= 0)
                ct = ct * fn[lcnt[i - 1] - 1] % mod;
            if (rcnt[i + 1] - 1 >= 0)
                ct = ct * fn[rcnt[i + 1] - 1] % mod;
            ll cd = rcnt[i + 1] * lsum[i - 1] % mod;
            cd = cd * fn[lcnt[i - 1]] % mod;
            if (rcnt[i + 1] - 1 >= 0)
                cd = cd * fn[rcnt[i + 1] - 1] % mod;
            ans = (ans + cat + cn + ct + cd) % mod;
        } 
    }

    cout << ans << endl;


    

}


int main() {
    ios::sync_with_stdio(0);
    int t = 1;
    while (t--) {
        solve();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值