题意:
将下面给的字符串转成莫斯电码,问完全由下面的字符串转化而成的莫斯电码一共有多少种情况。
解释样例:第一种为 ATTACK+DAWN ,第二种为 AT+TACK+DAWN 。
思路:
先用KMP求出每个小的字符串匹配串的结束位置,然后转化为一个邻接表,求出该邻接表,从1开始到lenT结束共有几条路径。
这里可以用dp来求解,dp公式比较简单,想想就推出来了。
dp[edge[i][k]]+=dp[i]
总结:
在写KMP循环求解结束位置的时候多写了一个条件, j<lenP 导致结果一直出不来,因为这样可能导致只算一次,而后面的模式串无法匹配到,下次一定要注意不要犯这样的错误了。
my code
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <string>
#include <vector>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int N = 1005;
string morse[] = {
".-", "-...", "-.-.", "-..",
".", "..-.", "--.", "....",
"..", ".---", "-.-", ".-..",
"--", "-.", "---", ".--.",
"--.-", ".-.", "...", "-",
"..-", "...-", ".--", "-..-",
"-.--", "--.."};
map<char, string> mp;
void getTable() {
for(char ch = 'A'; ch <= 'Z'; ch++)
mp[ch] = morse[ch-'A'];
}
vector<int> edge[N];
string tar, pat;
int lenT, lenP;
ll dp[N];
int jump[N];
void getNext() {
int j = 0, k = -1;
jump[0] = -1;
while(j < lenP) {
if(k == -1 || pat[j] == pat[k])
jump[++j] = ++k;
else k = jump[k];
}
}
void kmp() {
lenT = tar.size(), lenP = pat.size();
getNext();
int j = 0, k = 0;
while(j < lenT) {
if(k == -1 || tar[j] == pat[k]) {
j++, k++;
}else k = jump[k];
if(k == lenP) {
edge[j - lenP].push_back(j);
}
}
}
string trans(string str) {
string ret = "";
for(int i = 0; i < str.size(); i++)
ret += mp[str[i]];
return ret;
}
void init() {
memset(dp, 0, sizeof(dp));
lenT = tar.size();
for(int i = 0; i <= lenT; i++) {
edge[i].clear();
}
}
int main() {
getTable();
int T, n;
scanf("%d", &T);
while(T--) {
init();
cin >> tar;
scanf("%d", &n);
string str;
for(int i = 0; i < n; i++) {
cin >> str;
pat = trans(str);
kmp();
}
dp[0] = 1;
for(int i = 0; i < lenT; i++) {
for(int k = 0; k < edge[i].size(); k++)
dp[edge[i][k]] += dp[i];
}
printf("%lld\n", dp[lenT]);
if(T) puts("");
}
return 0;
}