zoukankan      html  css  js  c++  java
  • bzoj4032/luoguP4112 [HEOI2015]最短不公共子串(后缀自动机+序列自动机上dp)

    bzoj4032/luoguP4112 [HEOI2015]最短不公共子串(后缀自动机+序列自动机上dp)

    bzoj Luogu

    题解时间

    给两个小写字母串 $ A $ , $ B $ ,请你计算:

    (1) $ A $ 的一个最短的子串,它不是 $ B $ 的子串

    (2) $ A $ 的一个最短的子串,它不是 $ B $ 的子序列

    (3) $ A $ 的一个最短的子序列,它不是 $ B $ 的子串

    (4) $ A $ 的一个最短的子序列,它不是 $ B $ 的子序列

    水题四合一,一题更比四题sao

    首先由于都是要从 $ A $ 中找,所以按照套路是把 $ A $ 在 $ B $ 上匹配

    所以先构建出 $ B $ 的SAM和序列自动机。

    序列自动机:就是一个 $ next[i][ch] $ 数组表示第 $ i $ 位往后第一个出现字符 $ ch $ 的位置,纯粹用来匹配的。

    (1) 直接以 $ A $ 每一位为起点在 $ B $ 的SAM上暴力匹配,只要失配就更新答案然后跳出。

    (2) 换成在序列自动机上。

    (3) $ dp[i][j] $ 表示 $ A $ 的前 $ i $ 个字符形成的子序列在 $ B $ 的SAM上匹配到了 $ j $ 位置,此时形成的最短子序列长度,这是个挺经典的dp了。

    (4) 换成在序列自动机上。

    #include<bits/stdc++.h>
    using namespace std;
    namespace RKK
    {
    const int N=2011,inf=0x3f3f3f3f;
    int n1;char s1[N];
    int n2;char s2[N];
    struct remilia{int tranc[26],len,pre;};
    struct sakuya
    {
    	remilia s[N<<1];
    	int fin,size;
    	sakuya(){fin=size=1;}
    	void ins(int ch)
    	{
    		int npx,npy,lpx,lpy;
    		npx=++size;
    		s[npx].len=s[fin].len+1;
    		for(lpx=fin;lpx&&!s[lpx].tranc[ch];lpx=s[lpx].pre) s[lpx].tranc[ch]=npx;
    		if(!lpx) s[npx].pre=1;
    		else
    		{
    			lpy=s[lpx].tranc[ch];
    			if(s[lpy].len==s[lpx].len+1) s[npx].pre=lpy;
    			else
    			{
    				npy=++size;
    				s[npy]=s[lpy];
    				s[npy].len=s[lpx].len+1;
    				s[lpy].pre=s[npx].pre=npy;
    				while(s[lpx].tranc[ch]==lpy)
    				{
    					s[lpx].tranc[ch]=npy;
    					lpx=s[lpx].pre;
    				}
    			}
    		}
    		fin=npx;
    	}
    	void insert(char *str,int sl)
    	{
    		for(int i=1;i<=sl;i++)
    			ins(str[i]-'a');
    	}
    }sam;
    struct flandre
    {
    	int ne[N][26],tmp[26];
    	void insert(char *s,int sl)
    	{
    		for(int i=sl;i>=0;i--)
    			memcpy(ne[i],tmp,104),tmp[s[i]-'a']=i;
    	}
    }sem;
    void solve1()
    {
    	int ans=inf;
    	for(int sp=1;sp<=n1;sp++)
    	{
    		int px=1;
    		for(int i=sp;i<=n1;i++)
    		{
    			if(!sam.s[px].tranc[s1[i]-'a']){ans=min(ans,i-sp+1);break;}
    			px=sam.s[px].tranc[s1[i]-'a'];
    		}
    	}
    	printf("%d
    ",ans==inf?-1:ans);
    }
    void solve2()
    {
    	int ans=inf;
    	for(int sp=1;sp<=n1;sp++)
    	{
    		int px=0;
    		for(int i=sp;i<=n1;i++)
    		{
    			if(!sem.ne[px][s1[i]-'a']){ans=min(ans,i-sp+1);break;}
    			px=sem.ne[px][s1[i]-'a'];
    		}
    	}
    	printf("%d
    ",ans==inf?-1:ans);
    }
    int dp[N<<1];
    void solve3()
    {
    	int ans=inf;
    	memset(dp,0x3f,sizeof(dp));
    	dp[1]=0;
    	for(int i=1;i<=n1;i++)
    	{
    		for(int x=sam.size;x;x--)
    		{
    			if(sam.s[x].tranc[s1[i]-'a']) dp[sam.s[x].tranc[s1[i]-'a']]=min(dp[sam.s[x].tranc[s1[i]-'a']],dp[x]+1);
    			else ans=min(ans,dp[x]+1);
    		}
    	}
    	printf("%d
    ",ans==inf?-1:ans);
    }
    void solve4()
    {
    	int ans=inf;
    	memset(dp,0x3f,sizeof(dp));
    	dp[0]=0;
    	for(int i=1;i<=n1;i++)
    	{
    		for(int x=n2;x>=0;x--)
    		{
    			if(!sem.ne[x][s1[i]-'a']) ans=min(ans,dp[x]+1);
    			else dp[sem.ne[x][s1[i]-'a']]=min(dp[sem.ne[x][s1[i]-'a']],dp[x]+1);
    		}
    	}
    	printf("%d
    ",ans==inf?-1:ans);
    }
    int Iris()
    {
    	scanf("%s%s",s1+1,s2+1),n1=strlen(s1+1),n2=strlen(s2+1);
    	sam.insert(s2,n2),sem.insert(s2,n2);
    	solve1(),solve2(),solve3(),solve4();
    	return 0;
    }
    }
    int main(){return RKK::Iris();}
    
  • 相关阅读:
    [VueJS + Typescript] Decouple Dependencies Using IoC Containers in Vue with TypeScript and InversifyJS
    便利店选址
    spoj 1811 Longest Common Substring (后缀自动机)
    sharepoint 2013 根据网站模版创建网站,并赋值网站权限 create a site by custom site template
    一则 ORA-00471 处理方法
    好端端的项目重新运行的时候却不行了!!!
    C语言指针和数组知识总结(下)
    Java EE登陆界面生成随机数防止恶意注册或者登录
    ASP.NET获取上传图片的大小
    Not able to reset SmartRF04DD
  • 原文地址:https://www.cnblogs.com/rikurika/p/12079153.html
Copyright © 2011-2022 走看看