UVAlive - 5792 Diccionário Portuñol (Trie)
2015-07-09 11:41
246 查看
转自:cxlove
题意:有两个字符串集合,从第一个集合中取某个串的非空前缀,从第二个集合中取某个串的非空后缀,拼接成一个串,问有多少个不同的新串。
思路:首先把第一个集合中的串加入到Trie中,然后就可以枚举前缀了,然后就是统计后缀,麻烦的是可能出现重复的。
当我们按长度枚举前缀的时候,可以考虑如果后缀的前缀出现在前缀的后继中,那便不用考虑,后面总会统计到。
这样的话,其实只要比较第一个字母。
如果当前结点P表示一个前缀串,那么如果p -> next[i]为空,说明前缀中不含字母i为后继,那么我们就可以统计以i开头的后缀了。否则总能在p -> next[i]为前缀中统计到。
有一点需要注意的是,如果 p -> next[i]便是我们最终的串,即以p 为前缀时,后缀只有一个字母的话,那就不能把这一个字母拉入到前缀中,因为后缀是非空的。所以再处理下end[i],表示是否存在以单个字母i为后缀的。
至于统计以i开头的不重复后缀的话,可以反向加入到Trie中统计。
题意:有两个字符串集合,从第一个集合中取某个串的非空前缀,从第二个集合中取某个串的非空后缀,拼接成一个串,问有多少个不同的新串。
思路:首先把第一个集合中的串加入到Trie中,然后就可以枚举前缀了,然后就是统计后缀,麻烦的是可能出现重复的。
当我们按长度枚举前缀的时候,可以考虑如果后缀的前缀出现在前缀的后继中,那便不用考虑,后面总会统计到。
这样的话,其实只要比较第一个字母。
如果当前结点P表示一个前缀串,那么如果p -> next[i]为空,说明前缀中不含字母i为后继,那么我们就可以统计以i开头的后缀了。否则总能在p -> next[i]为前缀中统计到。
有一点需要注意的是,如果 p -> next[i]便是我们最终的串,即以p 为前缀时,后缀只有一个字母的话,那就不能把这一个字母拉入到前缀中,因为后缀是非空的。所以再处理下end[i],表示是否存在以单个字母i为后缀的。
至于统计以i开头的不重复后缀的话,可以反向加入到Trie中统计。
[code]#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<vector> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #include<algorithm> using namespace std; typedef long long LL; const int maxn=100010; const int maxm=1010; const int SIGMA_SIZE=26; int P,S; char a[maxm][maxm],b[maxm][maxm]; int tail[maxn]; int cnt[30]; LL ans; struct Trie { int ch[maxn][SIGMA_SIZE]; int val[maxn]; int sz; void clear(){memset(ch[0],0,sizeof(ch[0]));sz=1;} int idx(char x){return x-'a';} void insert(char *s) { int u=0; for(int i=0;s[i];i++) { int c=idx(s[i]); if(!ch[u][c]) { memset(ch[sz],0,sizeof(ch[sz])); val[sz]=0; ch[u][c]=sz++; } u=ch[u][c]; } val[u]=1; } void cal(int u) { for(int i=0;i<SIGMA_SIZE;i++) { if(ch[u][i]) { cnt[i]++; cal(ch[u][i]); } } } void solve(int u) { for(int i=0;i<SIGMA_SIZE;i++) { if(!ch[u][i]) { if(u) ans+=cnt[i]; } else { if(u&&tail[i])ans++; solve(ch[u][i]); } } } }prefix,suffix; int main() { while(scanf("%d%d",&P,&S)!=EOF,P||S) { prefix.clear(); suffix.clear(); memset(cnt,0,sizeof(cnt)); memset(tail,0,sizeof(tail)); for(int i=0;i<P;i++) { scanf("%s",a[i]); prefix.insert(a[i]); } for(int i=0;i<S;i++) { scanf("%s",b[i]); reverse(b[i],b[i]+strlen(b[i])); tail[b[i][0]-'a']=1; suffix.insert(b[i]); } ans=0; suffix.cal(0); prefix.solve(0); cout<<ans<<endl; } return 0; }
相关文章推荐
- Android两种 旋转Bitmap方法
- 【剑指offer】删除字符也出现在一个字符串
- BZOJ3924 [Zjoi2015]幻想乡战略游戏
- java反射机制实例解析
- Windows命令行
- arm-none-eabi-gcc编译器的安装和相关配置
- Json与数组
- 简历就该简而有力!
- 如何快速定位不小心暴露到全局的变量
- linux的mkdir命令
- YUM、RPM 与APT 、DPKG 常用等价命令
- Linux 多线程编程实例
- 图像的特征提取都有哪些算法
- java 软件 设置session超时(失效)的三种方式
- iOS 自动登录,登录过程中一直显示加载页
- ini文件的手动修改 一定要用notePad++等,而不要用操作系统自带的notepad.txt
- java基础入门-对象流与序列化
- java基础入门-对象流与序列化
- applet使用实践
- linux内核动态加载模块