牛客小白月赛3 B 躲藏【动态规划/字符串出现cwbc子序列多少次】

链接:https://www.nowcoder.com/acm/contest/87/B
来源:牛客网

XHRlyb和她的小伙伴Cwbc在玩捉迷藏游戏
Cwbc藏在多个不区分大小写的字符串中。
好奇的XHRlyb想知道,在每个字符串中Cwbc作为子序列分别出现了多少次
由于Cwbc可能出现的次数过多,你只需要输出每个答案对2000120420010122取模后的结果。
聪明的你在仔细阅读题目后,一定可以顺利的解决这个问题!

输入描述:

输入数据有多行,每行有一个字符串。

输出描述:

输出数据应有多行,每行表示一个答案取模后的结果。
示例1

输入

Cwbc

输出

1

说明

Cwbc作为子序列仅出现了1次。
示例2

输入

acdcecfwgwhwibjbkblcmcnco

输出

81

备注:

每行字符串长度不超过2×10^5
,字符串总长度不超过10^6

【分析】:

这道题需要用动态规划来写,令 f[i][j],(j = 1,2,3,4) 表示前 i 个字符中,匹配了字符串”cwbc” 的前多少位,那么有转移方程:

                f[i][1] = (f[i−1][1] + (s[i] ==′ c′)) % Mod 

                f[i][2] = (f[i−1][2] + (s[i] ==′ w′)∗f[i−1][1]) % Mod 

                f[i][3] = (f[i−1][3] + (s[i] ==′ b′)∗f[i−1][2]) % Mod 

                f[i][4] = (f[i−1][4] + (s[i] ==′ c′)∗f[i−1][3]) % Mod

但是数组的开小大概需要 35MB 左右,会超过内存限制,所以还需要优化一下。
容易发现,每一个字符的状态都只从它前一个字符的状态转移过来,显然我们可以考虑使用滚动数组来优化空间开销。我们考虑去掉第一维的状态,只保留第二维的状态。那么转移方程就变为: f[
1] = (f[1] + (s[i] ==′ c′)) % Mod f[2] = (f[2] + (s[i] ==′ w′)∗f[1]) % Mod f[3] = (f[3] + (s[i] ==′ b′)∗f[2]) % Mod f[4] = (f[4] + (s[i] ==′ c′)∗f[3]) % Mod 同一个位置有且仅有一个字符,不难发现转移方程间是不会相互影响的。因此,省去第一维的状态是正确的。

【代码】:

#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <string>  
#define ll long long  
#define mod 2000120420010122  
using namespace std;  
string str;  
ll dp[5];  
  
int main()  
{  
  while(cin>>str){  
    int len = str.length();  
    memset(dp,0,sizeof(dp));  
    for(int i=0;i<len;i++){  
      str[i] = tolower(str[i]);  
      dp[1] = (dp[1] + (str[i] == 'c')) % mod;  
      dp[2] = (dp[2] + (str[i] == 'w') * dp[1]) % mod;  
      dp[3] = (dp[3] + (str[i] == 'b') * dp[2]) % mod;  
      dp[4] = (dp[4] + (str[i] == 'c') * dp[3]) % mod;  
    }  
    cout<<dp[4]<<endl;  
  }  
  return 0;  
}  
原文地址:https://www.cnblogs.com/Roni-i/p/9038943.html