原题地址:http://codeforces.com/contest/633/problem/C
题意:给你m个单词的词典和一句话,这句话中的每个单词都来自字典,字典中的每一个单词重复可用,把这句话所有大写字母变成小写字母,然后反转单词去掉空格,要求你恢复这句话。
思路:这题做法好巧妙.我们先对单词进行预处理,存在 里面.因为要还原整个字符串,但是我们又不知道究竟单词断在哪里.所以我们就现需要确定单词断在哪里对于这个问题我们使用 来判断, 表示在i前面有一个单词,其哈希值是 .最后倒着输出就行了.
#include <bits/stdc++.h>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define MOD 1e9+7
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define CLR(x,y) memset((x),y,sizeof(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 1e5 + 5;
string s, a;
int n, m;
ull dp[maxn];//dp[i]表示在i前面有单词,且其哈希值是dp[i]
unordered_map<ull, string>mp;
void dfs(int len) {
if(len == 0) return;
string str = mp[dp[len]];
dfs(len - str.size());
cout << str << " ";
}
int main() {
ios::sync_with_stdio(false);
cin >> n >> s >> m;
for(int i = 1; i <= m; ++i) {
cin >> a;
string b = a;
int len = a.size();
ull tmp = 0;
for(int j = 0; j < len; ++j) {
tmp = tmp * seed + tolower(a[j]);
}
mp[tmp] = b;
}
CLR(dp, -1);
dp[0] = 0;
for(int i = 0; i < n; ++i) {
ull tmp = 0;
for(int j = i; j >= 0; --j) {
tmp = tmp * seed + s[j];
if(dp[j] != -1 && mp.count(tmp)) {
dp[i + 1] = tmp;
break;
}
}
}
dfs(n);
return 0;
}