牛客小白月赛躲藏:
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述:
XHRlyb和她的小伙伴Cwbc在玩捉迷藏游戏。
Cwbc藏在多个不区分大小写的字符串中。
好奇的XHRlyb想知道,在每个字符串中Cwbc作为子序列分别出现了多少次。
由于Cwbc可能出现的次数过多,你只需要输出每个答案对2000120420010122取模后的结果。
聪明的你在仔细阅读题目后,一定可以顺利的解决这个问题!
输入描述:
输入数据有多行,每行有一个字符串。
输出描述:
输出数据应有多行,每行表示一个答案取模后的结果。
实例:
示例1
输入
Cwbc
输出
1
说明
Cwbc作为子序列仅出现了1次。
示例2
输入
acdcecfwgwhwibjbkblcmcnco
输出
81
说明
Cwbc作为子序列出现了34=81次。
题解:
很经典的dp 用dp[i][j]来表示前i个字符中 匹配的字符j个数 j这个维度是子序列的长度 这题中j的长度就为4 分别为1,2,3,4.
容易发现,每一个字符的状态都只从它前一个字符的状态转移过来,显然我们可以考虑使用滚动数组来优化空间开销。我们考虑去掉第一维的状态,只保留第二维的状态。那么转移方程就变为:
dp[1] = (dp[1] + (s[i] ==′ c′)) % Mod
dp2] = (dp[2] + (s[i] ==′ w′)∗dp[1]) % Mod
dp[3] = (dp[3] + (s[i] ==′ b′)∗dp[2]) % Mod
dp[4] = (dp[4] + (s[i] ==′ c′)∗dp[3]) % Mod
代码展示[c++ java]:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
string s ;
ll mod = 2000120420010122 ;
ll dp[10] ;
ll sum ;
//Cwbc
int main(){
while(cin >> s){
ll a = 0 , b = 0 , c = 0 , d = 0 ;
for(int i = s.size() - 1 ; i >= 0 ; i--){
if(s[i] == 'c' || s[i] == 'C'){
a = a + 1 ;
a = a % mod ;
d = d + c ;
d = d % mod ;
}
if(s[i] == 'w' || s[i] == 'W'){
c = c + b ;
c = c % mod ;
}
if(s[i] == 'b' || s[i] == 'B'){
b = a + b ;
b = b % mod ;
}
}
cout << d % mod << endl ;
}
return 0 ;
}
import java.util.Scanner;
public class 躲藏 {
public static void main(String[] args){
Scanner input = new Scanner(System.in);
while(input.hasNext()){
char[] ch = input.nextLine().toLowerCase().toCharArray();
long a = 0;
long b = 0;
long c = 0;
long d = 0;
for(int i=0;i<ch.length;i++) {
if(ch[i]=='c'){
a=(a+1);
d = (d+c)% 2000120420010122L;
}
else if(ch[i] == 'w')b=(a+b)% 2000120420010122L;
else if(ch[i] == 'b')c=(c+b)% 2000120420010122L;
}
System.out.println(d);
}
}
}