• 【题解】[HAOI2016]找相同字符


    [HAOI2016]找相同字符

    ( ext{Solution:})

    第一个想法,考虑对一个串建立自动机,另一个在上面匹配统计答案。

    写完发现被样例 hack 了,原因是往字符后面新加入一个后缀字母后的答案不好统计的样子。

    考虑直接换成广义 SAM ,求每一个点在两个串里面的出现次数,其对应答案就是 (siz[i][0] imes siz[i][1] imes (len[i]-len[pa[i]]))

    由于 SAM 其本身带去重功能,所以我们要维护好两个 (siz.)

    这样会发现一个节点对应的所有后缀答案都是这样的,正确性显然。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N=1e6+10;
    namespace SAM{
    	int len[N],pa[N],siz[N][2],ch[N][26],last=1,tot=1;
    	vector<int>G[N];
    	void insert(const int &c,const int &col){
    		int p=last,np=++tot;last=tot;
    		len[np]=len[p]+1;siz[np][col]=1;
    		for(;p&&!ch[p][c];p=pa[p])ch[p][c]=np;
    		if(!p)pa[np]=1;
    		else{
    			int q=ch[p][c];
    			if(len[q]==len[p]+1)pa[np]=q;
    			else{
    				int nq=++tot;
    				memcpy(ch[nq],ch[q],sizeof ch[q]);
    				len[nq]=len[p]+1;pa[nq]=pa[q];pa[q]=pa[np]=nq;
    				for(;p&&ch[p][c]==q;p=pa[p])ch[p][c]=nq;
    			}
    		}
    	}
    	void dfs(int x){
    		for(auto v:G[x]){
    			dfs(v);
    			siz[x][0]+=siz[v][0];
    			siz[x][1]+=siz[v][1];
    		}
    	}
    	void Build(){
    		for(int i=2;i<=tot;++i)G[pa[i]].push_back(i);
    		dfs(1);
    	}
    }
    char s[N];
    using namespace SAM;
    signed main(){
    	scanf("%s",s+1);
    	int n=strlen(s+1);
    	for(int i=1;i<=n;++i)insert(s[i]-'a',0);
    	scanf("%s",s+1);
    	n=strlen(s+1);
    	last=1;
    	for(int i=1;i<=n;++i)insert(s[i]-'a',1);
    	Build();
    	int Ans=0;
    	for(int i=1;i<=tot;++i){
    		if(!siz[i][0]||!siz[i][1])continue;
    		Ans+=(len[i]-len[pa[i]])*siz[i][0]*siz[i][1];
    	}
    	cout<<Ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    实验任务四
    java语言基础第二讲 课程作业02 总结
    java 计算精度处理
    构建之法阅读笔记02
    周活动总结表
    周进度条
    构建之法阅读笔记01
    四则运算软件需求规格说明书
    四则运算2
    周进度条
  • 原文地址:https://www.cnblogs.com/h-lka/p/15177257.html
Copyright © 2020-2023  润新知