题目链接:https://www.nowcoder.com/acm/contest/87/B
第一眼看以为是kmp,然后仔细一看是子序列,再看数据范围,暴力的话肯定会超时,所以这道题需要用动态规划来写,令 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同一个位置有且仅有一个字符,不难发现转移方程间是不会相互影响的。因此,省去第一维的状态
是正确的。
AC代码:
#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;
}