[luogu2292][L语言]

题目链接

思路

这道题我用的是AC自动机的做法。
先把子串挂到trie树上,在单词结尾打标记的时候,标记的是当前单词的长度。然后去上面查询母串的时候,每查询到一个单词,就建立一条线段,这条线段的结尾位置是母串当前的位置,开始位置就是用当前位置减去这个单词的长度。
然后只要去判断,选出一些线段,使得这些线段紧挨着(既不相互覆盖,中间也不遗漏)从母串开始位置铺,能铺到的最远的地方。所以只需要一遍bfs就行了。

代码

/*
* @Author: wxyww
* @Date:   2018-12-17 08:38:38
* @Last Modified time: 2018-12-17 09:09:28
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<bitset>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const int N = 2000000 + 100;
ll read() {
   ll x=0,f=1;char c=getchar();
   while(c<'0'||c>'9') {
      if(c=='-') f=-1;
      c=getchar();
   }
   while(c>='0'&&c<='9') {
      x=x*10+c-'0';
      c=getchar();
   }
   return x*f;
}
int trie[1000][30],end[1000];
char s[30];
int tot;
void insert() {
   int len = strlen(s + 1);
   int now = 0;
   for(int i = 1;i <= len;++i) {
      int k = s[i] - 'a';
      if(!trie[now][k]) trie[now][k] = ++tot;
      now = trie[now][k];
   }
   end[now] = len;
}
struct node {
   int l,r;
}e[N];
int ejs;
int fail[N];
char S[N];
queue<int>q;
void build() {
   for(int i = 0;i < 26;++i) if(trie[0][i]) q.push(trie[0][i]);
   while(!q.empty()) {
      int u = q.front();q.pop();
      for(int i = 0;i < 26;++i) {
         if(trie[u][i]) fail[trie[u][i]] = trie[fail[u]][i],q.push(trie[u][i]);
         else trie[u][i] = trie[fail[u]][i];
      }
   }
}
vector<int>v[N];
void work() {
   int len = strlen(S + 1);
   ejs = 0;int now = 0;
   for(int i = 1;i <= len;++i) {
      now = trie[now][S[i] - 'a'];
      for(int j = now;j;j = fail[j]) {
         if(end[j]) e[++ejs].l = i - end[j] + 1,e[ejs].r = i;
      }
   }
}
int vis[N];
void bfs() {
   q.push(1);
   int ans = 0;
   for(int i = 1;i <= ejs;++i) v[e[i].l].push_back(i);
   memset(vis,0,sizeof(vis));
   while(!q.empty()) {
      int l = q.front();q.pop();
      int k = v[l].size();
      for(int i = 0;i < k;++i) {
         int z = v[l][i];
         if(vis[z]) continue;
         vis[z] = 1;
         q.push(e[z].r + 1);
         ans = max(ans,e[z].r);
      }
   }
   printf("%d\n",ans);
   int len = strlen(S + 1);
   for(int i = 1;i <= len;++i) v[i].clear();
}
int main() {
   int n = read(),m = read();
   for(int i = 1;i <= n;++i) {
      scanf("%s",s + 1);
      insert();
   }
   build();
   for(int i = 1;i <= m;++i) {
      scanf("%s",S + 1);
      work();
   bfs();
   }

   return 0;
}
全部评论

相关推荐

最近群里有很多同学找我看简历,问问题,主要就是集中在明年三月份的暑期,我暑期还能进大厂嘛?我接下来该怎么做?对于我来说,我对于双非找实习的一个暴论就是title永远大于业务,你在大厂随随便便做点慢SQL治理加个索引,可能就能影响几千人,在小厂你从零到一搭建的系统可能只有几十个人在使用,量级是不一样的。对双非来说,最难的就是约面,怎么才能被大厂约面试?首先这需要一点运气,另外你也需要好的实习带给你的背书。有很多双非的同学在一些外包小厂待了四五个月,这样的产出有什么用呢?工厂的可视化大屏业务很广泛?产出无疑是重要的,但是得当你的实习公司到了一定的档次之后,比如你想走后端,那么中厂后端和大厂测开的选择,你可以选择中厂后端(注意,这里的中厂也得是一些人都知道的,比如哈啰,得物,b站之类,不是说人数超过500就叫中厂),只有这个时候你再去好好关注你的产出,要不就无脑大厂就完了。很多双非同学的误区就在这里,找到一份实习之后,就认为自己达到了阶段性的任务,根本不再投递简历,也不再提升自己,玩了几个月之后,美其名曰沉淀产出,真正的好产出能有多少呢?而实际上双非同学的第一份实习大部分都是工厂外包和政府外包!根本无产出可写😡😡😡!到了最后才发现晚了,所以对双非同学来说,不要放过任何一个从小到中,从中到大的机会,你得先有好的平台与title之后再考虑你的产出!因为那样你才将将能过了HR初筛!我认识一个双非同学,从浪潮到海康,每一段都呆不久,因为他在不断的投递和提升自己,最后去了美团,这才是双非应该做的,而我相信大部分的双非同学,在找到浪潮的那一刻就再也不会看八股,写算法,也不会打开ssob了,这才是你跟别人的差距。
迷茫的大四🐶:我也这样认为,title永远第一,只有名气大,才有人愿意了解你的简历
双非本科求职如何逆袭
点赞 评论 收藏
分享
饿魔:没人说?我来牛美孩
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务