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 }