BZOJ1212 [HNOI2004]L语言
看到最长前缀想到Trie字典树
但此题是分段匹配(多个单词),于是想到二重循环枚举起点
记录\(mark_i\)表示能否通过单词匹配到\(i\),如果可以则记录答案并以该点为起点继续匹配
若匹配过程中发现之前单词的结尾(可用结尾标记判断),则令当前\(mark=1\)
注:\(1MB\approx10^6\)
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
bool bo[1000005];//1MB=1e6
int ch[1000005][30],n,m,tot = 1;
char str[1000005];
bool mark[1000005];//表示能通过多个单词匹配到i位置
inline void write(int s)
{
if(s < 0)
{
putchar('-');
s = -s;
write(s);
}
if(s > 9)
write(s % 10);
putchar(s % 10 + '0');
}
inline void Insert(char * s)//建Trie字典树
{
int u = 1,len = strlen(s + 1);
for(int i = 1;i <= len; ++i)
{
int c = s[i] - 'a';
if(!ch[u][c])
ch[u][c] = ++tot;
u = ch[u][c];
}
bo[u] = true;
}
inline void find(char * s)//匹配文章s
{
int ans,now = 1,len = strlen(s + 1);
memset(mark,0,sizeof mark);
mark[0] = 1;//0位置匹配根节点
for(int i = 0,k;i <= len; ++i)//从0开始!
{
if(!mark[i])//不能匹配到当前位置
continue;
else
ans = i;//记录答案
for(k = i + 1,now = 1;k <= len; ++k)
{
int c = s[k] - 'a';
now = ch[now][c];
if(!now)
break;
if(bo[now])//发现单词结尾
mark[k] = 1;
}
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin >> n >> m;
for(int i = 1;i <= n; ++i)
{
cin >> str + 1;
Insert(str);
}
for(int i = 1;i <= m; ++i)
{
cin >> str + 1;
find(str);
}
return 0;
}