zoukankan      html  css  js  c++  java
  • 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();
        }
    }
    
    
    
  • 相关阅读:
    移动端h5实现拍照上传图片并预览&webuploader
    移动端实现上拉加载更多(使用dropload.js vs js)
    实用的移动端日历选择插件
    string.replace替换
    js与native的交互
    div实现返回符,倒三角,椭圆+小知识收集
    js返回一组日期中最近连续的天数
    javascript 事件冒泡和事件代理
    微信小程序DEMO——面包旅行的代码
    微信小程序使用 iconfont
  • 原文地址:https://www.cnblogs.com/BOZHAO/p/13747452.html
Copyright © 2011-2022 走看看