USACO最长前缀(trie练习题)

来源:互联网 发布:李刚疯狂java讲义 编辑:程序博客网 时间:2024/06/08 14:33

点我

题目描述

在生物学中,一些生物的结构是用包含其要素的大写字母序列来表示的。生物学家对于把长的序列分解成较短的序列(即元素)很感兴趣。

如果一个集合 P 中的元素可以通过串联(元素可以重复使用,相当于 Pascal 中的 “+” 运算符)组成一个序列 S ,那么我们认为序列 S 可以分解为 P 中的元素。元素不一定要全部出现(如下例中BBC就没有出现)。举个例子,序列 ABABACABAAB 可以分解为下面集合中的元素:

{A, AB, BA, CA, BBC}

序列 S 的前面 K 个字符称作 S 中长度为 K 的前缀。设计一个程序,输入一个元素集合以及一个大写字母序列 S ,设S'是序列S的最长前缀,使其可以分解为给出的集合P中的元素,求S'的长度K。

输入输出格式

输入格式:

输入数据的开头包括 1..200 个元素(长度为 1..10 )组成的集合,用连续的以空格分开的字符串表示。字母全部是大写,数据可能不止一行。元素集合结束的标志是一个只包含一个 “.” 的行。集合中的元素没有重复。接着是大写字母序列 S ,长度为 1..200,000 ,用一行或者多行的字符串来表示,每行不超过 76 个字符。换行符并不是序列 S 的一部分。

输出格式:

只有一行,输出一个整数,表示 S 符合条件的前缀的最大长度。

输入输出样例

输入样例#1:
A AB BA CA BBC.ABABACABAABC
输出样例#1:
11

说明

翻译来自NOCOW

USACO 2.3

代码

#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>#include<ctime>#define For(i,a,b) for(register int i=a;i<=b;++i)#define Rep(i,a,b) for(register int i=a;i>=b;--i)const int maxx=1e5+7;using namespace std;int be[2000001],ne[2000001],to[2000001],e=0,cnt=0;void add(int x, int y){//链式前向星存trie    to[++e]=y;    ne[e]=be[x];    be[x]=e;}struct node{    bool end; char x;}llz[2000001];bool f[2000001];char x[1200],s[2000010];void insert(char *s){//trie的插入    int i,u=0,len=strlen(s);    For(v,0,len-1){        bool flag=0;        for(i=be[u];i;i=ne[i]){            int go=to[i];            if(llz[go].x==s[v]){                u=go;                flag=1;                break;            }        }        if(!flag) {add(u,++cnt); u=cnt; llz[u].x=s[v];}//        if(v==len-1) llz[u].end=1;//标记结束位置    }}bool find(int l,int r){//trie的查询    int i,u=0,flag;    For(v,l,r){        flag=0;        for(i=be[u];i;i=ne[i]){            int go=to[i];            if(llz[go].x==s[v]){                u=go;                flag=1;                break;            }        }        if(!flag)return 0;        if(v==r)            if(llz[u].end==1){                return 1;            }            else return 0;    }}int main(){#ifndef ONLINE_JUDGE    freopen("input.in", "r", stdin);    freopen("output.out", "w", stdout);#endif    int i,j,l,ans=0,M=0;    while(1){//对每个单词集合建trie        scanf("%s",x);        if(x[0]=='.') break;i=strlen(x);M=max(i,M);//找到最长的长度,下面会有用的        insert(x);    }    scanf("%s",s+1);    while(scanf("%s",x)!=EOF) strcat(s+1,x);//读入s串    l=strlen(s+1);    f[0]=1;//f[x]表示在x位置之前所有的字母能匹配    For(i,1,l){        for(j=i-1;j>=0;j--)            if(f[j] && find(j+1,i)){//如果j以前能全部匹配,并且j+1到i能匹配,i位置也能全匹配                f[i]=1;                ans=i;                break;            }if(j<0 && i-ans>M) break;    //剪枝,如果当前比最长集合还要长的位置没匹配成功,后面也不能匹配上        }    printf("%d\n",ans);    return 0;}


code by  罗旅洲

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手机检测不到u盾怎么办 农行有k宝怎么办信用卡 k米怎么点不了怎么办 c1驾照被扣3分怎么办 淘宝账号被黑了怎么办 淘宝卖家号虚假交易违规怎么办 扣扣申诉成功后怎么办 微信二维码收款异常怎么办 国际包裹被退回去了怎么办 京东账号手机号换了怎么办 换手机号了淘宝账号怎么办 qq登录id密码忘记怎么办 iphone商店密码忘记了怎么办 淘宝账号被限制登入怎么办 手机换号码了qq登不上怎么办 换手机了qq登不上怎么办 微信帐号和密码错误怎么办 高考生忘记登录密码怎么办 高考生登录密码丢了怎么办 高考志愿登录密码忘了怎么办 电视声音和画面不同步怎么办 苹果5s不能开机怎么办 红米手机老是闪退怎么办 苹果7plus打字卡怎么办 手机总是出现无响应怎么办 手机淘宝怎么打不开了怎么办 淘宝买东西卖家不同意退货怎么办 苹果自带浏览器不能上网怎么办 淘宝账号买不了东西怎么办 支付宝被限制登录怎么办 微信登录不上 钱怎么办 淘宝账号买家权限被限制怎么办 淘宝中店新品打不开怎么办 旺旺号被限制有退款怎么办 登陆微信收不到验证码怎么办 淘宝店注册成功后怎么办 充电宝掉进水里怎么办 空光盘读不出来怎么办 苹果8plus丢了怎么办 苹果8plus掉了怎么办 淘宝账户被限制使用怎么办