Codeforces 100548G - The Problem to Slow Down You & UVAlive 7041 :回文自动机

无病呻吟:字符串算法好像还剩下后缀树。。但是他好像和后缀自动机差不多的样子(这就是你划水的原因吗?)?以及还剩下一个KMP自动机。。。但是他好像和KMP也没什么区别的样子(同上?)?以及好不容易补上了PAM这个坑。。。15年西安出了一个PAM的题,成了难题,17年哈尔滨又来了一次,这次就是中等题了。吓得我赶紧学了一波。。慌得不行


PAM:至少先学一个ACAM或者SAM,然后PAM基本上稍微看几眼就懂了了。


题意:每次给出两个串,求公共回文串个数。具体的说就是求四元组的个数,合法的四元组(s1,t1,s2,t2)定义为:串1的[ s1, t1 ]子串是一个回文串,且串2的[ s2 , t2 ]子串是一个回文串,且两段子串相同。


题解:对串1和串2构造两个PAM,然后要记住PAM有两个起点0和1,分别对应于长度为奇数和偶数的起点。然后同时往下dfs,统计答案是两个PAM的cnt乘积。串1的cnt对应于s1,t1的选择数,串2 的cnt对应于s2,t2的选择数。


Code:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+100;
struct PAM{
	int nxt[maxn][26],len[maxn],cnt[maxn],fail[maxn];
	int S[maxn];
	int last,p,now;
	int newnode(int l){
		memset(nxt[p],0,sizeof nxt[p]);
		cnt[p]=0;
		len[p]=l;
		return p++;
	}
	void init(){
		p =0;
		newnode(0);
		newnode(-1);
		last =0;
		now =0;
		S[now++] =-1;
		fail[0]=1;
	}
	inline int get_fail(int x){
		int tx =x;
		while (S[now-len[tx]-2]!=S[now-1]) tx = fail[tx];
		return tx;
	} 
	void add(int c){
		S[now++] =c;
		int cur = get_fail(last);
		if (!nxt[cur][c]){
			int tt = newnode(len[cur]+2);
			fail[tt] = nxt[get_fail(fail[cur])][c];
			nxt[cur][c] =tt;
		}
		last = nxt[cur][c];
		cnt[last]++;
	}
	void count(){
		for (int i=p-1;i>=0;i--){
			cnt[fail[i]]+=cnt[i];
		}
		cnt[0]=cnt[1]=0;
	}

}pam1,pam2;
long long dfs(int u,int v){
	long long res =0;
	for (int i=0;i<26;i++){
		int uu = pam1.nxt[u][i];
		int vv = pam2.nxt[v][i];
		if (uu&&vv){
			res +=1LL*pam1.cnt[uu]*pam2.cnt[vv];
			res+=dfs(uu,vv);
		}
	}
	return res;
}
int T;
int Cas=1; 
int len1,len2;
char s1[maxn],s2[maxn];
int main(){
	scanf("%d",&T);
	while (T--){
		pam1.init();
		pam2.init();
		scanf("%s%s",s1,s2);
		len1 = strlen(s1);
		len2 = strlen(s2);
		for (int i=0;i<len1;i++){
			pam1.add(s1[i]-'a');
		}
		for (int i=0;i<len2;i++){
			pam2.add(s2[i]-'a');
		}
		pam1.count();
		pam2.count();
		printf("Case #%d: %I64d\n",Cas++,dfs(0,0)+dfs(1,1));
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值