zoukankan      html  css  js  c++  java
  • POJ 3415 (后缀自动机)

    POJ 3415 Common Substrings

    Problem : 给两个串S、T (len <= 10^5), 询问两个串有多少个长度大于等于k的子串(位置不同也算)。
    Solution :最开始的想法是将S串和T串先后插入后缀自动机,统计出每个节点对应串的出现次数,不过这种做法被卡空间了。
    第二种想法是只将S串插入后缀自动机,建立后缀树,统计出每个节点对应串的出现次数,在统计出每个节点的所有父亲节点的出现次数之和。之后将T串在后缀自动机上进行匹配,假设当前T串在p节点匹配成功,且匹配成功长度为len,那么对答案的贡献就是p节点所有长度超过k的父亲节点,再加上当前节点中长度超过k但不超过
    tmp的串。

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    const int N = 200008;
    
    struct edge
    {
    	int v, nt;
    };
    
    struct Suffix_Automanon
    {
    	int nt[N][60], a[N], fail[N];
    	int tot, last, root;
    	int lt[N], sum;
    	int p, q, np, nq;
    	int cnt[N];
    	long long f[N];
    	edge eg[N];
    
    	int newnode(int len)
    	{
    		for (int i = 0; i < 60; ++i) nt[tot][i] = -1;
    		fail[tot] = -1; cnt[tot] = f[tot] = lt[tot] = 0; a[tot] = len;
    		return tot++;
    	}
    	void clear()
    	{
    		tot = sum = 0;
    		last = root = newnode(0);
    	}
    	void add(int u, int v)
    	{
    		eg[++sum] = (edge){v, lt[u]}; lt[u] = sum;
    	}
    	void insert(int ch)
    	{
    		p = last; np = last = newnode(a[p] + 1); cnt[np] = 1;
    		for (; ~p && nt[p][ch] == -1; p = fail[p]) nt[p][ch] = np;
    		if (p == -1) fail[np] = root;
    		else
    		{
    			q = nt[p][ch];
    			if (a[p] + 1 == a[q]) fail[np] = q;
    			else
    			{
    				nq = newnode(a[p] + 1);
    				for (int i = 0; i < 60; ++i) nt[nq][i] = nt[q][i]; 
    				fail[nq] = fail[q]; fail[q] = fail[np] = nq;
    				for (; ~p && nt[p][ch] == q; p = fail[p]) nt[p][ch] = nq;
    			} 
    		}
    	}
    	void dfs(int u)
    	{
    		for (int i = lt[u]; i; i = eg[i].nt)
    		{
    			dfs(eg[i].v);
    			cnt[u] += cnt[eg[i].v];
    		}
    	}
    	void dfs(int u, int k)
    	{
    		for (int i = lt[u]; i; i = eg[i].nt)
    		{
    			if (u != root && k <= a[u])
    			{  
    				f[eg[i].v] += f[u] + (a[u] - max(k, a[fail[u]] + 1) + 1) * cnt[u];
    			}
    			dfs(eg[i].v, k);
    		}
    	}
    	void build(int k)
    	{
    		for (int i = 1; i < tot; ++i) add(fail[i], i);
    		dfs(root);
    		dfs(root, k);
    	}
    	void solve(const string &s, int k)
    	{
    		int p = root, tmp = 0;
    		long long ans = 0;
    		for (int i = 0, len = s.length(); i < len; ++i)
    		{
    			int ch = s[i] - 'A';
    			if (~nt[p][ch]) p = nt[p][ch], tmp++;
    			else
    			{
    				for (; ~p && nt[p][ch] == -1; p = fail[p]);
    				if (p == -1) p = root, tmp = 0;
    				else
    				{
    					tmp = a[p] + 1;
    					p = nt[p][ch]; 
    				}
    			}
    			if (p != root)
    			{
    				ans += f[p];
    				if (tmp >= k && k <= a[p]) ans += (min(a[p], tmp) - max(k, a[fail[p]] + 1) + 1) * cnt[p];
    			}
    		}
    		cout << ans << endl;
    	}
    
    }sam;
    
    int main()
    {
    	int n; string s, t;
    	while (cin >> n >> s >> t)
    	{
    		sam.clear();
    		for (int i = 0, len = s.length(); i < len; ++i)
    			sam.insert(s[i] - 'A');
    		sam.build(n);
    		sam.solve(t, n);
    	}
    }
    
    
  • 相关阅读:
    chapter16 计算机体系结构基础
    ASP.NET 2.0加密Web.config 配置文件
    用IIS6.0的Kernel Caching 压缩技术提高应用程序性能
    .net中怎样执行一个字符串
    ASP.NET 页面生存周期中的关键事件
    ASP.NET获取客户端IP及MAC地址
    DOS命令关闭计算机
    1个式子检测密码强度
    徐州话六级考试
    .net2.0中新增的Substitution控件
  • 原文地址:https://www.cnblogs.com/rpSebastian/p/7222439.html
Copyright © 2011-2022 走看看