BZOJ 1212 && Luogu 2292 [HNOI 2004] L语言
刚学 Trie 碰到这题差点懵逼
表示加了个 DP 我差点就不会了
主要讲一下 DP 的思路
令 F[i] == 1 表示以第 i 个字符(从 0 开始)结尾的字符串能被理解
同理,F[i] == 0 表示不能理解
当满足 F[j] == 1 且以 F[j+1] 开头,以 F[i] 结尾的单词在 Trie 内
就把 F[i] 置为 1
最后只要输出一个最大的 i 使得 F[i] == 1 即可
(蒟蒻专属暴力思路,好想又好写,但奇慢无比,在 Luogu 上第十个点 TLE,幸亏有 O2 这种神奇的东西)
代码
#include<bits/stdc++.h> using namespace std; int cnt,f[1050000]; char a[11],s0[1050000]; queue<int>q; struct tree{ // Trie int fail,end,vis[26]; }ac[220]; inline void build(char s[]){ // 建 Trie int l=strlen(s),now=0; for(int i=0;i<l;i++){ int ch=s[i]-'a'; // 优化:少算 2 次减法 if(!ac[now].vis[ch]) ac[now].vis[ch]=++cnt; now=ac[now].vis[ch]; } ac[now].end=1; // 标记单词末尾 } inline bool query(int l,int r){ // 查询以 l 和 r 为两端的单词是否在 Trie 内 int u=0; for(int i=l;i<=r;i++){ int ch=s0[i]-'a'; if(!ac[u].vis[ch]) return 0; // 节点不存在则返回 False u=ac[u].vis[ch]; } return ac[u].end; } int main(){ int n,m; scanf("%d%d",&n,&m); while(n--){ scanf("%s",a); build(a); } while(m--){ scanf("%s",s0); int l=strlen(s0),ans=0; for(int i=0;i<l;i++) f[i]=0; for(int i=0;i<l;i++){ for(int j=max(i-10,-1);j<=i;j++) // 单词长度最大为 10,所以 DP 前 10 个字符 if((j==-1||f[j])&&query(j+1,i)){ // 字符串下标从 0 开始,所以把 DP 最小值设为 -1 f[i]=1; ans=i+1; // 下标为 i 的字符是第 i+1 个 break; } if(i-9>ans) break; // 长于单词长度后立即跳出 } printf("%d\n",ans); } return 0; }
By The_Seventh
2017-12-29 08:06:39