zoukankan      html  css  js  c++  java
  • Luogu P3966 [TJOI2013]单词

    题目链接 (Click) (Here)

    本题(AC)自动机写法的正解之一是(Fail)树上跑(DP)

    (AC)自动机是(Trie)树和(Fail)树共存的结构,前者可以方便地处理前缀问题,而在后者中,一个节点的子节点,代表以当前字符串为后缀的所有字符串节点(根节点外向(Fail)树)。我们最初给每个串的所有前缀计数(+1),后期统计时,在该前缀的所有后缀上((Fail)树上的祖先节点上),将其自身答案累加上去,就是总共出现的次数。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1000010;
    
    struct AC_Auto {
    	int top, sta[N];
    	long long sum[N];
    	int cnt, ch[N][26], pre[N], fail[N];
    
    	AC_Auto () {
    		cnt = top = 0;
    		memset (ch, 0, sizeof (ch));
    		memset (sum, 0, sizeof (sum));
    		memset (pre, 0, sizeof (pre));
    		memset (fail, 0, sizeof (fail));
    	}
    
    	void add_str (char *s) {
    		int l = strlen (s), now = 0;
    		for (int i = 0; i < l; ++i) {
    			if (!ch[now][s[i] - 'a']) {
    				ch[now][s[i] - 'a'] = ++cnt;
    			}
    			pre[ch[now][s[i] - 'a']] = now;
    			now = ch[now][s[i] - 'a'];
    			sum[now]++;
    		}
    		sta[++top] = now;
    	}
    
    	queue <int> q;
    	
    	void build () {
    		for (int i = 0; i < 26; ++i) {
    			if (ch[0][i]) {
    				q.push (ch[0][i]);
    			}
    		}
    		while (!q.empty ()) {
    			int u = q.front (); q.pop ();
    			for (int i = 0; i < 26; ++i) {
    				if (ch[u][i]) {
    					q.push (ch[u][i]);
    					fail[ch[u][i]] = ch[fail[u]][i];
    				} else {
    					ch[u][i] = ch[fail[u]][i];
    				}
    			}
    		}
    	}
    
    	int _cnt, head[N];
    
    	struct edge {
    		int nxt, to;
    	}e[N];
    
    	void add_edge (int from, int to) {
    		e[++_cnt].nxt = head[from];
    		e[_cnt].to = to;
    		head[from] = _cnt;
    	} 
    
    	void dp (int u) {
    		for (int i = head[u]; ~i; i = e[i].nxt) {
    			dp (e[i].to);
    			sum[u] += sum[e[i].to];
    		}
    	}
    	
    	void get_ans () {
    		_cnt = 0;
    		memset (head, -1, sizeof (head));
    		for (int i = 1; i <= cnt; ++i) {
    			add_edge (fail[i], i);
    		}
    		dp (0);
    		for (int i = 1; i <= top; ++i) {
    			cout << sum[sta[i]] << endl;
    		}
    	}
    	
    	
    	
    	
    }AC;
    
    int n; char s[N];
    
    int main () {
    	cin >> n;
    	for (int i = 1; i <= n; ++i) {
    		scanf ("%s", s);
    		AC.add_str (s);
    	}
    	AC.build ();
    	AC.get_ans ();
    }
    
    

    (UPD:)新增了后缀数组(+ST)(+)倍增写法

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 2000010;
    
    char tmp[N];
    int n, len, ban = 'z', s[N], id[N], sa[N], tp[N], rk[N], _rk[N], bin[N], _len[N], height[N];
    
    void get_height (int n) {
    	int k = 0;
    	for (int i = 1; i <= n; ++i) {
    		if (k != 0) --k;
    		int j = sa[rk[i] - 1];
    		while (s[i + k] == s[j + k]) ++k;
    		height[rk[i]] = k;
    	}
    }
    
    void base_sort (int n, int m) {
    	for (int i = 0; i <= m; ++i) bin[i] = 0;
    	for (int i = 1; i <= n; ++i) bin[rk[tp[i]]]++;
    	for (int i = 1; i <= m; ++i) bin[i] += bin[i - 1];
    	for (int i = n; i >= 1; --i) sa[bin[rk[tp[i]]]--] = tp[i];
    }
    
    void suffix_sort (int n, int m) {
    	for (int i = 1; i <= n; ++i) {
    		tp[i] = i, rk[i] = s[i];
    	}
    	base_sort (n, m);
    	for (int w = 1; w <= n; w <<= 1) {
    		int cnt = 0;
    		for (int i = n - w + 1; i <= n; ++i) tp[++cnt] = i;
    		for (int i = 1; i <= n; ++i) if (sa[i] > w) tp[++cnt] = sa[i] - w;
    		base_sort (n, m);
    		memcpy (_rk, rk, sizeof (rk));
    		rk[sa[1]] = cnt = 1;
    		for (int i = 2; i <= n; ++i) {
    			rk[sa[i]] = (_rk[sa[i - 1]] == _rk[sa[i]]) && (_rk[sa[i - 1] + w] == _rk[sa[i] + w]) ? cnt : ++cnt; 
    		}
    		if (cnt == n) break;
    		m = cnt;
    	}
    }
    
    int fa[N][25];
    
    int query (int l, int r) {
    	if (l >= r) return 0; l++;
    	int mx = log2 (r - l + 1);
    	return min (fa[l][mx], fa[r - (1 << mx) + 1][mx]);
    }
    
    void get_STlist (int n) {
    	int mx = log2 (n);
    	for (int i = 1; i <= n; ++i) fa[i][0] = height[i];
    	for (int i = 1; i <= mx; ++i) {
    		for (int j = 1; j <= n - (1 << i) + 1; ++j) {
    			fa[j][i] = min (fa[j][i - 1], fa[j + (1 << (i - 1))][i - 1]);
    		}
    	}
    }
    
    int main () {
    	cin >> n;
    	for (int i = 1; i <= n; ++i) {
    		scanf ("%s", tmp);
    		int l = strlen (tmp);
    		id[i] = len + 1;
    		_len[i] = l;
    		for (int j = 0; j < l; ++j) {
    			s[++len] = tmp[j];
    		}
    		s[++len] = ++ban;
    	}
    	suffix_sort (len, ban);
    	get_height (len);
    	get_STlist (len);
    	for (int i = 1; i <= n; ++i) {
    		int l = rk[id[i]], r = rk[id[i]];
    		for (int j = 24; j >= 0; --j) {
    			int tol = l - (1 << j);
    			int tor = r + (1 << j);
    			if (tol >= 1   && query (tol, rk[id[i]]) >= _len[i]) l = tol;
    			if (tor <= len && query (rk[id[i]], tor) >= _len[i]) r = tor;
    		}
    		printf ("%d
    ", r - l + 1);
    	}
    }
    
    
  • 相关阅读:
    生活中的大数据 hadoop
    IOS设计模式学习(11)中介者
    Java 编程的动态性,第3部分: 应用反射--转载
    Java编程 的动态性,第 2部分: 引入反射--转载
    Java 编程的动态性 第1 部分: 类和类装入--转载
    斐波那契数列(fabnacci)java实现
    Chrome调试大全--转载
    jboss7 加载module过程
    UML解惑:图说UML中的六大关系--转
    jboss学习
  • 原文地址:https://www.cnblogs.com/maomao9173/p/10468748.html
Copyright © 2011-2022 走看看