广义回文自动机

广义回文自动机

这个想法是从 广义\(SAM\) 上得来的,本来想百度下有没有讲解 广义\(PAM\) 的,结果发现网上根本没有讲这玩意的,但想想本质发现 广义\(PAM\) 很好构造,没有 广义\(SAM\) 在线构造法那么复杂。

\(PAM\) 中是专门判了重节点,况且 \(PAM\) 中没有节点会同时包含两个状态,所以可以每次都是从头加字符串,这样不会影响 \(PAM\) 的性质。构造 广义\(PAM\) 的方法就是构造 广义\(SAM\) 的那个假掉的做法。

P5555 秩序魔咒

这题应该成为 广义\(PAM\) 的模板吧,直接建 广义\(PAM\) ,然后统计答案即可。

#include<bits/stdc++.h>
#define pc(x) putchar(x)
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){f=ch=='-'?-1:f;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
void write(int x)
{
    if(x<0){x=-x;putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+48);
}
int n,m,f[600005][2],maxlen,ans;
char s[300005];
struct G_PAM
{
    int ch[26],fa,len;
}tr[600005];
int lst,cnt=1;
void init()
{
    s[0]=-1;tr[1].len=-1;
    tr[0].fa=tr[1].fa=1;
    lst=0;
}
void insert(int k,int c,int id)
{
    int p=lst;
    while(s[k-tr[p].len-1]!=c+'a')p=tr[p].fa;
    if(!tr[p].ch[c])
    {
        int q=lst=++cnt,v=tr[p].fa;
        while(s[k-tr[v].len-1]!=c+'a')v=tr[v].fa;
        tr[q].fa=tr[v].ch[c];
        tr[tr[p].ch[c]=q].len=tr[p].len+2;
    }else lst=tr[p].ch[c];
    f[lst][id]++;
}
vector<int>e[600005];
void dfs(int x)
{
    for(int i=0;i<(int)e[x].size();++i)
    {
        int y=e[x][i];dfs(e[x][i]);
        f[x][0]+=f[y][0];f[x][1]+=f[y][1];
    }
    if(x==1||x==0||!f[x][0]||!f[x][1])return;
    if(tr[x].len>maxlen)maxlen=tr[x].len,ans=1;
    else if(tr[x].len==maxlen)ans++;
}
int main()
{
    n=read(),m=read();
    scanf("%s",s+1);init();
    for(int i=1;i<=n;++i)insert(i,s[i]-'a',0);
    scanf("%s",s+1);init();e[1].push_back(0);
    for(int i=1;i<=m;++i)insert(i,s[i]-'a',1);
    for(int i=2;i<=cnt;++i)e[tr[i].fa].push_back(i);
    dfs(1);write(maxlen),pc(' '),write(ans),pc('\n');
    return 0;
}

P5685 [JSOI2013]快乐的 JYY

应该是快乐的GYY

双倍经验,快水!(记得是大写字母!!!)

#include<bits/stdc++.h>
#define pc(x) putchar(x)
#define ll long long
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){f=ch=='-'?-1:f;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
void write(ll x)
{
	if(x<0){x=-x;putchar('-');}
	if(x>9)write(x/10);
	putchar(x%10+48);
}
int n,m,f[100005][2];ll ans;
char s[50005];
struct G_PAM
{
	int ch[26],fa,len;
}tr[100005];
int lst,cnt=1;
void init()
{
	s[0]=-1;tr[1].len=-1;
	tr[0].fa=tr[1].fa=1;
	lst=0;
}
void insert(int k,int c,int id)
{
	int p=lst;
	while(s[k-tr[p].len-1]!=c+'A')p=tr[p].fa;
	if(!tr[p].ch[c])
	{
		int q=lst=++cnt,v=tr[p].fa;
		while(s[k-tr[v].len-1]!=c+'A')v=tr[v].fa;
		tr[q].fa=tr[v].ch[c];
		tr[tr[p].ch[c]=q].len=tr[p].len+2;
	}else lst=tr[p].ch[c];
	f[lst][id]++;
}
vector<int>e[600005];
void dfs(int x)
{
	for(int i=0;i<(int)e[x].size();++i)
	{
		int y=e[x][i];dfs(e[x][i]);
		f[x][0]+=f[y][0];f[x][1]+=f[y][1];
	}
	if(x==1||x==0)return;
	ans+=1ll*f[x][0]*f[x][1];
}
int main()
{
	scanf("%s",s+1);n=strlen(s+1);init();
	for(int i=1;i<=n;++i)insert(i,s[i]-'A',0);
	scanf("%s",s+1);n=strlen(s+1);init();
	for(int i=1;i<=n;++i)insert(i,s[i]-'A',1);
	for(int i=2;i<=cnt;++i)e[tr[i].fa].push_back(i);
	e[1].push_back(0);dfs(1);write(ans),pc('\n');
	return 0;
}

不知道这个是不是真的 广义\(PAM\) ,大佬教教我/kel

posted @ 2022-03-24 11:42  violetctl39  阅读(270)  评论(0编辑  收藏  举报