HDU 4622/4641 后缀自动机简单应用

4641

4641因为是多组数据所以为了方便把板子改成了用数组的二而不是指针的写法。

计算出现k次以上的字符串一共有几个。

对于已经建立好的SAM,每加入一个字符,多出来了一次的字符串就是所有的以这个字符为结尾的后缀字符串。

所以只需要统计加入这个字符之后又多了几个就可以了,用后缀数组就可以实现。

记录一下每个状态的right集合的大小(size的求法可以想象成一个树形dp)

然后如果某种状态的right集合的大小达到了K,那么就将答案加上val[p]-val[fa[p]]

#include<bits/stdc++.h>
#include<iostream>
#include<string.h>
#define N 500005 
#define INF 0x3f3f3f3f
using namespace std;
char s[50005];
char s1[10];

int n,m,k,tot=0;
long long ans=0;
struct state{
    state *par, *go[26];
    int val,size;  //val==maxlen  fst==very left
    state(int _val) :
        par(0), val(0), size(0){
        memset(go,0,sizeof(go));
    }
};

struct suffixautomaton{
    int fa[N],go[N][26];
    int val[N], size[N];
    int root,last;
    int id;
    void extend(int w){
        int p=last;
        int np=++id;
        val[np]=val[p]+1;
        while (p!=-1&&go[p][w]==0){
            go[p][w]=np;
            p=fa[p];
        }
        if (p==-1) fa[np]=root;
        else{
            int q=go[p][w];
            if (val[p]+1==val[q]){
                fa[np]=q;
            }
            else{
                int nq=++id;
                val[nq]=val[p]+1;
                memcpy(go[nq],go[q],sizeof(go[q]));
                size[nq]=size[q];
                fa[nq]=fa[q];
                fa[q]=fa[np]=nq;
                while (p!=-1&&go[p][w]==q) {
                    go[p][w]=nq;
                    p=fa[p];
                }
            }
        }
        last=np;
        while (np&&size[np]<k){
            size[np]++;
            if (size[np]>=k) ans+=(val[np]-val[fa[np]]);
            np=fa[np];
        }
    }
    
    void init(char *s){
        memset(go,0,sizeof(go));
        memset(val,0,sizeof(val));
        memset(size,0,sizeof(size));
        memset(fa,0,sizeof(fa));
        
        root=last=id=0;
        fa[root]=-1;
        int len=strlen(s+1);
        for (int i=1;i<=len;i++){
            extend(s[i]-'a');
        }
    }
}A;

int main(){
while (scanf("%d%d%d",&n,&m,&k)!=EOF){
    ans=0; 
    scanf("%s",s+1);
    A.init(s);
    int typ;
    while (m--){
        scanf("%d",&typ);
        if (typ==1){
            scanf("%s",s1);
            A.extend(s1[0]-'a');
        }
        else{
            printf("%lld\n",ans);
        }
    }
}
return 0;
} 

4622

这个题目刚开始使用memset超时……佛了

后来又因为调试代码没有删除WA了几次……

题目是后缀数组的板子题目?

求某个子串中相互不相同的子串的个数,由于字符串的大小只有2000,所以就可以直接预处理好所有的情况然后回答。

预处理的方法就是裸的SAM加上一句话……

加上这个字符之后如果出现了一个新的字符串,这个字符串一定是长度在(val[fa[p]], val[p]]之间的。

#include<bits/stdc++.h>
#include<iostream>
#include<string.h>
#define N 100005
#define LEN 2005

using namespace std;
char s[LEN];
int n,m,k,tot=0;
int ans[LEN][LEN];

struct suffixautomaton{
	int fa[N],go[N][26];
	int val[N];
	int root,last;
	int id,	sum;
	int newnode(int v){
		id++;
		for (int i=0;i<26;i++) go[id][i]=0;
		val[id]=v;
		return id;
	}
	void extend(int w){
		int p=last;
		int np=newnode(val[p]+1);
		while (p!=-1&&go[p][w]==0){
			go[p][w]=np;
			p=fa[p];
		}
		if (p==-1) fa[np]=root;
		else{
			int q=go[p][w];
			if (val[p]+1==val[q]){
				fa[np]=q;
			}
			else{
				int nq=newnode(val[p]+1);
				memcpy(go[nq],go[q],sizeof(go[q]));
				fa[nq]=fa[q];
				fa[q]=fa[np]=nq;
				while (p!=-1&&go[p][w]==q) {
					go[p][w]=nq;
					p=fa[p];
				}
			}
		}
		last=np;
		sum+=(val[np]-val[fa[np]]);
		return;
	}
	
	void init(char *s, int st, int len){
		id=-1;
		root=last=newnode(0);
		fa[root]=-1;
		sum=0;
		for (int i=st;i<=len;i++){
			extend(s[i]-'a');
			ans[st][i]=sum; 
		}
	}
}A;

int main(){
	int T;
	scanf("%d",&T);
	while (T--){
		scanf("%s",s+1);
		int len=strlen(s+1);
		for (int i=1;i<=len;i++){
			A.init(s,i,len);
		}/*
		for (int i=1;i<=len;i++){
			for (int j=i;j<=len;j++){
				cout<<ans[i][j]<<" ";
			}
			cout<<endl;
		}*/
		int m,l,r;
		scanf("%d",&m);
		while (m--){
			scanf("%d%d",&l,&r);
			printf("%d\n",ans[l][r]);
		}
	} 
} 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值