zoukankan      html  css  js  c++  java
  • Codeforces 452E Three Strings(后缀自动机)

    上学期很认真地学了一些字符串的常用工具,各种 suffix structre,但是其实对后缀自动机这个部分是理解地不太透彻的,以致于看了师兄A这题的代码后,我完全看不懂,于是乎重新看回一些学习后缀自动机的博客和代码,重新理解了一些概念,感觉自己对于后缀自动机的理解深了一些。

    先说说题意,给了三个串,问对于长度为x的串,满足(i1,i2,i3)(s1[i1..i1+k-1]==s2[i2...i2+k-1]==s3[i3+i3+k-1])有多少组,要输出全部的组数。

    师兄的代码的做法是这样的,插入三个串到后缀自动机上,中间用不同的分隔符隔开。然后对于每个状态求它的right集合的大小,求的是该字符串在三个串里的right集合的大小。具体的处理方法好像是这样的,因为有了分隔符,所以如果存在到达分隔符的后继,说明该状态是当前字符串的1个后缀,初始化为1,然后就dfs一遍,将right集合加回去。 此时对于每个状态right[0]*right[1]*right[2]即是该集合表示的字符串的三元对的大小,那么这样的三元对可以更新多少呢? 由后缀自动机的知识可以知道,对于状态s,它可以更新长度为min(s),max(s)的大小,max(s)就是下面的val,而后缀自动机的性质是min(s)=max(pre)-1。所以对于每个三元对段更,由于是先更新再询问,所以可以先打上标记,然后再回加,这样就可以求出正确的答案了。下面贴一记从师兄那里学习到的代码

    #pragma warning(disable:4996)
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <vector>
    #include <string>
    using namespace std;
    
    #define mod 1000000007
    #define ll long long
    #define maxn 610000
    
    struct State{
    	State *suf, *go[30];
    	int val;;ll right[3];
    	State() :suf(0), val(0){
    		memset(go, 0, sizeof(go));
    	}
    }*root,*last;
    
    State statePool[maxn], *cur;
    
    void init(){
    	cur = statePool;
    	root = last = cur++;
    }
    
    void extend(int w){
    	State *p = last, *np = cur++;
    	np->val = p->val + 1;
    	while (p&&!p->go[w]) p->go[w] = np, p = p->suf;
    	if (!p) np->suf = root;
    	else{
    		State *q = p->go[w];
    		if (p->val + 1 == q->val) np->suf = q;
    		else{
    			State *nq = cur++;
    			memcpy(nq->go, q->go, sizeof q->go);
    			nq->val = p->val + 1;
    			nq->suf = q->suf;
    			q->suf = nq;
    			np->suf = nq;
    			while (p&&p->go[w] == q){
    				p->go[w] = nq, p = p->suf;
    			}
    		}
    	}
    	last = np;
    }
    
    char str[maxn]; int n;
    bool vis[maxn];
    
    void dfs(State *u){
    	if (vis[u - statePool]) return;
    	if (!vis[u - statePool]){
    		vis[u - statePool] = true;
    		for (int i = 0; i < 3; i++){
    			if (u->go[26 + i]) u->right[i] = 1;
    		}
    		for (int i = 0; i < 26; i++){
    			if (u->go[i]) {
    				dfs(u->go[i]);
    				for (int k = 0; k < 3; k++){
    					u->right[k] = (u->right[k] + u->go[i]->right[k]) % mod;
    				}
    			}
    		}
    	}
    }
    
    ll num[maxn];
    
    int main()
    {
    	init(); int n = 1e8;
    	scanf("%s", str);
    	n = min(n, int(strlen(str)));
    	for (int i = 0; str[i]; i++) extend(str[i] - 'a');
    	extend(26);
    
    	scanf("%s", str);
    	n = min(n, int(strlen(str)));
    	for (int i = 0; str[i]; i++) extend(str[i] - 'a');
    	extend(27);
    
    	scanf("%s", str);
    	n = min(n, int(strlen(str)));
    	for (int i = 0; str[i]; i++) extend(str[i] - 'a');
    	extend(28);
    	dfs(root);
    
    	int tot = cur - statePool;
    
    	for (int i = 1; i < tot; i++){
    		State *u = &statePool[i];
    		ll tmp = u->right[0] % mod * u->right[1] % mod*u->right[2] % mod;
    		num[u->val] = (num[u->val] + tmp) % mod;
    		num[u->suf->val] = ((num[u->suf->val] - tmp) % mod + mod) % mod;
    	}
    
    	for (int i = tot-2; i >= 1; i--){
    		num[i] = (num[i] + num[i + 1]) % mod;
    	}
    	for (int i = 1; i <= n; i++){
    		if (i>1) printf(" ");
    		printf("%I64d", num[i]);
    	}
    	puts("");
    }
    
  • 相关阅读:
    jni 内存泄露 local reference table overflow (max=512)
    解决Android BitmapOutOfMemory 内存泄露
    c/c++ library编译
    如何查Android native crash BUG
    Shallow Size Retained Size
    android adb 命令发送 keyevent
    Android Dialog背景全透明无边框 Theme Style
    Android 销毁ImageView的bitmap
    Android EditText show softKeyBoard automatically
    jQuery 参考手册 事件
  • 原文地址:https://www.cnblogs.com/chanme/p/3876840.html
Copyright © 2011-2022 走看看