zoukankan      html  css  js  c++  java
  • BZOJ4032 [HEOI2015]最短不公共子串 【后缀自动机 + 序列自动机 + dp】

    题目链接

    BZOJ4032

    题解

    首先膜(hb)
    空手切神题
    一问(hash),二问枚举
    三问(trie)树,四问(dp)
    南二巨佬神(hb)
    空手吊打自动机
    (orz orz orz orz orz orz orz)

    咳。说正解
    要处理子串,直接搬上后缀自动机
    要处理子序列,直接搬上序列自动机【雾】

    何为序列自动机##

    序列自动机其实很简单,就是具有识别所有子序列功能的自动机
    建机原理及过程及其简单,只需要从后往前扫一遍,对每一个位置建立一个节点,该节点的各个边连向最晚出现的对应的字符对应的节点
    只需记录下每个字符最晚出现的节点就可以(O(n|s|))建机了 【(|s|)为字符集大小】
    代码实现:

    struct LAM{
    	int ch[maxn][26],last[26],cnt;
    	void ins(int x){
    		int p = ++cnt;
    		for (int i = 0; i < 26; i++)
    			ch[p][i] = last[i];
    		last[x] = p;
    	}
    	void init(){
    		for (int i = 0; i < 26; i++)
    			ch[1][i] = last[i];
    	}
    }lam;
    ......
        lam.cnt = 1;
        for (int i = len; i; i--) lam.ins(s[i] - 'a');
        lam.init();
    

    第一、二问##

    只需枚举(A)子串的起点,然后看看能在自动机中走多远即可

    第三、四问##

    (A)的子序列有关,就上(dp)
    (f[i][j])表示(A)的前(i)个字符形成的所有子序列匹配到自动机(j)号节点的最短长度
    如果(i)不选

    [f[i][j] = f[i - 1][j] ]

    如果(i)被选,那么枚举是从哪一个节点转移来的
    设上一个节点为(u)

    [f[i][j] = min{f[i - 1][u] + 1} ]

    【注意这里是枚举(u)

    答案即为(f[len][0])(0)表示空,即不匹配】

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<map>
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define mp(a,b) make_pair<int,int>(a,b)
    #define cls(s) memset(s,0,sizeof(s))
    #define cp pair<int,int>
    #define LL long long int
    using namespace std;
    const int maxn = 4005,maxm = 100005,INF = 0x3f3f3f3f;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    struct SAM{
    	int ch[maxn][26],pre[maxn],step[maxn],last,cnt;
    	void ins(int x){
    		int p = last,np = ++cnt; step[np] = step[p] + 1; last = np;
    		while (p && !ch[p][x]) ch[p][x] = np,p = pre[p];
    		if (!p) pre[np] = 1;
    		else {
    			int q = ch[p][x];
    			if (step[q] == step[p] + 1) pre[np] = q;
    			else {
    				int nq = ++cnt; step[nq] = step[p] + 1;
    				for (int i = 0; i < 26; i++) ch[nq][i] = ch[q][i];
    				pre[nq] = pre[q]; pre[np] = pre[q] = nq;
    				while (ch[p][x] == q) ch[p][x] = nq,p = pre[p];
    			}
    		}
    	}
    }sam;
    struct LAM{
    	int ch[maxn][26],last[26],cnt;
    	void ins(int x){
    		int p = ++cnt;
    		for (int i = 0; i < 26; i++)
    			ch[p][i] = last[i];
    		last[x] = p;
    	}
    	void init(){
    		for (int i = 0; i < 26; i++)
    			ch[1][i] = last[i];
    	}
    }lam;
    char A[maxn],B[maxn];
    int lena,lenb;
    void solve1(){
    	int ans = INF;
    	for (int i = 1,j; i <= lena; i++){
    		int u = 1,cnt = 0;
    		for (j = i; j <= lena; j++){
    			++cnt;
    			if (!sam.ch[u][A[j] - 'a']) break;
    			u = sam.ch[u][A[j] - 'a'];
    		}
    		if (j <= lena) ans = min(ans,cnt);
    	}
    	if (ans == INF) puts("-1");
    	else printf("%d
    ",ans);
    }
    void solve2(){
    	int ans = INF;
    	for (int i = 1,j; i <= lena; i++){
    		int u = 1,cnt = 0;
    		for (j = i; j <= lena; j++){
    			++cnt;
    			if (!lam.ch[u][A[j] - 'a']) break;
    			u = lam.ch[u][A[j] - 'a'];
    		}
    		if (j <= lena) ans = min(ans,cnt);
    	}
    	if (ans == INF) puts("-1");
    	else printf("%d
    ",ans);
    }
    int f[2005][maxn];
    void solve3(){
    	memset(f,INF,sizeof(f));
    	f[0][1] = 0;
    	for (int i = 1; i <= lena; i++){
    		for (int j = 1; j <= sam.cnt; j++) f[i][j] = min(f[i][j],f[i - 1][j]);
    		for (int j = 1; j <= sam.cnt; j++){
    			int to = sam.ch[j][A[i] - 'a'];
    			f[i][to] = min(f[i][to],min(f[i - 1][to],f[i - 1][j] + 1));
    		}
    	}
    	if (f[lena][0] == INF) puts("-1");
    	else printf("%d
    ",f[lena][0]);
    }
    void solve4(){
    	memset(f,INF,sizeof(f));
    	f[0][1] = 0;
    	for (int i = 1; i <= lena; i++){
    		for (int j = 1; j <= lam.cnt; j++) f[i][j] = min(f[i][j],f[i - 1][j]);
    		for (int j = 1; j <= lam.cnt; j++){
    			int to = lam.ch[j][A[i] - 'a'];
    			f[i][to] = min(f[i][to],min(f[i - 1][to],f[i - 1][j] + 1));
    		}
    	}
    	if (f[lena][0] == INF) puts("-1");
    	else printf("%d
    ",f[lena][0]);
    }
    int main(){
    	scanf("%s",A + 1); lena = strlen(A + 1);
    	scanf("%s",B + 1); lenb = strlen(B + 1);
    	sam.last = sam.cnt = 1; lam.cnt = 1;
    	for (int i = 1; i <= lenb; i++) sam.ins(B[i] - 'a');
    	for (int i = lenb; i; i--) lam.ins(B[i] - 'a');
    	lam.init();
    	solve1();
    	solve2();
    	solve3();
    	solve4();
    	return 0;
    }
    
    
  • 相关阅读:
    (转)Spring Boot 2 (五):Docker Compose + Spring Boot + Nginx + Mysql 实践
    (转)Spring Boot 2 (四):使用 Docker 部署 Spring Boot
    (转)Spring Boot 2 (三):Spring Boot 开源软件都有哪些?
    (转)Spring Boot 2 (二):Spring Boot 2 尝鲜-动态 Banner
    (转)Spring Boot 2(一):【重磅】Spring Boot 2.0权威发布
    环境变量和用户变量有什么区别?
    记录一下,关于错误提示:could not find a part of path “X:”的解决办法
    日积月累:ScrollView嵌套ListView只显示一行
    android PopupWindow实现从底部弹出或滑出选择菜单或窗口
    WCF 配置文件中的MaxStringContentLength & MaxReceivedMessageSize
  • 原文地址:https://www.cnblogs.com/Mychael/p/9039976.html
Copyright © 2011-2022 走看看