https://codeforces.com/contest/633/problem/C
题意:
一个密码,由很多单词分别进行操作后,连接而成。操作如下 :
先翻转,然后全部变为小写字母,最后消去单词间空格,连接成密码。 现给你一些单词和一个密码,将密码换成原来字典上的单词
思路:直接逆序将所有单词插入到字典树中,直接回朔法dfs,判断是否能以该字母作为结尾,然后继续判断下一单词是否存在
#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define fi first
#define se second
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
typedef pair<P, int> LP;
const ll inf = 0x3f3f3f3f;
const int N = 1e6 + 10;
const ll mod = 10007;
const int base=131;
tr1::unordered_map<ll,ll> mp;
ll n,m,id,x,y,k,q,cnt,flag;
ll num[1000000];//单词出现次数
ll tree[N][27];//tree[i][j]表示节点i的第j个儿子的节点编号
ll tot;//总结点数
string s;
int ans[N];
string t[N];
void ins(string str,int id)
{
int root=0;
int l=str.size();
for(int i=l-1;i>=0;i--)
{
str[i]=tolower(str[i]);//这里注意换小写
int id=str[i]-'a';
if(!tree[root][id]) tree[root][id]=++tot;
root=tree[root][id];
}
num[root]=id;//单词结尾标记下标
}
int dfs(int x)
{
if(x==n)
{
for(int i=1;i<=cnt;i++)
cout<<t[ans[i]]<<" ";
flag=1;
return 1;
}
if(flag) return 1;
int root=0;
for(int i=x;i<n;i++)//枚举每个字母作为结尾
{
int id=s[i]-'a';
root=tree[root][id];
if(!root) return 0;//如果该字母此路径上不存在 错误
if(num[root])//枚举结尾单词
{
ans[++cnt]=num[root];
if(dfs(i+1))
{
return 1;
}
cnt--;
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
cin>>s;
cin>>m;
for(int i=1;i<=m;i++)
{
cin>>t[i];
ins(t[i],i);
}
dfs(0);
}