【ybtoj】【字典树】单词拼接
题意
E. 1.单词拼接
题目描述
给定由一些单词组成的词典。
一个单词是特殊的,当且仅当它能由词典里的两个单词拼接而成。
求词典里特殊的单词数。
输入格式
一行一个字符串,表示词典里的一个单词。每个字符串由小写字母组成,每个字符串按字典序排列,每个字符串只会出现一次。
输出格式
一行一个字符串,按字典序输出所有特殊的单词。
样例
样例输入
a ahat hat hatword hziee word
样例输出
ahat hatword
题解
两种方法
方法一:把每个串先都插入字典树里,之后暴力枚举每一个串的前半部分和后半部分,如果都能前后两部分都能在字典树中找到,那说明这个字符串是特殊的
方法二:把每个串正反(正反串记为S1,S2)分别插入两个字典树(记为A,B),同时记录正串和反串能被完整字符覆盖的前缀,如果∃ i,使得 S1[ i ]==S2[ len-i ],就说明原串是特殊的
Tips:
- 我第一次知道还可以在while(scanf)外面输出
while(scanf("%s",s+1)!=EOF)
{
...
}
for(int i=1;i<=n;i++) printf..
- 这题数据范围给错了,要开 5e4,RE了好久才发现
代码
单词拆分
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f,N = 50010;
int n,tot=1;
char s[N][33];
int trie[N<<5][30],ans,ed[N<<5];
void insert(int id)
{
int p=1,len=strlen(s[id]+1);
for(int i=1;i<=len;i++)
{
int ch=s[id][i]-'a';
if(!trie[p][ch]) trie[p][ch]=++tot;
p=trie[p][ch];
}
ed[p]++;
}
int find(int id,int l,int r)
{
int p=1;
for(int i=l;i<=r;i++)
{
int ch=s[id][i]-'a';
if(!trie[p][ch]) return 0;
p=trie[p][ch];
}
return ed[p];
}
int main()
{
int now=1;
while(scanf("%s",s[now]+1)!=EOF)
{
insert(now);
now++;
}
for(int i=1;i<=now-1;i++)
{
int len=strlen(s[i]+1);
//printf("len=%d\n",len);
for(int k=1;k<len;k++)
if(find(i,1,k)&&find(i,k+1,len))
{
printf("%s\n",s[i]+1);
break;
}
}
return 0;
}