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

题目来源

https://codeforces.ml/contest/1426/problem/F

题意分析

  题目意思的大致可以描述为,给你一个串,该串只包括'a','b','c','?'四个字母,'?' 表示这一位可以填任何一个字母,问的是所有的情况下,即问号被替换成三个字母的所有情况下,其子串‘abc’的个数是多少?

思路分析

  第一眼就是dp,但是因为细节想了挺久的,记录一下整体的想法。
  能够影响答案个数的,是‘ab’子串,当它遇到一个‘c’字符时候,答案就变大了。那么我们假设前n个字符的‘ab’子串个数为dp[i],而会影响dp[i]数量的为‘a’字符。所以我们维护三个变量,分别为前一个位置‘ab’子串的个数(设为x)和前一个位置‘a’字符的个数(设为y)以及当前的答案(设为ans),然后分以下三种情况讨论:
    1. 当这一位的字符为‘a’的时候,三个变量只有y会发生变化。这里需要思考的是,‘a’字符的变化不只是单纯的+1,而是3k, k 为这个位置之前的‘?’字符的个数。

    2. 当这一位的字符为‘b’的时候,三个变量只有x会发生变化,增大了y。

    3. 当这一位的字符为‘c’的时候,三个变量只有ans在发生变化,增大了x。

    4. 当这一位的字符为‘?’的时候,三个变量都会发生变化,ans=ans*3+x;   x=3*x+y; y=3*y+3k; 这里需要注意的一个点是,当遇到一个‘?’字符的时候,最终字符的情况就会分裂出原来情况的三倍,所以不能够简单的按照某一个字母去想。

code

 1 #include <bits/stdc++.h>
 2 
 3 #define int long long
 4 using namespace std;
 5 const int maxn = 2e5 + 7;
 6 const int mod = 1e9 + 7;
 7 char ch[maxn];
 8 int dp[maxn];
 9 
10 int power(int a, int b, int c){
11     int ans = 1;
12     while (b){
13         if (b & 1) ans = ans * a % c;
14         b>>=1;
15         a = a * a % c;
16     }
17     return ans;
18 }
19 
20 signed main(){
21     int n; scanf("%lld", &n);
22     scanf("%s", ch);
23     int a = 0, b = 0, w = 0, num = 0;
24     int ans = 0;
25     for (int i=0; i<n; i++){
26         if (i) dp[i] = dp[i-1];
27         if (ch[i] == 'a') a += power(3, num, mod);
28         else if (ch[i] == 'b') dp[i] += a;
29         else if (ch[i] == 'c') ans += dp[i];
30         else if (ch[i] == '?'){
31             ans *= 3; ans += dp[i];
32             dp[i] *= 3; dp[i] += a;
33             a *= 3; a += power(3, num, mod);
34             num ++;
35         }
36         a %= mod; b %= mod; ans %= mod; dp[i] %= mod;
37 //           for (int j=0; j<n; j++) printf("%lld ", a);
38 //        printf("\n");
39     }
40     printf("%lld\n", ans);
41     return 0;
42 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值