• HDU5421 Victor and String 和 APIO2014 回文串


    两道差不多的题,都是回文自动机right集合处理相关。

    Victor and String

    Victor loves to play with string. He thinks a string is charming as the string is a palindromic string.

    Victor wants to play n times. Each time he will do one of following four operations.

    1. add a char c to the beginning of the string.

    2. add a char c to the end of the string.

    3. ask the number of different charming substrings.

    4. ask the number of charming substrings, the same substrings which starts in different location has to be counted.

    At the beginning, Victor has an empty string.

    1≤n≤100000

    题解

    来自翁文涛《回文树及其应用》。

    CO int N=200000+10;
    
    namespace PAM{
    	int str[N],L,R;
    	int tot,last[2];
    	int ch[N][26],fa[N],len[N],dep[N];
    	LL ans;
    	
    	IN int new_node(int l){
    		fill(ch[tot],ch[tot]+26,0);
    		len[tot]=l,dep[tot]=0;
    		return tot++;
    	}
    	IN void init(int n){
    		memset(str,-1,sizeof str),L=n,R=n-1;
    		tot=0,new_node(0),new_node(-1),fa[0]=fa[1]=1;
    		last[0]=last[1]=1;
    		ans=0;
    	}
    	int get_fail(int x,bool d){
    		if(d)while(str[R-len[x]-1]!=str[R]) x=fa[x];
    		else while(str[L+len[x]+1]!=str[L]) x=fa[x];
    		return x;
    	}
    	void extend(int c,bool d){
    		if(d) str[++R]=c;
    		else str[--L]=c;
    		int p=get_fail(last[d],d);
    		if(!ch[p][c]){
    			int cur=new_node(len[p]+2);
    			fa[cur]=ch[get_fail(fa[p],d)][c];
    			ch[p][c]=cur;
    			dep[cur]=dep[fa[cur]]+1;
    		}
    		last[d]=ch[p][c];
    		if(len[last[d]]==R-L+1) last[d^1]=last[d];
    		ans+=dep[last[d]];
    	}
    }
    
    void real_main(int n){
    	PAM::init(n);
    	while(n--){
    		int opt=read<int>();
    		if(opt<=2){
    			char c[2];scanf("%s",c);
    			PAM::extend(c[0]-'a',opt-1);
    		}
    		else if(opt==3) printf("%d
    ",PAM::tot-2);
    		else if(opt==4) printf("%lld
    ",PAM::ans);
    	}
    }
    int main(){
    	for(int n;~scanf("%d",&n);) real_main(n);
    	return 0;
    }
    

    我发现初始化的时候必须memset。这是因为跳fail的时候可能会越界。

    然后我加了一些特判,可以去掉memset

    namespace PAM{
    	int str[N],L,R;
    	int tot,last[2];
    	int ch[N][26],fa[N],len[N],dep[N];
    	LL ans;
    	
    	IN int new_node(int l){
    		fill(ch[tot],ch[tot]+26,0);
    		len[tot]=l,dep[tot]=0;
    		return tot++;
    	}
    	IN void init(int n){
    		L=n,R=n-1;
    		tot=0,new_node(0),new_node(-1),fa[0]=fa[1]=1;
    		last[0]=last[1]=1;
    		ans=0;
    	}
    	int get_fail(int x,bool d){
    		if(d)while(assert(L<=R-len[x]-1 and R-len[x]-1<=R),str[R-len[x]-1]!=str[R]) x=fa[x];
    		else while(assert(L<=L+len[x]+1 and L+len[x]+1<=R),str[L+len[x]+1]!=str[L]) x=fa[x];
    		return x;
    	}
    	void extend(int c,bool d){
    		if(d) str[++R]=c;
    		else str[--L]=c;
    		int p=get_fail(len[last[d]]==R-L?fa[last[d]]:last[d],d); // edit
    		if(!ch[p][c]){
    			int cur=new_node(len[p]+2);
    			fa[cur]=ch[get_fail(fa[p],d)][c];
    			ch[p][c]=cur;
    			dep[cur]=dep[fa[cur]]+1;
    		}
    		last[d]=ch[p][c];
    		if(len[last[d]]==R-L+1) last[d^1]=last[d];
    		ans+=dep[last[d]];
    	}
    }
    

    APIO2014 回文串

    考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最大出现值。

    数据满足1≤字符串长度≤300000。

    题解

    co int N=300000+10;
    int last=1,tot=1;
    int ch[N][26],fa[N]={1,1},len[N]={0,-1},siz[N];
    char s[N];
    
    int get_fa(int x,int i){
    	while(s[i-len[x]-1]!=s[i]) x=fa[x];
    	return x;
    }
    void extend(int i){
    	int p=get_fa(last,i);
    	int x=ch[p][s[i]-'a'];
    	if(!x){
    		x=++tot;
    		fa[x]=ch[get_fa(fa[p],i)][s[i]-'a'];
    		len[x]=len[p]+2;
    		ch[p][s[i]-'a']=x;
    	}
    	++siz[x];
    	last=x;
    }
    int main(){
    	scanf("%s",s+1);int n=strlen(s+1);
    	for(int i=1;i<=n;++i) extend(i);
    	for(int i=tot;i>=2;--i) siz[fa[i]]+=siz[i];
    	LL ans=0;
    	for(int i=1;i<=tot;++i) ans=max(ans,(LL)siz[i]*len[i]);
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    后缀自动机做法

    http://hzwer.com/6847.html
    https://blog.csdn.net/u012288458/article/details/51785834

    每找到一个回文串,就在所有的串中查找出现了多少次
    因为暴力跳非常的慢,所以用倍增优化

    每次查询都是从末尾节点开始,倍增找到最后一个长度大于等于p的节点
    manacher算法证明了本质不同的回文串只有(O(n))个,复杂度(O(nlog n))

    第一次写直接做的manacher算法,分析了一会儿。求偶回文串的时候以左端点代替空隙,然后其他操作基本一致。

    co int N=6e5;
    // Suffix Automaton
    int last=1,tot=1;
    int ch[N][26],fa[N],len[N],siz[N],pos[N]; // pos:out->in
    void extend(int c,int po){
    	int p=last,cur=last=++tot;
    	len[cur]=len[p]+1,siz[cur]=1,pos[po]=cur;
    	for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;
    	if(!p) fa[cur]=1;
    	else{
    		int q=ch[p][c];
    		if(len[q]==len[p]+1) fa[cur]=q;
    		else{
    			int clone=++tot;
    			memcpy(ch[clone],ch[q],sizeof ch[q]);
    			fa[clone]=fa[q],len[clone]=len[p]+1;
    			fa[cur]=fa[q]=clone;
    			for(;ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
    		}
    	}
    }
    int cnt[N],id[N],anc[N][21];
    ll ans;
    void query(int l,int r){
    	int p=pos[r];
    	for(int i=20;i>=0;--i)
    		if(len[anc[p][i]]>=r-l+1) p=anc[p][i];
    	ans=max(ans,(ll)siz[p]*(r-l+1));
    }
    
    char s[N];
    int n,p[N];
    int main(){
    	scanf("%s",s+1),n=strlen(s+1);
    	for(int i=1;i<=n;++i) extend(s[i]-'a',i);
    // build
    	for(int i=1;i<=tot;++i) ++cnt[len[i]];
    	for(int i=1;i<=n;++i) cnt[i]+=cnt[i-1];
    	for(int i=1;i<=tot;++i) id[cnt[len[i]]--]=i;
    	for(int i=tot;i;--i){
    		int p=id[i];
    		siz[fa[p]]+=siz[p];
    	}
    	for(int i=1;i<=tot;++i){
    		int p=id[i];
    		anc[p][0]=fa[p];
    		for(int j=1;j<=20;++j) anc[p][j]=anc[anc[p][j-1]][j-1];
    	}
    // Manacher
    	s[0]='@',s[n+1]='#';
    	int mx=0,id=1;
    	for(int i=1;i<n;++i){ // even, represent with left vertice
    		if(mx>i) p[i]=min(mx-i,p[2*id-i]);
    		else p[i]=0;
    		while(s[i+p[i]+1]==s[i-p[i]])
    			++p[i],query(i-p[i]+1,i+p[i]);
    		if(p[i]+i>mx) mx=p[i]+i,id=i;
    	}
    	mx=0,id=1;
    	for(int i=1;i<=n;++i){ // odd
    		if(mx>i) p[i]=min(mx-i,p[2*id-i]);
    		else p[i]=1,query(i-p[i]+1,i+p[i]-1);
    		while(s[i+p[i]]==s[i-p[i]])
    			++p[i],query(i-p[i]+1,i+p[i]-1);
    		if(p[i]+i>mx) mx=p[i]+i,id=i;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    变换后台数据的表现形式(类型vue中的管道函数)
    R语言决策树和随机森林分类电信公司用户流失churn数据和参数调优、ROC曲线可视化
    R语言几何布朗运动 GBM模拟股票价格优化建立期权定价概率加权收益曲线可视化
    R语言用GARCH模型波动率建模和预测、回测风险价值 (VaR)分析股市收益率时间序列
    python用pystan贝叶斯IRT模型拟合Rasch模型分析学生考试问题数据
    【视频】关联规则模型、Apriori算法及R语言挖掘商店交易数据与交互可视化|数据分享
    RK3288 Android7.1 PMU RK808 调试
    vue.js3:用qrcodeparser解析二维码图片(vue@3.2.36)
    一文详解|增长那些事儿
    为 Serverless Devs 插上 Terraform 的翅膀,实现企业级多环境部署(上)
  • 原文地址:https://www.cnblogs.com/autoint/p/11950886.html
Copyright © 2020-2023  润新知