BZOJ4032: [HEOI2015]最短不公共子串

n<=2000的两个串,求四个问:

(1) A的一个最短的子串,它不是B的子串
(2) A的一个最短的子串,它不是B的子序列
(3) A的一个最短的子序列,它不是B的子串
(4) A的一个最短的子序列,它不是B的子序列
 
一开始??????嗯要识别子串和子序列需要俩东西:序列自动机和后缀自动机。
前两问:枚举A的起点直接在两个自动机里走即可。
后两问:
方法一:(x,y)表示A的序列自动机上第x位和B的后缀/序列自动机上第y位匹配上时的最短串。从两个根节点开始bfs一次即可。复杂度n*n*26,空间巨大。
方法二:只留一个状态y,把x当作一种转移途径,从左到右枚举A串字符,使B的自动机上所有和当前字符相同的转移路径进行一次转移。复杂度n*n。
  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 #include<algorithm>
  5 //#include<iostream>
  6 using namespace std;
  7 
  8 int n,m;
  9 #define maxn 4011
 10 char a[maxn],b[maxn];
 11 
 12 struct seAM
 13 {
 14     int ch[maxn][26],pre[maxn],last[26];
 15     seAM() {pre[1]=0; for (int i=0;i<26;i++) last[i]=1;}
 16     int idx(char c) {return c-'a';}
 17     void insert(char c,int p)
 18     {
 19         int id=idx(c);p++;
 20         pre[p]=last[id];
 21         for (int i=0;i<26;i++)
 22             for (int j=last[i];j && !ch[j][id];j=pre[j]) ch[j][id]=p;
 23         last[id]=p;
 24     }
 25 }sb;
 26 
 27 struct SAM
 28 {
 29     struct Node
 30     {
 31         int ch[26],pre,pos;
 32         Node() {memset(ch,0,sizeof(ch)); pre=0;}
 33     }a[maxn];
 34     int size,last,root;
 35     SAM() {root=1; a[1].pos=0; size=1; last=1;}
 36     int idx(char c) {return c-'a';}
 37     void insert(char c,int p)
 38     {
 39         int id=idx(c),x=++size;
 40         a[x].pos=p;
 41         int y=last;
 42         for (;y && !a[y].ch[id];y=a[y].pre) a[y].ch[id]=x;
 43         last=x;
 44         if (!y) a[x].pre=root;
 45         else if (a[a[y].ch[id]].pos==a[y].pos+1) a[x].pre=a[y].ch[id];
 46         else
 47         {
 48             int z=a[y].ch[id],w=++size;
 49             a[w]=a[z]; a[w].pos=a[y].pos+1;
 50             a[z].pre=a[x].pre=w;
 51             for (;y && a[y].ch[id]==z;y=a[y].pre) a[y].ch[id]=w;
 52         }
 53     }
 54 }sam;
 55 
 56 int f[maxn];
 57 int main()
 58 {
 59     scanf("%s%s",a+1,b+1);n=strlen(a+1);m=strlen(b+1);
 60     for (int i=1;i<=m;i++) sb.insert(b[i],i),sam.insert(b[i],i);
 61     int ans;
 62     
 63     ans=n+1;
 64     for (int i=1;i<=n;i++)
 65     {
 66         int p=sam.root,j;
 67         for (j=i;p && j<=n;j++) p=sam.a[p].ch[a[j]-'a'];
 68         if (!p) ans=min(ans,j-i);
 69     }
 70     if (ans>n) puts("-1");else printf("%d\n",ans);
 71     
 72     ans=n+1;
 73     for (int i=1;i<=n;i++)
 74     {
 75         int p=1,j;
 76         for (j=i;p && j<=n;j++) p=sb.ch[p][a[j]-'a'];
 77         if (!p) ans=min(ans,j-i);
 78     }
 79     if (ans>n) puts("-1");else printf("%d\n",ans);
 80     
 81     ans=n+1;
 82     memset(f,0x3f,sizeof(f));
 83     f[1]=0;
 84     for (int i=1;i<=n;i++)
 85         for (int j=sam.size;j>=1;j--)
 86         {
 87             int tmp;if (!(tmp=sam.a[j].ch[a[i]-'a'])) ans=min(ans,f[j]+1);
 88             else f[tmp]=min(f[tmp],f[j]+1);
 89         }
 90     if (ans>n) puts("-1");else printf("%d\n",ans);
 91     
 92     ans=n+1;
 93     memset(f,0x3f,sizeof(f));
 94     f[1]=0;
 95     for (int i=1;i<=n;i++)
 96         for (int j=m+1;j>=1;j--)
 97         {
 98             int tmp;if (!(tmp=sb.ch[j][a[i]-'a'])) ans=min(ans,f[j]+1);
 99             else f[tmp]=min(f[tmp],f[j]+1);
100         }
101     if (ans>n) puts("-1");else printf("%d\n",ans);
102     
103     return 0;
104 }
View Code

 

转载于:https://www.cnblogs.com/Blue233333/p/8010500.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的公寓报修管理系统,源码+数据库+毕业论文+视频演示 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本公寓报修管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此公寓报修管理系统利用当下成熟完善的Spring Boot框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的MySQL数据库进行程序开发。公寓报修管理系统有管理员,住户,维修人员。管理员可以管理住户信息和维修人员信息,可以审核维修人员的请假信息,住户可以申请维修,可以对维修结果评价,维修人员负责住户提交的维修信息,也可以请假。公寓报修管理系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。 关键词:公寓报修管理系统;Spring Boot框架;MySQL;自动化;VUE
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值