zoukankan      html  css  js  c++  java
  • 【BZOJ1212】[HNOI2004]L语言

    【BZOJ1212】[HNOI2004]L语言

    题面

    bzoj

    洛谷

    题解

    其实可以不用AC自动机,但是最近在学就用了。。。

    先把自动机建好,然后我们考虑怎么做。

    设$vis[x]$表示文本串中$1-x$是否可以被表示出来

    然后暴跳$fail$

    设我们当前跳到了点$p$,在字符串的第$i$位

    若有以$p$结尾的字符串且$vis[i-dep[p]]$,就证明$vis[i]$可以被拼出来了

    好像做完了?然而并没有。

    因为类似于$abcba$这样的串也会被判成由$abc$和$cba$构成的

    所以我们要开一个差分数组看是否可以取到

    体作可以看代码理解

    代码

    #include <iostream> 
    #include <cstdio> 
    #include <cstdlib> 
    #include <cstring> 
    #include <cmath> 
    #include <algorithm>
    #include <queue> 
    using namespace std; 
    const int MAX_N = 2e6;
    const int MAX_M = 5000; 
    struct AC_Auto {
    	int c[MAX_M][26], fail[MAX_M], dep[MAX_M], cc[MAX_N], tot;
    	bool vis[MAX_N], End[MAX_M]; 
    	AC_Auto() : tot(0) { } 
    	void insert(char *s) { 
    		int o = 0; 
    		for (int i = 1, l = strlen(s + 1); i <= l; i++) { 
    			int son = s[i] - 'a'; 
    			if (!c[o][son]) c[o][son] = ++tot; 
    			o = c[o][son];
    			dep[o] = i; 
    		} 
    		End[o] = 1; 
    	} 
    	void build() { 
    		static queue<int> que; 
    		for (int i = 0; i < 26; i++) if (c[0][i]) que.push(c[0][i]), fail[c[0][i]] = 0; 
    		while (!que.empty()) { 
    			int o = que.front(); que.pop(); 
    			for (int i = 0; i < 26; i++)
    				if (c[o][i]) fail[c[o][i]] = c[fail[o]][i], que.push(c[o][i]);
    				else c[o][i] = c[fail[o]][i]; 
    		} 
    	} 
    	int query(char *s) {
    		memset(vis, 0, sizeof(vis)); 
    		memset(cc, 0, sizeof(cc)); 
    		vis[0] = 1;
    		int l = strlen(s + 1); 
    		for (int i = 1, o = 0; i <= l; i++) { 
    			o = c[o][s[i] - 'a']; 
    			for (int x = o; x; x = fail[x])
    				if (End[x] && vis[i - dep[x]]) {
    					vis[i] = 1; 
    					cc[i - dep[x] + 1]++;
    					cc[i + 1]--; 
    				} 
    		}
    		int res = 0; 
    		for (int i = 1, tot = 0; i <= l; i++) {
    			tot += cc[i]; 
    			if (tot) ++res; else break; 
    		}
    		return res; 
    	} 
    } ac;
    int N, M; char s[MAX_N]; 
    int main () {
    	scanf("%d%d", &N, &M); 
    	for (int i = 1; i <= N; i++) scanf("%s", s + 1), ac.insert(s); 
    	ac.build(); 
    	while (M--) {
    		scanf("%s", s + 1);
    		printf("%d
    ", ac.query(s)); 
    	} 
    	return 0; 
    } 
    
  • 相关阅读:
    hdu 1028 母函数 一个数有几种相加方式
    第m个全排列
    大数处理
    并查集
    KMP算法及KMP算法的应用(POJ2406)
    算法---分治法
    末学者笔记--NTP服务和DNS服务
    末学者笔记--NFS服务和DHCP服务讲解
    末学者笔记--SSHD服务及SCP用法
    末学者笔记——SAMBA服务、FTP服务讲解
  • 原文地址:https://www.cnblogs.com/heyujun/p/10241312.html
Copyright © 2011-2022 走看看